Logo Search packages:      
Sourcecode: netbook-launcher-efl version File versions  Download package

gadget_item.c

/* -*- Mode: C; indent-tabs-mode: nil; tab-width: 2 -*-
 *
 * Copyright (C) 2009 Canonical Ltd.
 * Authors:
 *  Gustavo Sverzut Barbieri <gustavo.barbieri@canonical.com>
 *
 * This file is part of Netbook Launcher EFL.
 *
 * Netbook Launcher EFL is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * Netbook Launcher EFL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Netbook Launcher EFL.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <gtk/gtk.h>
#include <Elementary.h>
#include <cairo/cairo.h>
#include <libgadget/libgadget.h>
#include "netbook-launcher.h"

#define SMART_DATA_GET(o, ptr)  \
    struct _data *ptr = evas_object_smart_data_get(o)

#define SMART_DATA_GET_OR_RETURN(o, ptr) \
    SMART_DATA_GET(o, ptr);              \
    if (!ptr) {                          \
        ERR("no private data for object %p (%s)\n", \
            o, evas_object_type_get(o));            \
        return;                          \
    }

#define SMART_DATA_GET_OR_RETURN_NULL(o, ptr)   \
    SMART_DATA_GET(o, ptr);                     \
    if (!ptr) {                                 \
        ERR("no private data for object %p (%s)\n", \
            o, evas_object_type_get(o));            \
    return NULL;                                \
    }

struct _data {
    Evas_Object_Smart_Clipped_Data base;
    Evas_Object *cairo;
    GadgetProxy *proxy;
    GadgetManager *manager;
    const char *uid;
    const char *path;
};

/* Keep just one instance of them */
static Evas_Smart_Class _parent_sc = EVAS_SMART_CLASS_INIT_NULL;
static unsigned int gtk_init_count = 0;
static unsigned int g_type_init_count = 0;
static GadgetManager *manager = NULL;

static void *
_setup_private_data(Evas_Object *o, unsigned int size)
{
    struct _data *priv;

    priv = evas_object_smart_data_get(o);
    if (!priv) {
        priv = malloc(size);
        if (!priv) {
            ERR("could not malloc private data.\n");
            return NULL;
        }
        evas_object_smart_data_set(o, priv);
    }

    return priv;
}

static void
_smart_add(Evas_Object *o)
{
    struct _data *priv;

    priv = _setup_private_data(o, sizeof(struct _data));
    if (!priv) {
        ERR("Could not add new smart object\n");
        return;
    }

    priv->cairo = NULL;
    priv->proxy = NULL;
    priv->manager = NULL;
    priv->path = NULL;
    priv->uid = NULL;

    _parent_sc.add(o);
}

static void
_smart_del(Evas_Object *o)
{
    SMART_DATA_GET(o, priv);

    if (priv->cairo)
        evas_object_del(priv->cairo);
    if (priv->manager)
        g_object_unref(priv->manager);
    if (priv->proxy)
        g_object_unref(priv->proxy);
    if (priv->path)
        eina_stringshare_del(priv->path);
    if (priv->uid)
        eina_stringshare_del(priv->uid);

    priv->cairo = NULL;
    priv->manager = NULL;
    priv->proxy = NULL;

    _parent_sc.del(o);
}

static void
_smart_calculate(Evas_Object *o)
{
    Evas_Coord x, y, w, h;
    SMART_DATA_GET_OR_RETURN(o, priv);
    evas_object_geometry_get(o, &x, &y, &w, &h);
    evas_object_image_data_update_add(priv->cairo, 0, 0, w, h);
}

static void
_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
{
    SMART_DATA_GET_OR_RETURN(o, priv);

    /* Resize smart object */
    evas_object_image_size_set(priv->cairo, w, h);
    cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
    evas_image_cairo_surface_set(priv->cairo, s);

    evas_object_smart_changed(o);

    return;
}

static Evas_Smart_Class *
_smart_class_new(void)
{
    static Evas_Smart_Class sc =
        EVAS_SMART_CLASS_INIT_NAME_VERSION("EFLGADGET");

    if (!_parent_sc.name) {
        evas_object_smart_clipped_smart_set(&sc);
        _parent_sc = sc;
        sc.add = _smart_add;
        sc.del = _smart_del;
        sc.resize = _smart_resize;
        sc.calculate = _smart_calculate;
    }

    return &sc;
}

static guint
_evas_to_gdk_state(int buttons, Evas_Modifier *modifiers)
{
  guint rv = 0;
  rv |= ((buttons & 0x1f) * GDK_BUTTON1_MASK); // shift buttons left
  if (evas_key_modifier_is_set(modifiers, "Shift"))
    rv |= GDK_SHIFT_MASK;
  if (evas_key_modifier_is_set(modifiers, "Control"))
    rv |= GDK_CONTROL_MASK;
  if (evas_key_modifier_is_set(modifiers, "Alt"))
    rv |= GDK_MOD1_MASK;
  return rv;
}

