diff --git a/src/e_mod_edgar.c b/src/e_mod_edgar.c index 5a47525..9ed32a5 100644 --- a/src/e_mod_edgar.c +++ b/src/e_mod_edgar.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2008-2014 Davide Andreoli (see AUTHORS) +/* Copyright (C) 2008-2018 Davide Andreoli (see AUTHORS) * * This file is part of edgar. * edgar is free software: you can redistribute it and/or modify @@ -23,6 +23,18 @@ #include "efl.eo_api.h" +#ifdef EFL_VERSION_1_21 +#define EDGAR_GADGETS_DOMAIN "Edgar" +#endif + + +/* TODO: + + - correctly manage the new bryce orientations + - change popups to be elm based, no more edje for them + +*/ + /* Local typedefs */ typedef struct { const char *name; // ex: "ruler" (from folder name) @@ -53,6 +65,14 @@ static const char *_edgar_gc_id_new(const E_Gadcon_Client_Class *client_class); static void _edgar_gc_id_del(const E_Gadcon_Client_Class *client_class, const char *id); static Evas_Object *_edgar_gc_icon(const E_Gadcon_Client_Class *client_class, Evas *evas); +#ifdef EDGAR_GADGETS_DOMAIN +/* Local Gadget/Bryce Prototypes */ +EINTERN Evas_Object *edgar_bryce_create_cb(Evas_Object *parent, const char *type, int *id, E_Gadget_Site_Orient orient); +EINTERN char *edgar_bryce_name_cb(const char *type); +static Evas_Object *edgar_bryce_popup_new(Edgar_Py_Gadget *gadget, Evas_Object *gadget_object); +static void edgar_bryce_popup_del(Edgar_Py_Gadget *gadget, Evas_Object *ctx_popup); +#endif + /* Python eapi module proto */ PyMODINIT_FUNC PyInit_eapi(void); @@ -293,6 +313,14 @@ edgar_gadget_load(const char *name, const char *path) e_gadcon_provider_register(cclass); eina_hash_add(edgar_gadgets, name, gadget); +#ifdef EDGAR_GADGETS_DOMAIN + // add the gadget to the bryce gadgets system + e_gadget_external_type_add(EDGAR_GADGETS_DOMAIN, name, + edgar_bryce_create_cb, NULL); + e_gadget_external_type_name_cb_set(EDGAR_GADGETS_DOMAIN, name, + edgar_bryce_name_cb); +#endif + return gadget; } @@ -308,6 +336,11 @@ edgar_gadget_unload(Edgar_Py_Gadget *gadget) EINA_LIST_FOREACH_SAFE(gadget->pops_obj, l, l2, popup_content) E_FREE_FUNC(popup_content, evas_object_del); +#ifdef EDGAR_GADGETS_DOMAIN + // remove the gadget from the bryce gadgets system + e_gadget_external_type_del(EDGAR_GADGETS_DOMAIN, gadget->name); +#endif + // Free the gadcon client class e_gadcon_provider_unregister(gadget->cclass); eina_stringshare_del(gadget->cclass->name); @@ -583,6 +616,252 @@ edgar_mouse_down1_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) } +#ifdef EDGAR_GADGETS_DOMAIN +/*****************************************************************************/ +/***** Gadget/Bryce Pupup *************************************************/ +/*****************************************************************************/ +static void +edgar_bryce_ctxpopup_dismissed_cb(void *data, Evas_Object *obj, void *info EINA_UNUSED) +{ + Edgar_Py_Gadget *gadget = data; + edgar_bryce_popup_del(gadget, obj); +} + +static Evas_Object * +edgar_bryce_popup_new(Edgar_Py_Gadget *gadget, Evas_Object *gadget_object) +{ + Evas_Object *ctxpopup, *content; + + DBG("EDGAR: Bryce popup for gadget:%s", gadget->name); + + // create the popup content from the e/gadgets/name/popup group + content = edje_object_add(evas_object_evas_get(gadget_object)); + if (!edgar_theme_object_set(gadget, content, "popup")) + { + DBG("EDGAR: Bryce no popup found for gadget:%s", gadget->name); + evas_object_del(content); + return NULL; + } + // tell edje to propagate sizes to the ctxpopup + edje_object_update_hints_set(content, EINA_TRUE); + + // call the popup_created() method of the gadget. + PyObject *pyobj = object_from_instance(content); + PyObject *ret = PyObject_CallMethod(gadget->instance, "popup_created", + "(S)", pyobj); + PY_ON_ERROR_RETURN(!ret, NULL, "Cannot call popup_created()"); + Py_DECREF(pyobj); + Py_DECREF(ret); + + // put the popup content in an elm ctxpopup + ctxpopup = elm_ctxpopup_add(e_gadget_site_get(gadget_object)); + elm_object_style_set(ctxpopup, "noblock"); + elm_object_content_set(ctxpopup, content); + evas_object_smart_callback_add(ctxpopup, "dismissed", + edgar_bryce_ctxpopup_dismissed_cb, gadget); + e_gadget_util_ctxpopup_place(gadget_object, ctxpopup, NULL); + evas_object_show(ctxpopup); + + // keep track of the popup + gadget->pops_obj = eina_list_append(gadget->pops_obj, content); + evas_object_data_set(gadget_object, "edgar-ctxpopup", ctxpopup); + evas_object_data_set(ctxpopup, "edgar-ctxpopup-owner", gadget_object); + + return ctxpopup; +} + +static void +edgar_bryce_popup_del(Edgar_Py_Gadget *gadget, Evas_Object *ctxpopup) +{ + Evas_Object *popup_content = elm_object_content_get(ctxpopup); + Evas_Object *gadget_object = evas_object_data_get(ctxpopup, "edgar-ctxpopup-owner"); + + DBG("EDGAR: Bryce popup delete for gadget:%s", gadget->name); + + // call the popup_destoyed() method of the gadget. + PyObject *pyobj = object_from_instance(popup_content); + PyObject *ret = PyObject_CallMethod(gadget->instance, "popup_destroyed", + "(S)", pyobj); + PY_ON_ERROR_RETURN(!ret, , "Cannot call popup_destroyed()"); + Py_DECREF(pyobj); + Py_DECREF(ret); + + // remove popup references + gadget->pops_obj = eina_list_remove(gadget->pops_obj, popup_content); + evas_object_data_del(gadget_object, "edgar-ctxpopup"); + evas_object_data_del(ctxpopup, "edgar-ctxpopup-owner"); + + // delete the ctxpopup itself and the content object + evas_object_del(ctxpopup); +} + + +/*****************************************************************************/ +/***** Gadget/Bryce Menu *************************************************/ +/*****************************************************************************/ +static void +edgar_bryce_menu_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info) +{ + Edgar_Py_Gadget *gadget = data; + E_Menu *m = event_info; + E_Menu_Item *mi; + + DBG("EDGAR: Bryce menu for gadget:%s", gadget->name); + e_menu_title_set(m, gadget->label); + + mi = e_menu_item_new(m); + e_menu_item_label_set(mi, "Gadget info"); + e_util_menu_item_theme_icon_set(mi, "help-about"); + e_menu_item_callback_set(mi, edgar_menu_info_cb, gadget); +} + +static void +edgar_bryce_mouse_down_cb(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event) +{ + Edgar_Py_Gadget *gadget = data; + Evas_Event_Mouse_Down *ev = event; + Eina_Bool pop_on_desk = (uintptr_t)evas_object_data_get(obj, "edgar-pop-on-desk"); + + if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; + + if (ev->button == 1 && !pop_on_desk) // left button (gadget popup) + { + Evas_Object *ctxpopup; + + if ((ctxpopup = evas_object_data_get(obj, "edgar-ctxpopup"))) + elm_ctxpopup_dismiss(ctxpopup); + else if ((ctxpopup = edgar_bryce_popup_new(gadget, obj))) + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; + } + else if (ev->button == 3) // right button (TODO) + { + // e_gadget_configure(inst->o_clock); + ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD; + } +} + + +/*****************************************************************************/ +/***** Gadget/Bryce IFace *************************************************/ +/*****************************************************************************/ +static void +edgar_bryce_delete_cb(void *data, const Efl_Event *event) +{ + Edgar_Py_Gadget *gadget = data; + Evas_Object *gadget_object = event->object; + Evas_Object *ctxpopup; + PyObject *pyobj, *ret; + Eina_Bool pop_on_desk = (uintptr_t)evas_object_data_get(gadget_object, + "edgar-pop-on-desk"); + + DBG("EDGAR: Bryce instance del for gadget:%s", gadget->name); + + // is there a popup opened for this gadget object? + if ((ctxpopup = evas_object_data_get(gadget_object, "edgar-ctxpopup"))) + edgar_bryce_popup_del(gadget, ctxpopup); + + // call the correct method in the python gadget + pyobj = object_from_instance(gadget_object); + if (pop_on_desk) + { + ret = PyObject_CallMethod(gadget->instance, "popup_destroyed", + "(S)", pyobj); + PY_ON_ERROR_RETURN(!ret, , "Cannot call popup_destroyed()"); + } + else + { + ret = PyObject_CallMethod(gadget->instance, "instance_destroyed", + "(S)", pyobj); + PY_ON_ERROR_RETURN(!ret, , "Cannot call instance_destroyed()"); + } + Py_XDECREF(ret); + Py_XDECREF(pyobj); +} + +EINTERN Evas_Object * +edgar_bryce_create_cb(Evas_Object *parent, const char *type, int *id, E_Gadget_Site_Orient orient) +{ + Edgar_Py_Gadget *gadget; + Evas_Object *obj; + Eina_Bool pop_on_desk = EINA_FALSE; + + gadget = eina_hash_find(edgar_gadgets, type); + if (!gadget) return NULL; + + DBG("EDGAR: Bryce create type:%s id:%d (orient:%d) (edjefile:%s)", + type, *id, orient, gadget->edjefile); + + // create the python Gadget class instance (if not already done) + if (!gadget->instance) + { + DBG("EDGAR: Instantiate the python class"); + gadget->instance = PyObject_CallMethod(gadget->mod, "Gadget", ""); + PY_ON_ERROR_RETURN(!gadget->instance, NULL, "Cannot create the Gadget instance"); + } + + // do we want the popup expanded on desktop ? + if (gadget->opt_pop_on_desk && orient == E_GADGET_SITE_ORIENT_NONE && *id >= 0) + pop_on_desk = EINA_TRUE; + + // create the edje object (main or popup) + obj = edje_object_add(evas_object_evas_get(parent)); + if (!edgar_theme_object_set(gadget, obj, pop_on_desk ? "popup" : "main")) + { + DBG("EDGAR: ERROR, cannot find a theme for the gadget: '%s'", type); + evas_object_del(obj); + return NULL; + } + evas_object_data_set(obj, "edgar-pop-on-desk", (void*)(uintptr_t)pop_on_desk); + evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN, + edgar_bryce_mouse_down_cb, gadget); + evas_object_smart_callback_add(obj, "gadget_menu", + edgar_bryce_menu_cb, gadget); + // keep track of this instance lifetime (I would have really preferred an explicit callback here!!) + // NOTE: del cb with priority to be called before the python-efl one. + // Otherwise python-efl delete the python obj too soon. + efl_event_callback_priority_add(obj, EFL_EVENT_DEL, + EFL_CALLBACK_PRIORITY_BEFORE, + edgar_bryce_delete_cb, gadget); + + // call the correct method in the python gadget + PyObject *pyobj = object_from_instance(obj); + PyObject *ret = NULL; + if (pop_on_desk) + { + ret = PyObject_CallMethod(gadget->instance, "popup_created", + "(S)", pyobj); + PY_ON_ERROR_RETURN(!ret, NULL, "Cannot call popup_created()"); + } + else + { + ret = PyObject_CallMethod(gadget->instance, "instance_created", + // "(Si)", pyobj, gc->location->site); + "(Si)", pyobj, 0); // TODO PASS THE CORRECT ORIENT !! + PY_ON_ERROR_RETURN(!ret, NULL, "Cannot call instance_created()"); + } + Py_XDECREF(ret); + Py_XDECREF(pyobj); + + return obj; +} + +EINTERN char * +edgar_bryce_name_cb(const char *type) +{ + Edgar_Py_Gadget *gadget; + Eina_Strbuf *buf = eina_strbuf_new(); + + if (!buf) return NULL; + gadget = eina_hash_find(edgar_gadgets, type); + if (!gadget) return NULL; + + eina_strbuf_append_printf(buf, "%s (python)", gadget->label); + + return eina_strbuf_release(buf); +} +#endif + + /*****************************************************************************/ /***** Gadcon IFace *******************************************************/ /*****************************************************************************/ diff --git a/src/e_mod_edgar.h b/src/e_mod_edgar.h index edfb5e6..0b257a8 100644 --- a/src/e_mod_edgar.h +++ b/src/e_mod_edgar.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2008 Davide Andreoli (see AUTHORS) +/* Copyright (C) 2008-2018 Davide Andreoli (see AUTHORS) * * This file is part of edgar. * edgar is free software: you can redistribute it and/or modify diff --git a/src/e_mod_main.c b/src/e_mod_main.c index e03fd04..16b897a 100644 --- a/src/e_mod_main.c +++ b/src/e_mod_main.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2008-2014 Davide Andreoli (see AUTHORS) +/* Copyright (C) 2008-2018 Davide Andreoli (see AUTHORS) * * This file is part of edgar. * edgar is free software: you can redistribute it and/or modify diff --git a/src/e_mod_main.h b/src/e_mod_main.h index 2e442d9..ab4ba76 100644 --- a/src/e_mod_main.h +++ b/src/e_mod_main.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2008 Davide Andreoli (see AUTHORS) +/* Copyright (C) 2008-2018 Davide Andreoli (see AUTHORS) * * This file is part of edgar. * edgar is free software: you can redistribute it and/or modify