rendered paste body#include <cairo.h>
#include <Ecore_Data.h>
#include <Ecore_Evas.h>
#include <Ecore.h>
#include <Evas.h>
#include <glib.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <webkit/webkit.h>
#define win_w 800
#define win_h 800
#define ECORE_FD ipc_socket[0]
#define WEBKIT_FD ipc_socket[1]
#define LOCK(name) pthread_mutex_lock(&name->lock)
#define UNLOCK(name) pthread_mutex_unlock(&name->lock)
typedef enum {
EVAS_OBJECT_WEBKIT_RESIZE,
EVAS_OBJECT_WEBKIT_EXPOSE,
EVAS_OBJECT_WEBKIT_TITLE_CHANGED,
EVAS_OBJECT_WEBKIT_CLEANUP,
EVAS_OBJECT_WEBKIT_EMBED_CREATE,
EVAS_OBJECT_WEBKIT_EMBED_DESTROY,
EVAS_OBJECT_WEBKIT_EMBED_RESIZE,
EVAS_OBJECT_WEBKIT_EMBED_OPEN_URL,
EVAS_OBJECT_WEBKIT_EMBED_MOTION_NOTIFY,
EVAS_OBJECT_WEBKIT_EMBED_BUTTON_PRESS,
EVAS_OBJECT_WEBKIT_EMBED_BUTTON_RELEASE,
EVAS_OBJECT_WEBKIT_EMBED_KEY_PRESS,
EVAS_OBJECT_WEBKIT_EMBED_KEY_RELEASE,
EVAS_OBJECT_WEBKIT_EMBED_ENTER_NOTIFY,
EVAS_OBJECT_WEBKIT_EMBED_LEAVE_NOTIFY
} Evas_WebKit_EventType;
typedef struct {
Evas_WebKit_EventType type;
// XXX use union!
int w, h; // window size
int x, y; // mouse position
char *title;
} Evas_WebKit_Event;
typedef struct {
Evas_WebKit_Event event;
time_t timestamp;
char *id;
} Evas_WebKit_Message;
typedef struct _Evas_WebKit_Private {
char *id;
char *buffer;
int buffer_size;
int h, w;
pthread_mutex_t lock;
time_t timestamp;
} Evas_WebKit_Private;
Ecore_Evas *ee = NULL;
Evas *evas = NULL;
cairo_surface_t *surface = NULL;
cairo_t *source_context = NULL;
static int ipc_socket[2];
static Ecore_Hash *obj_mapping;
static Ecore_Hash *private_data_mapping;
static Ecore_Hash *webview_mapping;
static GtkWidget* web_test;
static void
webkit_web_view_resize(WebKitWebView *web_view, Evas_WebKit_Private *data,
int w, int h)
{
GtkAllocation alloc = {0, 0, w, h};
cairo_surface_destroy(surface);
gtk_widget_size_allocate(GTK_WIDGET(web_view), &alloc);
surface = cairo_surface_create_similar(cairo_get_target(source_context),
CAIRO_CONTENT_COLOR_ALPHA, w, h);
data->w = w;
data->h = h;
}
static void
webkit_web_view_clear(WebKitWebView *web_view, Evas_WebKit_Private *data)
{
int w, h;
w = cairo_image_surface_get_width(surface);
h = cairo_image_surface_get_height(surface);
cairo_surface_destroy(surface);
surface = cairo_surface_create_similar(cairo_get_target(source_context),
CAIRO_CONTENT_COLOR_ALPHA, w, h);
data->w = w;
data->h = h;
}
static void
webkit_web_view_paint(WebKitWebView *web_view, Evas_WebKit_Private *data,
int x, int y, int w, int h)
{
WebKitWebFrame *web_frame;
cairo_t *cr;
cr = cairo_create(surface);
cairo_rectangle (cr, x, y, w, h);
web_frame = webkit_web_view_get_main_frame(web_view);
webkit_web_frame_show(web_frame, cr);
cairo_destroy(cr);
data->buffer = (char *) cairo_image_surface_get_data(surface);
}
static void
read_message(int ipc_fd, char **id, Evas_WebKit_Event *event, time_t *timestamp)
{
Evas_WebKit_Message msg;
read(ipc_fd, &msg, sizeof(Evas_WebKit_Message));
*event = msg.event;
*id = msg.id;
*timestamp = msg.timestamp;
}
static void
send_message(int ipc_fd, char *id, Evas_WebKit_Event event, time_t timestamp)
{
Evas_WebKit_Message msg;
msg.event = event;
msg.id = id;
msg.timestamp = timestamp;
write(ipc_fd, &msg, sizeof(Evas_WebKit_Message));
}
static void
title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame,
const gchar* title, gpointer user_data)
{
Evas_WebKit_Private *data;
Evas_WebKit_Event event;
data = (Evas_WebKit_Private *) user_data;
event.type = EVAS_OBJECT_WEBKIT_TITLE_CHANGED;
event.title = strdup(title);
send_message(WEBKIT_FD, data->id, event, data->timestamp);
}
static void
progress_change_cb (WebKitWebView *web_view, gint progress, gpointer user_data)
{
Evas_WebKit_Private *data;
Evas_WebKit_Event event;
data = (Evas_WebKit_Private *) user_data;
webkit_web_view_clear(web_view, data);
webkit_web_view_paint(web_view, data, 0, 0, data->w, data->h);
printf("Load progress %d\n", progress);
event.type = EVAS_OBJECT_WEBKIT_EXPOSE;
send_message(WEBKIT_FD, data->id, event, data->timestamp);
}
static int
_evas_webkit_dispatch(void *user_data, Ecore_Fd_Handler *fd_handler)
{
Evas_Object *obj;
Evas_WebKit_Private *data;
Evas_WebKit_Event event;
char *id;
time_t timestamp;
(void) user_data;
(void) fd_handler;
read_message(ECORE_FD, &id, &event, ×tamp);
data = ecore_hash_get(private_data_mapping, id);
printf("HERE");
// optimization
//if (data->timestamp != timestamp)
// return 1;
obj = ecore_hash_get(obj_mapping, (void *) id);
LOCK(data);
switch (event.type) {
case EVAS_OBJECT_WEBKIT_RESIZE:
evas_object_image_pixels_dirty_set(obj, 1);
evas_object_image_fill_set(obj, 0, 0, data->w, data->h);
evas_object_image_size_set(obj, data->w, data->h);
evas_object_image_data_copy_set(obj, data->buffer);
evas_object_image_pixels_dirty_set(obj, 0);
break;
case EVAS_OBJECT_WEBKIT_EXPOSE:
evas_object_image_pixels_dirty_set(obj, 1);
evas_object_image_fill_set(obj, 0, 0, data->w, data->h);
evas_object_image_size_set(obj, data->w, data->h);
evas_object_image_data_copy_set(obj, data->buffer);
evas_object_image_pixels_dirty_set(obj, 0);
break;
case EVAS_OBJECT_WEBKIT_TITLE_CHANGED:
ecore_evas_title_set(ee, event.title);
free(event.title);
break;
case EVAS_OBJECT_WEBKIT_CLEANUP:
printf("CLEANUP");
ecore_hash_remove(private_data_mapping, id);
ecore_hash_remove(obj_mapping, id);
//UNLOCK(data);
//free(data);
//return 1;
default:
break;
}
UNLOCK(data);
return 1;
}
gboolean
webkit_dispatch(GIOChannel *source, GIOCondition condition, gpointer user_data)
{
WebKitWebView *web_view;
Evas_WebKit_Private *data;
Evas_WebKit_Event event;
char *id;
time_t timestamp;
read_message(WEBKIT_FD, &id, &event, ×tamp);
data = ecore_hash_get(private_data_mapping, (void *) id);
LOCK(data);
switch (event.type) {
case EVAS_OBJECT_WEBKIT_EMBED_CREATE:
printf("Create GtkWebView with id=%s\n", id);
web_test = webkit_web_canvas_new(0, 0);
web_view = webkit_web_canvas_get_web_view(WEBKIT_WEB_CANVAS(web_test));
g_signal_connect (G_OBJECT (web_view), "load-progress-changed",
G_CALLBACK (progress_change_cb), data);
g_signal_connect (G_OBJECT (web_view), "title-changed",
G_CALLBACK (title_change_cb), data);
webkit_web_view_open(web_view, "http://www.enlightenment.org");
ecore_hash_set(webview_mapping, id, web_view);
break;
case EVAS_OBJECT_WEBKIT_EMBED_DESTROY:
printf("Remove GtkWebView with id=%s\n", id);
ecore_hash_remove(webview_mapping, id);
event.type = EVAS_OBJECT_WEBKIT_CLEANUP;
send_message(WEBKIT_FD, id, event, data->timestamp);
break;
case EVAS_OBJECT_WEBKIT_EMBED_RESIZE:
printf("Resize GtkWebView (%d, %d) with id=%s - ", event.w, event.h, id);
web_view = ecore_hash_get(webview_mapping, (void *) id);
webkit_web_view_resize(web_view, data, event.w, event.h);
webkit_web_view_paint(web_view, data,
0, 0, event.w, event.h);
event.type = EVAS_OBJECT_WEBKIT_RESIZE;
send_message(WEBKIT_FD, id, event, data->timestamp);
break;
case EVAS_OBJECT_WEBKIT_EMBED_MOTION_NOTIFY:
web_view = ecore_hash_get(webview_mapping, (void *) id);
webkit_web_view_clear(web_view, data);
webkit_web_view_paint(web_view, data,
0, 0, data->w, data->h);
event.type = EVAS_OBJECT_WEBKIT_EXPOSE;
send_message(WEBKIT_FD, id, event, data->timestamp);
break;
case EVAS_OBJECT_WEBKIT_EMBED_BUTTON_PRESS:
break;
case EVAS_OBJECT_WEBKIT_EMBED_BUTTON_RELEASE:
break;
case EVAS_OBJECT_WEBKIT_EMBED_KEY_PRESS:
break;
case EVAS_OBJECT_WEBKIT_EMBED_KEY_RELEASE:
break;
case EVAS_OBJECT_WEBKIT_EMBED_ENTER_NOTIFY:
break;
case EVAS_OBJECT_WEBKIT_EMBED_LEAVE_NOTIFY:
break;
default:
break;
}
UNLOCK(data);
return TRUE;
}
void *
webkit_thread(void *data)
{
int watch;
GMainLoop *webkit_loop;
GIOChannel *io_channel;
webkit_loop = g_main_loop_new(NULL, TRUE);
gtk_init(NULL, NULL);
webview_mapping = ecore_hash_new(ecore_direct_hash, ecore_direct_compare);
io_channel = g_io_channel_unix_new(WEBKIT_FD);
watch = g_io_add_watch(io_channel, G_IO_IN, webkit_dispatch, NULL);
g_main_loop_run(webkit_loop);
pthread_exit(NULL);
ecore_hash_destroy(webview_mapping);
}
static pthread_t thread;
int
evas_webkit_init()
{
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, ipc_socket) < 0)
return 1;
obj_mapping = ecore_hash_new(ecore_direct_hash, ecore_direct_compare);
private_data_mapping = ecore_hash_new(ecore_direct_hash, ecore_direct_compare);
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 100, 100);
source_context = cairo_create(surface);
pthread_create(&thread, NULL, webkit_thread, NULL);
return 0;
}
void
evas_webkit_shutdown()
{
pthread_join(thread, NULL);
ecore_hash_destroy(private_data_mapping);
ecore_hash_destroy(obj_mapping);
}
void
on_evas_object_webkit_resize(void *user_data, Evas *e,
Evas_Object *obj, void *event_info)
{
Evas_WebKit_Private *data;
Evas_WebKit_Event event;
int x, y, w, h;
char *id;
id = evas_object_data_get(obj, "object-id");
data = ecore_hash_get(private_data_mapping, id);
evas_object_geometry_get(obj, &x, &y, &w, &h);
evas_object_image_pixels_dirty_set(obj, 1);
LOCK(data);
data->timestamp = time(NULL);
event.type = EVAS_OBJECT_WEBKIT_EMBED_RESIZE;
event.w = w;
event.h = h;
//printf("signal resize (%d, %d, %d, %d) - ", y, x, w, h);
send_message(ECORE_FD, id, event, data->timestamp);
UNLOCK(data);
}
void
on_evas_object_webkit_mouse_move(void *user_data, Evas *e,
Evas_Object *obj, void *event_info)
{
Evas_WebKit_Private *data;
Evas_WebKit_Event event;
char *id;
id = evas_object_data_get(obj, "object-id");
data = ecore_hash_get(private_data_mapping, id);
LOCK(data);
data->timestamp = time(NULL);
event.type = EVAS_OBJECT_WEBKIT_EMBED_MOTION_NOTIFY;
// XXX get from event_info
event.x = 0;
event.y = 0;
printf("signal mouse (%d, %d) \n", data->w, data->h);
send_message(ECORE_FD, id, event, data->timestamp);
UNLOCK(data);
}
void
on_evas_object_webkit_mouse_down(void *data, Evas *e,
Evas_Object *obj, void *event_info)
{
char *id;
id = evas_object_data_get(obj, "object-id");
//send_message(ECORE_FD, id, EVAS_OBJECT_WEBKIT_EMBED_BUTTON_PRESS);
}
void
on_evas_object_webkit_mouse_up(void *data, Evas *e,
Evas_Object *obj, void *event_info)
{
char *id;
id = evas_object_data_get(obj, "object-id");
//send_message(ECORE_FD, id, EVAS_OBJECT_WEBKIT_EMBED_BUTTON_RELEASE);
}
void
on_evas_object_webkit_key_down(void *data, Evas *e,
Evas_Object *obj, void *event_info)
{ char *id;
id = evas_object_data_get(obj, "object-id");
//send_message(ECORE_FD, id, EVAS_OBJECT_WEBKIT_EMBED_KEY_PRESS);
}
void
on_evas_object_webkit_key_up(void *data, Evas *e,
Evas_Object *obj, void *event_info)
{
char *id;
id = evas_object_data_get(obj, "object-id");
//send_message(ECORE_FD, id, EVAS_OBJECT_WEBKIT_EMBED_KEY_RELEASE);
}
void
on_evas_object_webkit_mouse_in(void *data, Evas *e,
Evas_Object *obj, void *event_info)
{
char *id;
id = evas_object_data_get(obj, "object-id");
//send_message(ECORE_FD, id, EVAS_OBJECT_WEBKIT_EMBED_ENTER_NOTIFY);
}
void
on_evas_object_webkit_mouse_out(void *data, Evas *e,
Evas_Object *obj, void *event_info)
{
char *id;
id = evas_object_data_get(obj, "object-id");
//send_message(ECORE_FD, id, EVAS_OBJECT_WEBKIT_EMBED_LEAVE_NOTIFY);
}
void
on_evas_object_webkit_del(void *data, Evas *e,
Evas_Object *obj, void *event_info)
{
Evas_WebKit_Event event;
char *id;
evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL,
on_evas_object_webkit_del);
evas_object_event_callback_del(obj, EVAS_CALLBACK_RESIZE,
on_evas_object_webkit_resize);
evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_MOVE,
on_evas_object_webkit_mouse_move);
evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_DOWN,
on_evas_object_webkit_mouse_down);
evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP,
on_evas_object_webkit_mouse_up);
evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_DOWN,
on_evas_object_webkit_key_down);
evas_object_event_callback_del(obj, EVAS_CALLBACK_KEY_UP,
on_evas_object_webkit_key_up);
evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_IN,
on_evas_object_webkit_mouse_in);
evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_OUT,
on_evas_object_webkit_mouse_out);
id = evas_object_data_get(obj, "object-id");
event.type = EVAS_OBJECT_WEBKIT_EMBED_DESTROY;
send_message(ECORE_FD, id, event, time(NULL));
}
Evas_Object *
evas_object_webkit_add(Ecore_Evas *ee)
{
Evas_WebKit_Event event;
Evas_Object *obj = NULL;
char *id;
char tmp[100];
obj = evas_object_image_add(ecore_evas_get(ee));
evas_object_image_colorspace_set(obj, EVAS_COLORSPACE_ARGB8888);
Evas_WebKit_Private *private_data = malloc(sizeof(Evas_WebKit_Private));
memset(private_data, 0, sizeof(Evas_WebKit_Private));
pthread_mutex_init(&private_data->lock, NULL);
sprintf(tmp, "%d", ecore_hash_count(obj_mapping));
id = strdup(tmp);
ecore_hash_set(obj_mapping, id, obj);
ecore_hash_set(private_data_mapping, id, private_data);
private_data->id = id;
evas_object_data_set(obj, "object-id", id);
event.type = EVAS_OBJECT_WEBKIT_EMBED_CREATE;
send_message(ECORE_FD, id, event, time(NULL));
evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL,
on_evas_object_webkit_del, NULL);
evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE,
on_evas_object_webkit_resize, NULL);
evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE,
on_evas_object_webkit_mouse_move, NULL);
evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
on_evas_object_webkit_mouse_down, NULL);
evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
on_evas_object_webkit_mouse_up, NULL);
evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN,
on_evas_object_webkit_key_down, NULL);
evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_UP,
on_evas_object_webkit_key_up, NULL);
evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_IN,
on_evas_object_webkit_mouse_in, NULL);
evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_OUT,
on_evas_object_webkit_mouse_out, NULL);
ecore_main_fd_handler_add(ECORE_FD, ECORE_FD_READ,
_evas_webkit_dispatch, NULL,
NULL, NULL);
return obj;
}
/* -------- APPLICATION -------- */
static void
on_ecore_evas_resize(Ecore_Evas *ee)
{
Evas_Object *obj = NULL;
int x, y, w, h;
ecore_evas_geometry_get(ee, &x, &y, &w, &h);
obj = evas_object_name_find(ecore_evas_get(ee), "webkit");
if (obj) {
evas_object_move(obj, 0, 0);
evas_object_resize(obj, w, h);
}
}
static void
on_ecore_evas_delete_request(Ecore_Evas *ee)
{
(void) ee;
ecore_main_loop_quit();
}
static int
on_ecore_signal_exit(void *data, int type, void *event)
{
(void) data;
(void) type;
(void) event;
ecore_main_loop_quit();
return 0;
}
int
main(int argc, const char **argv)
{
Evas_Object *webkit = NULL;
int ret = EXIT_FAILURE;
if (!ecore_init()) {
fprintf(stderr, "Unable to init Ecore, bailing out.\n");
goto out;
}
ecore_app_args_set(argc, argv);
ecore_evas_init();
if (evas_webkit_init()) {
fprintf(stderr, "Unable to open IPC channel.\n");
goto out;
}
ee = ecore_evas_software_x11_new(NULL, 0, 0, 0, win_w, win_h);
if (!ee)
goto out_ecore;
evas = ecore_evas_get(ee);
ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, on_ecore_signal_exit, ee);
ecore_evas_title_set(ee, "WebKit on Evas Test");
ecore_evas_name_class_set(ee, "EvasWebKitTest", "EvasWebKitTest");
ecore_evas_callback_delete_request_set(ee, on_ecore_evas_delete_request);
ecore_evas_callback_resize_set(ee, on_ecore_evas_resize);
webkit = evas_object_webkit_add(ee);
evas_object_name_set(webkit, "webkit");
evas_object_show(webkit);
on_ecore_evas_resize(ee);
ecore_evas_show(ee);
ecore_main_loop_begin();
evas_object_del(webkit);
evas_webkit_shutdown();
ecore_evas_shutdown();
ret = EXIT_SUCCESS;
out_ecore:
ecore_shutdown();
out:
return ret;
}