Add support for new E gadgets infra

Edgar gadgets can now live on both shelves and bryces.
This commit is contained in:
Davide Andreoli 2018-03-06 11:04:45 +01:00
parent c751489d8c
commit 205a16700e
4 changed files with 283 additions and 4 deletions

View File

@ -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 *******************************************************/
/*****************************************************************************/

View File

@ -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

View File

@ -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

View File

@ -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