All pastes #1001733 Raw Edit

Untitled

public text v1 · immutable
#1001733 ·published 2008-04-29 12:51 UTC
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, &timestamp);

    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, &timestamp);
    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;
}