static void
_key_down(void *data, Evas *evas, Evas_Object *o, void *ev)
{
    Evas_Event_Key_Down *kd = (Evas_Event_Key_Down *)ev;
    GdkEventKey e;
    Evas_Object *gadget = data;
    SMART_DATA_GET_OR_RETURN(gadget, priv);

    e.type = GDK_KEY_PRESS;
    e.time = kd->timestamp;
    e.keyval = 0;
    e.hardware_keycode = 0;
    e.state = _evas_to_gdk_state(0, kd->modifiers);

    gadget_proxy_event(priv->proxy, (GdkEvent *)&e);
}

static void
_key_up(void *data, Evas *evas, Evas_Object *o, void *ev)
{
    Evas_Event_Key_Up *ku = (Evas_Event_Key_Up *)ev;
    GdkEventKey e;
    Evas_Object *gadget = data;
    SMART_DATA_GET_OR_RETURN(gadget, priv);

    e.window = NULL;
    e.type = GDK_KEY_RELEASE;
    e.time = ku->timestamp;
    e.keyval = 0;
    e.hardware_keycode = 0;
    e.state = _evas_to_gdk_state(0, ku->modifiers);

    gadget_proxy_event(priv->proxy, (GdkEvent *)&e);
}

static void
_mouse_down(void *data, Evas *evas, Evas_Object *o, void *ev)
{
    Evas_Coord x, y;
    Evas_Event_Mouse_Down *md = (Evas_Event_Mouse_Down *)ev;
    GdkEventButton e;
    Evas_Object *gadget = data;
    SMART_DATA_GET_OR_RETURN(data, priv);

    evas_object_geometry_get(o, &x, &y, NULL, NULL);

    // the x coordinate of the pointer relative to the window.
    e.x = md->canvas.x - x;
    e.y = md->canvas.y - y;
    e.time = md->timestamp;
    // FIXME: Treat here double and triple-click too
    e.type = GDK_BUTTON_PRESS;
    e.device = NULL;
    e.button = md->button;
    e.state = _evas_to_gdk_state(md->button, md->modifiers);
    // the x coordinate of the pointer relative to the root of the screen.
    e.x_root = md->output.x;
    e.y_root = md->output.x;

    gadget_proxy_event(priv->proxy, (GdkEvent *)&e);
}


static void
_mouse_up(void *data, Evas *evas, Evas_Object *o, void *ev)
{
    Evas_Coord x, y;
    Evas_Event_Mouse_Up *mu = (Evas_Event_Mouse_Up *)ev;
    GdkEventButton e;
    Evas_Object *gadget = data;
    SMART_DATA_GET_OR_RETURN(gadget, priv);

    evas_object_geometry_get(o, &x, &y, NULL, NULL);

    e.x = mu->canvas.x - x;
    e.y = mu->canvas.y - y;
    e.time = mu->timestamp;
    e.type = GDK_BUTTON_RELEASE;
    e.device = NULL;
    e.button = mu->button;
    e.x_root = mu->output.x;
    e.y_root = mu->output.x;
    e.state = _evas_to_gdk_state(mu->button, mu->modifiers);

    gadget_proxy_event(priv->proxy, (GdkEvent *)&e);
}

static void
_mouse_move(void *data, Evas *evas, Evas_Object *o, void *ev)
{
    Evas_Coord x, y;
    Evas_Event_Mouse_Move *mm = (Evas_Event_Mouse_Move *)ev;
    GdkEventMotion e;
    Evas_Object *gadget = data;
    SMART_DATA_GET_OR_RETURN(gadget, priv);

    evas_object_geometry_get(o, &x, &y, NULL, NULL);

    e.type = GDK_MOTION_NOTIFY;
    e.time = mm->timestamp;
    e.x = mm->cur.canvas.x - x;
    e.y = mm->cur.canvas.y - y;
    e.x_root = mm->cur.output.x;
    e.y_root = mm->cur.output.x;
    e.state = _evas_to_gdk_state(mm->buttons, mm->modifiers);

    gadget_proxy_event(priv->proxy, (GdkEvent *)&e);
}

