enlightenment-module-comp-s.../src/e_mod_main.c

1164 lines
30 KiB
C

#include <e.h>
#include "e_mod_main.h"
/* Local Function Prototypes */
static E_Gadcon_Client *_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style);
static void _gc_shutdown(E_Gadcon_Client *gcc);
static void _gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient);
static char *_gc_label(E_Gadcon_Client_Class *client_class);
static const char *_gc_id_new(E_Gadcon_Client_Class *client_class);
static Evas_Object *_gc_icon(E_Gadcon_Client_Class *client_class, Evas *evas);
static void _scale_conf_new(void);
static void _scale_conf_free(void);
static Eina_Bool _scale_conf_timer(void *data);
static Config_Item *_scale_conf_item_get(const char *id);
static void _scale_cb_mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event);
static void _scale_cb_menu_post(void *data, E_Menu *menu);
static void _scale_cb_menu_configure(void *data, E_Menu *mn, E_Menu_Item *mi);
static void movorig(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void reszorig(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void delorig(void *data, Evas *e, Evas_Object *obj, void *event_info);
static E_Action *act = NULL;
typedef struct _Item Item;
typedef struct _E_Comp_Win E_Comp_Win;
struct _Item
{
Evas_Object *o;
E_Border *bd;
E_Comp_Win *cw;
double factor;
int x;
int y;
int w;
int h;
int mx;
int my;
};
static Eina_List *items = NULL;
static Eina_List *handlers = NULL;
static Ecore_Timer *timer = NULL;
static int max_x;
static int max_y;
static int min_x;
static int min_y;
static int width, height;
static int cnt = 0;
static double factor;
static double advance = 0.0;
static double zoom = 0.00;
static Ecore_X_Window input_win = 0;
static E_Msg_Handler *msg_handler = NULL;
/* static Evas *comp_evas = NULL; */
struct _E_Comp_Win
{
EINA_INLIST;
void *c; // parent compositor
Ecore_X_Window win; // raw window - for menus etc.
E_Border *bd; // if its a border - later
E_Popup *pop; // if its a popup - later
E_Menu *menu; // if it is a menu - later
int x, y, w, h; // geometry
struct {
int x, y, w, h; // hidden geometry (used when its unmapped and re-instated on map)
} hidden;
int pw, ph; // pixmap w/h
int border; // border width
Ecore_X_Pixmap pixmap; // the compositing pixmap
Ecore_X_Damage damage; // damage region
Ecore_X_Visual vis; // window visual
int depth; // window depth
Evas_Object *obj; // composite object
Evas_Object *shobj; // shadow object
Eina_List *obj_mirror; // extra mirror objects
Ecore_X_Image *xim; // x image - software fallback
void *up; // update handler
E_Object_Delfn *dfn; // delete function handle for objects being tracked
Ecore_X_Sync_Counter counter; // sync counter for syncronised drawing
Ecore_Timer *update_timeout; // max time between damage and "done" event
Ecore_Timer *ready_timeout; // max time on show (new window draw) to wait for window contents to be ready if sync protocol not handled. this is fallback.
int dmg_updates; // num of damage event updates since a redirect
Ecore_X_Rectangle *rects; // shape rects... if shaped :(
int rects_num; // num rects above
Ecore_X_Pixmap cache_pixmap; // the cached pixmap (1/nth the dimensions)
int cache_w, cache_h; // cached pixmap size
int update_count; // how many updates have happened to this win
double last_visible_time; // last time window was visible
double last_draw_time; // last time window was damaged
int pending_count; // pending event count
char *title, *name, *clas, *role; // fetched for override-redirect windowa
Ecore_X_Window_Type primary_type; // fetched for override-redirect windowa
Eina_Bool delete_pending : 1; // delete pendig
Eina_Bool hidden_override : 1; // hidden override
Eina_Bool animating : 1; // it's busy animating - defer hides/dels
Eina_Bool force : 1; // force del/hide even if animating
Eina_Bool defer_hide : 1; // flag to get hide to work on deferred hide
Eina_Bool delete_me : 1; // delete me!
Eina_Bool visible : 1; // is visible
Eina_Bool input_only : 1; // is input_only
Eina_Bool override : 1; // is override-redirect
Eina_Bool argb : 1; // is argb
Eina_Bool shaped : 1; // is shaped
Eina_Bool update : 1; // has updates to fetch
Eina_Bool redirected : 1; // has updates to fetch
Eina_Bool shape_changed : 1; // shape changed
Eina_Bool native : 1; // native
Eina_Bool drawme : 1; // drawme flag fo syncing rendering
Eina_Bool invalid : 1; // invalid depth used - just use as marker
Eina_Bool nocomp : 1; // nocomp applied
Eina_Bool needpix : 1; // need new pixmap
Eina_Bool needxim : 1; // need new xim
Eina_Bool real_hid : 1; // last hide was a real window unmap
Eina_Bool inhash : 1; // is in the windows hash
Eina_Bool show_ready : 1; // is this window ready for its first show
};
static int
_grow()
{
Item *it, *ot;
Eina_List *l, *ll;
int cont = 0;
int overlap;
int grow_l, grow_r, grow_d, grow_u;
EINA_LIST_FOREACH(items, l, it)
{
if (it->w >= it->bd->w)
continue;
if (it->h >= it->bd->h)
continue;
overlap = 0;
grow_l = grow_r = 2;
grow_u = grow_d = 2.0 * (double)it->bd->h/(double)it->bd->w;
if (it->x - grow_l < 0)
grow_l = 0;
if (it->y - grow_u < 0)
grow_u = 0;
if (it->x + it->w + grow_r > width)
grow_r = 0;
if (it->y + it->h + grow_d > height)
grow_d = 0;
if (!(grow_l || grow_r))
continue;
if (!(grow_u || grow_d))
continue;
EINA_LIST_FOREACH(items, ll, ot)
{
if (it == ot)
continue;
if (grow_l &&
E_INTERSECTS(it->x-grow_l*2, it->y, it->w, it->h,
ot->x, ot->y, ot->w, ot->h))
grow_l = 0;
if (grow_u &&
E_INTERSECTS(it->x, it->y-grow_u*2, it->w, it->h,
ot->x, ot->y, ot->w, ot->h))
grow_u = 0;
if (grow_r &&
E_INTERSECTS(it->x, it->y, it->w+grow_r*2, it->h,
ot->x, ot->y, ot->w, ot->h))
grow_r = 0;
if (grow_d &&
E_INTERSECTS(it->x, it->y, it->w, it->h+grow_d*2,
ot->x, ot->y, ot->w, ot->h))
grow_d = 0;
if (!((grow_l || grow_r) && (grow_u || grow_d)))
{
overlap = 1;
break;
}
}
if (!overlap)
{
cont++;
it->w += (grow_u && grow_d) ? 4 : 2;
it->h = it->w * (double)it->bd->h/(double)it->bd->w;
it->x -= grow_l;
it->y -= grow_u;
}
}
return cont;
}
static int
_place()
{
Item *it, *ot;
Eina_List *l, *ll;
int overlap = 0;
int outside = 0;
cnt++;
EINA_LIST_FOREACH(items, l, it)
{
it->mx = it->x;
it->my = it->y;
}
EINA_LIST_FOREACH(items, l, it)
{
EINA_LIST_FOREACH(l->next, ll, ot)
{
int w = it->w;
int h = it->h;
if (!E_INTERSECTS(it->x-2, it->y-2, it->w+4, it->h+4, ot->x, ot->y, ot->w, ot->h))
continue;
overlap += 1;
if (it->x < ot->x)
w += it->x - ot->x;
if (w < 0) w = 0;
if (it->x + it->w > ot->x + ot->w)
w = ot->x + ot->w - it->x;
if (it->y < ot->y)
h += it->y - ot->y;
if (h < 0) h = 0;
if (it->y + it->h > ot->y + ot->h)
h = ot->y + ot->h - it->y;
int dist_y = (it->y + it->h/2) - (ot->y + ot->h/2);
int dist_x = (it->x + it->w/2) - (ot->x + ot->w/2);
if (dist_x == 0 && dist_y == 0)
{
ot->x +=1;
ot->y +=1;
}
if (w > h)
{
if (dist_y)
{
dist_y = (dist_y > 0 ? 2 : -2);
it->my += dist_y;
ot->my -= dist_y;
}
if (dist_x)
{
dist_x = (dist_x > 0 ? 1 : -1);
it->mx += dist_x;
ot->mx -= dist_x;
}
}
else //if (w < h)
{
if (dist_y)
{
dist_y = (dist_y > 0 ? 1 : -1);
it->my += dist_y;
ot->my -= dist_y;
}
if (dist_x)
{
dist_x = (dist_x > 0 ? 2 : -2);
it->mx += dist_x;
ot->mx -= dist_x;
}
}
}
}
if (!overlap)
return 0;
EINA_LIST_FOREACH(items, l, it)
{
it->x = it->mx;
it->y = it->my;
if (it->x < 0)
{
outside = 1;
it->x = 0;
}
if (it->y < min_y)
{
outside = 1;
it->y = min_y;
}
if (it->x + it->w > max_x)
{
outside = 1;
it->x = max_x - it->w;
}
if (it->y + it->h > max_y)
{
outside = 1;
it->y = max_y - it->h;
}
}
if (outside)
{
if (cnt > 20)
{
/* printf("resize %f\n", factor); */
cnt = 0;
factor -= 0.02;
EINA_LIST_FOREACH(items, l, it)
{
it->w = it->bd->w * factor;
it->h = it->bd->h * factor;
}
}
return 1;
}
return overlap;
}
static void
_finish()
{
Ecore_Event_Handler *handler;
/* Eina_List *l; */
Item *it;
e_grabinput_release(input_win, input_win);
ecore_x_window_free(input_win);
input_win = 0;
EINA_LIST_FREE(items, it)
{
evas_object_event_callback_del(it->o, EVAS_CALLBACK_MOVE, movorig);
evas_object_event_callback_del(it->o, EVAS_CALLBACK_RESIZE, reszorig);
evas_object_event_callback_del(it->o, EVAS_CALLBACK_DEL, delorig);
E_FREE(it);
}
EINA_LIST_FREE(handlers, handler)
ecore_event_handler_del(handler);
e_msg_handler_del(msg_handler);
msg_handler = NULL;
e_manager_comp_evas_update(e_manager_current_get());
}
static Eina_Bool
_redraw(void *blah)
{
Eina_List *l;
Item *it;
advance += zoom;
/* evas_event_freeze(comp_evas); */
if (advance <= 1.0 && advance >= 0.0)
{
EINA_LIST_FOREACH(items, l, it)
{
it->cw->x = it->bd->x * (1.0 - advance) + it->x * advance;
it->cw->y = it->bd->y * (1.0 - advance) + it->y * advance;
double scaling = (double)(it->bd->w * (1.0 - advance) + it->w * advance) / (double)(it->cw->pw);
evas_object_move(it->o,
it->bd->x * (1.0 - advance) + it->x * advance,
it->bd->y * (1.0 - advance) + it->y * advance);
evas_object_resize(it->o,
it->cw->pw * scaling,
it->cw->ph * scaling);
}
}
/* evas_event_thaw(comp_evas); */
e_manager_comp_evas_update(e_manager_current_get());
if (advance <= 1.0 && advance >= 0.0)
return 1;
if (advance <= 0.0)
_finish();
timer = NULL;
return 0;
}
static void
delorig(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
/* Eina_List *l; */
Item *it = data;
items = eina_list_remove(items, it);
evas_object_event_callback_del(it->o, EVAS_CALLBACK_MOVE, movorig);
evas_object_event_callback_del(it->o, EVAS_CALLBACK_RESIZE, reszorig);
evas_object_event_callback_del(it->o, EVAS_CALLBACK_DEL, delorig);
E_FREE(it);
if (!timer)
timer = ecore_timer_add(0.01, _redraw, NULL);
zoom = -0.10;
}
static void
movorig(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
/* Item *it = data; */
/* printf("move\n"); */
}
// FIXME
static void
reszorig(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
Item *it = data;
int w, h;
double adv;
evas_object_geometry_get(obj, NULL, NULL, &w, &h);
if (advance > 1.0)
adv = 1.0;
else if (advance < 0.0)
adv = 0.0;
else
adv = advance;
double scaling = (double)(it->bd->w * (1.0 - adv) + it->w * adv) / (double)(it->cw->pw);
if (!((it->cw->pw * scaling == w) && (it->cw->ph * scaling == h)))
{
evas_object_resize(it->o,
it->cw->pw * scaling,
it->cw->ph * scaling);
}
}
static void
newwin(Evas *e, E_Manager *man, E_Manager_Comp_Source *src, E_Desk *desk)
{
Evas_Object *o;
Item *it;
if (!e_manager_comp_src_image_get(man, src)) return;
E_Comp_Win *cw = (void*)src;
if (!cw->bd) return;
if (cw->bd->desk != desk)
return;
it = E_NEW(Item, 1);
o = e_manager_comp_src_shadow_get(man, src);
/* evas_object_event_callback_add(o, EVAS_CALLBACK_MOVE, movorig, it); */
evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE, reszorig, it);
evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, delorig, it);
/* it->x = cw->bd->x;
* it->y = cw->bd->y; */
it->x = cw->bd->x + (cw->bd->desk->x - desk->x) * width;
it->y = cw->bd->y + (cw->bd->desk->y - desk->y) * height;
it->w = cw->bd->w;
it->h = cw->bd->h;
it->o = o;
it->bd = cw->bd;
it->cw = cw;
/* if (cw->bd->desk != desk)
* {
* cw->visible = EINA_TRUE;
* evas_object_show(o);
* evas_object_move(o, it->x, it->y);
* } */
/*
* e_manager_comp_src_hidden_set(man, src, EINA_FALSE);
* evas_object_show(o); */
items = eina_list_append(items, it);
}
static Eina_Bool
_cb_mouse_down(void *data, int type, void *event)
{
Ecore_Event_Mouse_Button *ev;
ev = event;
if (ev->window != input_win) return ECORE_CALLBACK_PASS_ON;
if (!timer)
timer = ecore_timer_add(0.01, _redraw, NULL);
zoom = -0.10;
Item *it;
Eina_List *l;
EINA_LIST_FOREACH(items, l, it)
{
if (E_INTERSECTS(ev->x, ev->y, 1, 1, it->x, it->y, it->w, it->h))
{
e_border_raise(it->bd);
break;
}
}
return ECORE_CALLBACK_PASS_ON;
}
static void
setup(E_Manager *man)
{
Eina_List *list, *l;
E_Manager_Comp_Source *src;
Evas *e;
int i = 0;
E_Zone *zone = e_util_zone_current_get(e_manager_current_get());
E_Desk *desk = e_desk_current_get(zone);
input_win = ecore_x_window_input_new(zone->container->win, 0, 0, 1, 1);
ecore_x_window_show(input_win);
if (!e_grabinput_get(input_win, 0, input_win))
{
ecore_x_window_free(input_win);
input_win = 0;
return;
}
e_zone_useful_geometry_get(zone, &min_x, &min_y, &width, &height);
handlers = eina_list_append
(handlers, ecore_event_handler_add
(ECORE_EVENT_MOUSE_BUTTON_DOWN, _cb_mouse_down, NULL));
e = e_manager_comp_evas_get(man);
/* comp_evas = e; */
list = (Eina_List *)e_manager_comp_src_list(man);
EINA_LIST_FOREACH(list, l, src)
{
newwin(e, man, src, desk);
}
max_x = width;
max_y = height;
factor = 1.0;
while (i++ < 10000 && _place());
printf("place %d\n", i);
if (i == 1)
{
_finish();
return;
}
i = 0;
while (i++ < 10000 && _grow())
{
int k = 0;
cnt = 0;
while (k++ < 10 && _place());
}
printf("grow %d\n", i);
advance = 0.0;
zoom = 0.1;
if (!timer)
timer = ecore_timer_add(0.01, _redraw, NULL);
}
static void
handler(void *data, const char *name, const char *info, int val,
E_Object *obj, void *msgdata)
{
E_Manager *man = (E_Manager *)obj;
E_Manager_Comp_Source *src = (E_Manager_Comp_Source *)msgdata;
Evas *e;
printf("handler... '%s' '%s'\n", name, info);
if (strcmp(name, "comp.manager")) return;
e = e_manager_comp_evas_get(man);
if (!strcmp(info, "change.comp"))
{
if (!e) printf("TTT: No comp manager\n");
else printf("TTT: comp canvas = %p\n", e);
if (e) setup(man);
}
else if (!strcmp(info, "resize.comp"))
{
printf("%s: %p | %p\n", info, man, src);
}
else if (!strcmp(info, "add.src"))
{
printf("%s: %p | %p\n", info, man, src);
newwin(e, man, src, e_desk_current_get(e_util_zone_current_get(man)));
}
else if (!strcmp(info, "del.src"))
{
printf("%s: %p | %p\n", info, man, src);
}
else if (!strcmp(info, "config.src"))
{
printf("%s: %p | %p\n", info, man, src);
}
else if (!strcmp(info, "visible.src"))
{
printf("%s: %p | %p\n", info, man, src);
}
}
/* Local Structures */
typedef struct _Instance Instance;
struct _Instance
{
/* An instance of our item (module) with its elements */
/* pointer to this gadget's container */
E_Gadcon_Client *gcc;
/* evas_object used to display */
Evas_Object *o_scale;
/* popup anyone ? */
E_Menu *menu;
/* Config_Item structure. Every gadget should have one :) */
Config_Item *conf_item;
};
/* Local Variables */
static int uuid = 0;
static Eina_List *instances = NULL;
static E_Config_DD *conf_edd = NULL;
static E_Config_DD *conf_item_edd = NULL;
Config *scale_conf = NULL;
static const E_Gadcon_Client_Class _gc_class =
{
GADCON_CLIENT_CLASS_VERSION, "scale",
{_gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon,
_gc_id_new, NULL, NULL},
E_GADCON_CLIENT_STYLE_PLAIN
};
/* We set the version and the name, check e_mod_main.h for more details */
EAPI E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Scale"};
/*
* Module Functions
*/
static void
_e_mod_action_cb_edge(E_Object *obj, const char *params, E_Event_Zone_Edge *ev)
{
Eina_List *list, *l;
E_Manager *man;
msg_handler = e_msg_handler_add(handler, NULL);
list = e_manager_list();
EINA_LIST_FOREACH(list, l, man)
{
Evas *e = e_manager_comp_evas_get(man);
if (e) setup(man);
}
}
/* Function called when the module is initialized */
EAPI void *
e_modapi_init(E_Module *m)
{
char buf[4096];
/* Location of message catalogs for localization */
snprintf(buf, sizeof(buf), "%s/locale", e_module_dir_get(m));
bindtextdomain(PACKAGE, buf);
bind_textdomain_codeset(PACKAGE, "UTF-8");
/* Location of theme to load for this module */
snprintf(buf, sizeof(buf), "%s/e-module-scale.edj", m->dir);
/* Display this Modules config info in the main Config Panel */
/* starts with a category, create it if not already exists */
e_configure_registry_category_add("advanced", 80, "Advanced",
NULL, "preferences-advanced");
/* add right-side item */
e_configure_registry_item_add("advanced/scale", 110, D_("Scale"),
NULL, buf, e_int_config_scale_module);
/* Define EET Data Storage for the config file */
conf_item_edd = E_CONFIG_DD_NEW("Config_Item", Config_Item);
#undef T
#undef D
#define T Config_Item
#define D conf_item_edd
E_CONFIG_VAL(D, T, id, STR);
E_CONFIG_VAL(D, T, switch2, INT);
conf_edd = E_CONFIG_DD_NEW("Config", Config);
#undef T
#undef D
#define T Config
#define D conf_edd
E_CONFIG_VAL(D, T, version, INT);
E_CONFIG_VAL(D, T, switch1, UCHAR); /* our var from header */
E_CONFIG_LIST(D, T, conf_items, conf_item_edd); /* the list */
/* Tell E to find any existing module data. First run ? */
scale_conf = e_config_domain_load("module.scale", conf_edd);
if (scale_conf)
{
/* Check config version */
if ((scale_conf->version >> 16) < MOD_CONFIG_FILE_EPOCH)
{
/* config too old */
_scale_conf_free();
ecore_timer_add(1.0, _scale_conf_timer,
D_("Scale Module Configuration data needed "
"upgrading. Your old configuration<br> has been"
" wiped and a new set of defaults initialized. "
"This<br>will happen regularly during "
"development, so don't report a<br>bug. "
"This simply means the module needs "
"new configuration<br>data by default for "
"usable functionality that your old<br>"
"configuration simply lacks. This new set of "
"defaults will fix<br>that by adding it in. "
"You can re-configure things now to your<br>"
"liking. Sorry for the inconvenience.<br>"));
}
/* Ardvarks */
else if (scale_conf->version > MOD_CONFIG_FILE_VERSION)
{
/* config too new...wtf ? */
_scale_conf_free();
ecore_timer_add(1.0, _scale_conf_timer,
D_("Your Scale Module configuration is NEWER "
"than the module version. This is "
"very<br>strange. This should not happen unless"
" you downgraded<br>the module or "
"copied the configuration from a place where"
"<br>a newer version of the module "
"was running. This is bad and<br>as a "
"precaution your configuration has been now "
"restored to<br>defaults. Sorry for the "
"inconvenience.<br>"));
}
}
/* if we don't have a config yet, or it got erased above,
* then create a default one */
if (!scale_conf) _scale_conf_new();
/* create a link from the modules config to the module
* this is not written */
scale_conf->module = m;
/* Tell any gadget containers (shelves, etc) that we provide a module
* for the user to enjoy */
e_gadcon_provider_register(&_gc_class);
act = e_action_add("scale");
if (act)
{
/* act->func.go = _e_mod_action_cb; */
act->func.go_edge = _e_mod_action_cb_edge;
e_action_predef_name_set
(D_("Desktop"),
D_("Scale Windows"),
"scale", "", NULL, 0);
}
/* Give E the module */
return m;
}
/*
* Function to unload the module
*/
EAPI int
e_modapi_shutdown(E_Module *m)
{
/* Unregister the config dialog from the main panel */
e_configure_registry_item_del("advanced/scale");
/* Remove the config panel category if we can. E will tell us.
category stays if other items using it */
e_configure_registry_category_del("advanced");
/* Kill the config dialog */
if (scale_conf->cfd) e_object_del(E_OBJECT(scale_conf->cfd));
scale_conf->cfd = NULL;
/* Tell E the module is now unloaded. Gets removed from shelves, etc. */
scale_conf->module = NULL;
e_gadcon_provider_unregister(&_gc_class);
/* Cleanup our item list */
while (scale_conf->conf_items)
{
Config_Item *ci = NULL;
/* Grab an item from the list */
ci = scale_conf->conf_items->data;
/* remove it */
scale_conf->conf_items =
eina_list_remove_list(scale_conf->conf_items,
scale_conf->conf_items);
/* cleanup stringshares */
if (ci->id) eina_stringshare_del(ci->id);
/* keep the planet green */
E_FREE(ci);
}
/* Cleanup the main config structure */
E_FREE(scale_conf);
/* Clean EET */
E_CONFIG_DD_FREE(conf_item_edd);
E_CONFIG_DD_FREE(conf_edd);
if (act)
{
e_action_predef_name_del(D_("Desktop"),
D_("Scale Windows"));
e_action_del("scale");
}
return 1;
}
/*
* Function to Save the modules config
*/
EAPI int
e_modapi_save(E_Module *m)
{
e_config_domain_save("module.scale", conf_edd, scale_conf);
return 1;
}
/* Local Functions */
/* Called when Gadget Controller (gadcon) says to appear in scene */
static E_Gadcon_Client *
_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style)
{
Instance *inst = NULL;
char buf[4096];
/* theme file */
snprintf(buf, sizeof(buf), "%s/e-module-scale.edj",
scale_conf->module->dir);
/* New visual instance, any config ? */
inst = E_NEW(Instance, 1);
inst->conf_item = _scale_conf_item_get(id);
/* create on-screen object */
inst->o_scale = edje_object_add(gc->evas);
/* we have a theme ? */
if (!e_theme_edje_object_set(inst->o_scale, "base/theme/modules/scale",
"modules/scale/main"))
edje_object_file_set(inst->o_scale, buf, "modules/scale/main");
/* Start loading our module on screen via container */
inst->gcc = e_gadcon_client_new(gc, name, id, style, inst->o_scale);
inst->gcc->data = inst;
/* hook a mouse down. we want/have a popup menu, right ? */
evas_object_event_callback_add(inst->o_scale, EVAS_CALLBACK_MOUSE_DOWN,
_scale_cb_mouse_down, inst);
/* add to list of running instances so we can cleanup later */
instances = eina_list_append(instances, inst);
/* return the Gadget_Container Client */
return inst->gcc;
}
/* Called when Gadget_Container says stop */
static void
_gc_shutdown(E_Gadcon_Client *gcc)
{
Instance *inst = NULL;
if (!(inst = gcc->data)) return;
instances = eina_list_remove(instances, inst);
/* kill popup menu */
if (inst->menu)
{
e_menu_post_deactivate_callback_set(inst->menu, NULL, NULL);
e_object_del(E_OBJECT(inst->menu));
inst->menu = NULL;
}
/* delete the visual */
if (inst->o_scale)
{
/* remove mouse down callback hook */
evas_object_event_callback_del(inst->o_scale, EVAS_CALLBACK_MOUSE_DOWN,
_scale_cb_mouse_down);
evas_object_del(inst->o_scale);
}
E_FREE(inst);
}
/* For when container says we are changing position */
static void
_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient)
{
e_gadcon_client_aspect_set(gcc, 16, 16);
e_gadcon_client_min_size_set(gcc, 16, 16);
}
/* Gadget/Module label, name for our module */
static char *
_gc_label(E_Gadcon_Client_Class *client_class)
{
return D_("Scale");
}
/* so E can keep a unique instance per-container */
static const char *
_gc_id_new(E_Gadcon_Client_Class *client_class)
{
Config_Item *ci = NULL;
ci = _scale_conf_item_get(NULL);
return ci->id;
}
static Evas_Object *
_gc_icon(E_Gadcon_Client_Class *client_class, Evas *evas)
{
Evas_Object *o = NULL;
char buf[4096];
/* theme */
snprintf(buf, sizeof(buf), "%s/e-module-scale.edj", scale_conf->module->dir);
/* create icon object */
o = edje_object_add(evas);
/* load icon from theme */
edje_object_file_set(o, buf, "icon");
return o;
}
/* new module needs a new config :), or config too old and we need one anyway */
static void
_scale_conf_new(void)
{
/* Config_Item *ci = NULL; */
/* char buf[128]; */
scale_conf = E_NEW(Config, 1);
scale_conf->version = (MOD_CONFIG_FILE_EPOCH << 16);
#define IFMODCFG(v) if ((scale_conf->version & 0xffff) < v) {
#define IFMODCFGEND }
/* setup defaults */
IFMODCFG(0x008d);
scale_conf->switch1 = 1;
_scale_conf_item_get(NULL);
IFMODCFGEND;
/* update the version */
scale_conf->version = MOD_CONFIG_FILE_VERSION;
/* setup limits on the config properties here (if needed) */
/* save the config to disk */
e_config_save_queue();
}
/* This is called when we need to cleanup the actual configuration,
* for example when our configuration is too old */
static void
_scale_conf_free(void)
{
/* cleanup any stringshares here */
while (scale_conf->conf_items)
{
Config_Item *ci = NULL;
ci = scale_conf->conf_items->data;
scale_conf->conf_items =
eina_list_remove_list(scale_conf->conf_items,
scale_conf->conf_items);
/* EPA */
if (ci->id) eina_stringshare_del(ci->id);
E_FREE(ci);
}
E_FREE(scale_conf);
}
/* timer for the config oops dialog (old configuration needs update) */
static Eina_Bool
_scale_conf_timer(void *data)
{
e_util_dialog_internal( D_("Scale Windows Configuration Updated"), data);
return EINA_FALSE;
}
/* function to search for any Config_Item struct for this Item
* create if needed */
static Config_Item *
_scale_conf_item_get(const char *id)
{
Eina_List *l = NULL;
Config_Item *ci = NULL;
char buf[128];
if (!id)
{
/* nothing passed, return a new id */
snprintf(buf, sizeof(buf), "%s.%d", _gc_class.name, ++uuid);
id = buf;
}
else
{
uuid++;
for (l = scale_conf->conf_items; l; l = l->next)
{
if (!(ci = l->data)) continue;
if ((ci->id) && (!strcmp(ci->id, id))) return ci;
}
}
ci = E_NEW(Config_Item, 1);
ci->id = eina_stringshare_add(id);
ci->switch2 = 0;
scale_conf->conf_items = eina_list_append(scale_conf->conf_items, ci);
return ci;
}
/* Pants On */
static void
_scale_cb_mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event)
{
Instance *inst = NULL;
Evas_Event_Mouse_Down *ev;
E_Zone *zone = NULL;
E_Menu_Item *mi = NULL;
int x, y;
if (!(inst = data)) return;
ev = event;
if (ev->button == 1)
{
_e_mod_action_cb_edge(NULL, NULL, NULL);
}
else if ((ev->button == 3) && (!inst->menu))
{
E_Menu *ma, *mg;
/* grab current zone */
zone = e_util_zone_current_get(e_manager_current_get());
/* create popup menu */
ma = e_menu_new();
e_menu_post_deactivate_callback_set(ma, _scale_cb_menu_post, inst);
inst->menu = ma;
mg = e_menu_new();
mi = e_menu_item_new(mg);
e_menu_item_label_set(mi, D_("Settings"));
e_util_menu_item_theme_icon_set(mi, "preferences-system");
e_menu_item_callback_set(mi, _scale_cb_menu_configure, NULL);
/* Each Gadget Client has a utility menu from the Container */
e_gadcon_client_util_menu_items_append(inst->gcc, ma, mg, 0);
e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &x, &y,
NULL, NULL);
/* show the menu relative to gadgets position */
e_menu_activate_mouse(ma, zone, (x + ev->output.x),
(y + ev->output.y), 1, 1,
E_MENU_POP_DIRECTION_AUTO, ev->timestamp);
evas_event_feed_mouse_up(inst->gcc->gadcon->evas, ev->button,
EVAS_BUTTON_NONE, ev->timestamp, NULL);
}
}
/* popup menu closing, cleanup */
static void
_scale_cb_menu_post(void *data, E_Menu *menu)
{
Instance *inst = NULL;
if (!(inst = data)) return;
if (!inst->menu) return;
e_object_del(E_OBJECT(inst->menu));
inst->menu = NULL;
}
/* call configure from popup */
static void
_scale_cb_menu_configure(void *data, E_Menu *mn, E_Menu_Item *mi)
{
if (!scale_conf) return;
if (scale_conf->cfd) return;
e_int_config_scale_module(mn->zone->container, NULL);
}