static void
_mouse_in(void *data, Evas *evas, Evas_Object *o, void *ev)
{
    Evas_Coord x, y;
    Evas_Event_Mouse_In *mi = (Evas_Event_Mouse_In *)ev;
    GdkEventCrossing e;
    Evas_Object *gadget = data;
    SMART_DATA_GET_OR_RETURN(gadget, priv);

    evas_object_geometry_get(o, &x, &y, NULL, NULL);

    e.type = GDK_ENTER_NOTIFY;
    e.time = mi->timestamp;
    e.x = mi->canvas.x - x;
    e.y = mi->canvas.y - y;
    e.state = _evas_to_gdk_state(mi->buttons, mi->modifiers);
    e.x_root = mi->output.x;
    e.y_root = mi->output.x;
    e.mode = GDK_CROSSING_NORMAL;

    gadget_proxy_event(priv->proxy, (GdkEvent *)&e);
}

static void
_mouse_out(void *data, Evas *evas, Evas_Object *o, void *ev)
{
    Evas_Coord x, y;
    Evas_Event_Mouse_Out *mo = (Evas_Event_Mouse_Out *)ev;
    GdkEventCrossing e;
    Evas_Object *gadget = data;
    SMART_DATA_GET_OR_RETURN(gadget, priv);

    evas_object_geometry_get(o, &x, &y, NULL, NULL);

    e.type = GDK_LEAVE_NOTIFY;
    e.time = mo->timestamp;
    e.x = mo->canvas.x - x;
    e.y = mo->canvas.y - y;
    e.state = _evas_to_gdk_state(mo->buttons, mo->modifiers);
    e.x_root = mo->output.x;
    e.y_root = mo->output.x;
    e.mode = GDK_CROSSING_NORMAL;

    gadget_proxy_event(priv->proxy, (GdkEvent *)&e);
}

static void
_mouse_wheel(void *data, Evas *evas, Evas_Object *o, void *ev)
{
    Evas_Coord x, y;
    Evas_Event_Mouse_Wheel *mw = (Evas_Event_Mouse_Wheel *)ev;
    GdkEventScroll e;
    Evas_Object *gadget = data;
    SMART_DATA_GET_OR_RETURN(gadget, priv);

    evas_object_geometry_get(o, &x, &y, NULL, NULL);

    e.type = GDK_SCROLL;
    e.time = mw->timestamp;
    e.x = mw->canvas.x - x;
    e.y = mw->canvas.y - y;
    e.x_root = mw->output.x;
    e.y_root = mw->output.x;
    e.state = _evas_to_gdk_state(0, mw->modifiers);
    e.direction =
        mw->direction == 0 && mw->z < 0 ? GDK_SCROLL_UP :
        mw->direction == 0 && mw->z > 0 ? GDK_SCROLL_DOWN :
        mw->direction != 0 && mw->z < 0 ? GDK_SCROLL_LEFT :
        GDK_SCROLL_RIGHT;

    gadget_proxy_event(priv->proxy, (GdkEvent *)&e);
}

static void
_on_queue_redraw(GadgetProxy *proxy, Evas_Object *gadget)
{
    cairo_t *cr;
    cairo_surface_t *cs;
    SMART_DATA_GET_OR_RETURN(gadget, priv);

    if (!priv->cairo || !priv->proxy)
        return;

    cs = evas_image_cairo_surface_get(priv->cairo);
    if (!cs) {
        ERR("Could not get cairo surface\n");
        return;
    }
    cr = cairo_create(cs);
    if (!cr) {
        ERR("Could not get cairo from surface\n");
        return;
    }

    cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
    cairo_paint(cr);
    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
    gadget_cairo_draw(GADGET_CAIRO(priv->proxy), cr);
    cairo_destroy(cr);

    evas_object_smart_changed(gadget);
}

static void
_on_queue_resize(GadgetProxy *proxy, Evas_Object *gadget)
{
    int w, h;
    SMART_DATA_GET_OR_RETURN(gadget, priv);

    w = gadget_proxy_get_width(proxy);
    h = gadget_proxy_get_height(proxy);

    evas_object_resize(gadget, w, h);
}

static void
_on_remove_me(GadgetProxy *proxy, Evas_Object *gadget)
{
    SMART_DATA_GET(gadget, priv);

    if (priv->proxy)
        gadget_proxy_removed(priv->proxy);

    evas_object_smart_callback_call(gadget, "remove-me", NULL);
}

static void
_on_begin_resize(GadgetProxy *proxy, GadgetResizePoint point, Evas_Object *gadget)
{
  INF("begin resize\n");
}

static void
_on_begin_drag_move(Evas_Object *gadget)
{
  INF("begin drag move\n");
}

static void
_on_open_url(GadgetProxy *proxy, const gchar *url, Evas_Object *gadget)
{
    INF("open url %s", url);
}

static void
_signals_connect(GadgetProxy *proxy, Evas_Object *gadget)
{
    if (!proxy || !gadget)
        return;

    g_signal_connect(proxy, "queue-redraw",
            G_CALLBACK(_on_queue_redraw), gadget);
    g_signal_connect(proxy, "queue-resize",
            G_CALLBACK(_on_queue_resize), gadget);
    g_signal_connect(proxy, "open-url",
            G_CALLBACK(_on_open_url), gadget);
    g_signal_connect(proxy, "begin-resize",
            G_CALLBACK(_on_begin_resize), gadget);
    g_signal_connect(proxy, "begin-drag-move",
            G_CALLBACK(_on_begin_drag_move), gadget);
    g_signal_connect(proxy, "remove-me",
            G_CALLBACK(_on_remove_me), gadget);
}

static void
_callbacks_add(Evas_Object *cairo, Evas_Object *gadget)
{
    if (!cairo || !gadget)
        return;

    evas_object_event_callback_add(cairo, EVAS_CALLBACK_MOUSE_DOWN,
            _mouse_down, gadget);
    evas_object_event_callback_add(cairo, EVAS_CALLBACK_MOUSE_UP,
            _mouse_up, gadget);
    evas_object_event_callback_add(cairo, EVAS_CALLBACK_MOUSE_MOVE,
            _mouse_move, gadget);
    evas_object_event_callback_add(cairo, EVAS_CALLBACK_MOUSE_IN,
            _mouse_in, gadget);
    evas_object_event_callback_add(cairo, EVAS_CALLBACK_MOUSE_OUT,
            _mouse_out, gadget);
    evas_object_event_callback_add(cairo, EVAS_CALLBACK_MOUSE_WHEEL,
            _mouse_wheel, gadget);
}

static Evas_Object *
_create_gadget(Evas *evas, Evas_Smart *smart, const char *path, const char *uid)
{
    Evas_Object *gadget = evas_object_smart_add(evas, smart);
    if (!gadget) {
        ERR("Could not add smart gadget\n");
        return NULL;
    }

    SMART_DATA_GET(gadget, priv);
    if (!priv)
        goto on_error;

    priv->manager = gadget_manager_get_default();
    if (!priv->manager) {
        ERR("Could not get a gadget manager\n");
        goto on_error;
    }
    gadget_manager_load_sources(priv->manager);

    if (!gadget_manager_can_handle_path(priv->manager, path)) {
        ERR("Cannot handle path: %s\n", path);
        goto on_error;
    }

    priv->proxy = gadget_manager_load_gadget(priv->manager, path, uid);
    if (!priv->proxy) {
        ERR("Unable to load gadget %s path %s\n", uid, path);
        goto on_error;
    }

    priv->cairo = evas_image_cairo_new(evas, 1, 1, 1);
    if (!priv->cairo)
        goto on_error;

    evas_object_smart_member_add(priv->cairo, gadget);
    evas_object_show(priv->cairo);

    priv->uid = eina_stringshare_add(uid);
    priv->path = eina_stringshare_add(path);

    _signals_connect(priv->proxy, gadget);
    _callbacks_add(priv->cairo, gadget);

    evas_object_image_filled_set(priv->cairo, 1);
    evas_image_cairo_fill_auto_set(priv->cairo, 1);
    _on_queue_resize(priv->proxy, gadget);

    return gadget;

on_error:
    evas_object_del(gadget);
    return NULL;
}

Evas_Object *
efl_gadget_new(Evas *evas, const char *path, const char *uid)
{
    Evas_Smart *smart;
    Evas_Object *gadget;

    if (!evas) {
        ERR("No canvas to add the gadget to\n");
        return NULL;
    }

    smart = evas_smart_class_new(_smart_class_new());
    if (!smart) {
        ERR("Could not create new smart class\n");
        return NULL;
    }

    gadget = _create_gadget(evas, smart, path, uid);
    if (!gadget) {
        ERR("Could not create new gadget\n");
        return NULL;
    }

    return gadget;
}

const char *
efl_gadget_path_get(Evas_Object *gadget)
{
    SMART_DATA_GET_OR_RETURN_NULL(gadget, priv);
    return priv->path;
}

const char *
efl_gadget_uid_get(Evas_Object *gadget)
{
    SMART_DATA_GET_OR_RETURN_NULL(gadget, priv);
    return priv->uid;
}

void
efl_gadget_init(int argc, char *argv[])
{
    if (!g_type_init_count)
        g_type_init();
    g_type_init_count++;

    if (!gtk_init_count)
        gtk_init(&argc, &argv);
    gtk_init_count++;

    /* Keep an extra reference around to the gadget manager, because if it ever
       actually has 0 references left, it will free itself and future calls to
       get_manager will misbehave. */
    manager = gadget_manager_get_default();
}

void
efl_gadget_shutdown(void)
{
    if (g_type_init_count - 1 >= 0)
        g_type_init_count--;

    if (gtk_init_count - 1 >= 0)
        gtk_init_count--;

    g_object_unref(manager);
}

Generated by  Doxygen 1.6.0   Back to index