1 #include "e_mod_appmenu_private.h"
2 
3 static int menu_count = 0;
4 static E_Menu *menu_pending = NULL;
5 static Ecore_Timer *menu_timer = NULL;
6 static int menu_dir = 0;
7 static Evas_Coord menu_x = 0, menu_y = 0, menu_w = 0, menu_h = 0;
8 
9 void
appmenu_cancel(void)10 appmenu_cancel(void)
11 {
12    if (menu_pending)
13      {
14         e_object_del(E_OBJECT(menu_pending));
15         menu_pending = NULL;
16      }
17    if (menu_timer)
18      {
19         ecore_timer_del(menu_timer);
20         menu_timer = NULL;
21      }
22 }
23 
24 int
appmenu_menu_count_get(void)25 appmenu_menu_count_get(void)
26 {
27    return menu_count;
28 }
29 
30 static void
item_activate(void * data EINA_UNUSED,E_Menu * m EINA_UNUSED)31 item_activate(void *data EINA_UNUSED, E_Menu *m EINA_UNUSED)
32 {
33    menu_count++;
34 }
35 
36 static void
item_deactivate(void * data EINA_UNUSED,E_Menu * m)37 item_deactivate(void *data EINA_UNUSED, E_Menu *m)
38 {
39    if (menu_pending == m) menu_pending = NULL;
40    menu_count--;
41 }
42 
43 static void
menu_deactive(E_Menu * m)44 menu_deactive(E_Menu *m)
45 {
46    Eina_List *iter;
47    E_Menu_Item *mi;
48    E_DBusMenu_Item *item;
49 
50    item = e_object_data_get(E_OBJECT(m));
51    if (item)
52      {
53         e_object_data_set(E_OBJECT(m), NULL);
54         e_dbusmenu_item_unref(item);
55      }
56    EINA_LIST_FOREACH(m->items, iter, mi)
57      {
58         item = e_object_data_get(E_OBJECT(mi));
59         if (item)
60           {
61              e_object_data_set(E_OBJECT(m), NULL);
62              e_dbusmenu_item_unref(item);
63           }
64         if (mi->submenu)
65           {
66              menu_deactive(mi->submenu);
67              e_menu_deactivate(mi->submenu);
68           }
69      }
70    e_object_del(E_OBJECT(m));
71 }
72 
73 static void
menu_post_deactivate(void * data,E_Menu * m)74 menu_post_deactivate(void *data, E_Menu *m)
75 {
76    E_Gadcon *gadcon = data;
77 
78    item_deactivate(data, m);
79    e_gadcon_locked_set(gadcon, 0);
80    menu_deactive(m);
81 }
82 
83 static void
sub_item_clicked_cb(void * data,E_Menu * m EINA_UNUSED,E_Menu_Item * mi EINA_UNUSED)84 sub_item_clicked_cb(void *data, E_Menu *m EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED)
85 {
86    E_DBusMenu_Item *item = data;
87    e_dbusmenu_event_send(item, E_DBUSMENU_ITEM_EVENT_CLICKED);
88 }
89 
90 static E_Menu *
item_submenu_new(E_DBusMenu_Item * item,E_Menu_Item * mi)91 item_submenu_new(E_DBusMenu_Item *item, E_Menu_Item *mi)
92 {
93    E_Menu *m;
94    E_DBusMenu_Item *child;
95 
96    m = e_menu_new();
97    EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
98    e_dbusmenu_item_ref(item);
99    e_object_data_set(E_OBJECT(m), item);
100    if (mi) e_menu_item_submenu_set(mi, m);
101 
102    EINA_INLIST_FOREACH(item->sub_items, child)
103      {
104         E_Menu_Item *submi;
105         if (!child->visible) continue;
106         submi = e_menu_item_new(m);
107         e_dbusmenu_item_ref(child);
108         e_object_data_set(E_OBJECT(submi), child);
109         if (child->type == E_DBUSMENU_ITEM_TYPE_SEPARATOR)
110           {
111              e_menu_item_separator_set(submi, 1);
112              continue;
113           }
114         e_menu_item_label_set(submi, child->label);
115         e_menu_item_callback_set(submi, sub_item_clicked_cb, child);
116         if (!child->enabled) e_menu_item_disabled_set(submi, 1);
117         if (child->toggle_type)
118           {
119              if (child->toggle_type == E_DBUSMENU_ITEM_TOGGLE_TYPE_CHECKMARK)
120                e_menu_item_check_set(submi, 1);
121              else if (child->toggle_type == E_DBUSMENU_ITEM_TOGGLE_TYPE_RADIO)
122                e_menu_item_radio_set(submi, 1);
123              e_menu_item_toggle_set(submi, child->toggle_state);
124           }
125         if (eina_inlist_count(child->sub_items))
126           item_submenu_new(child, submi);
127         e_util_menu_item_theme_icon_set(submi, child->icon_name);
128      }
129    e_menu_pre_activate_callback_set(m, item_activate, item);
130    e_menu_post_deactivate_callback_set(m, item_deactivate, item);
131    return m;
132 }
133 
134 static Eina_Bool
item_menu_delay(void * data EINA_UNUSED)135 item_menu_delay(void *data EINA_UNUSED)
136 {
137    Evas_Coord x, y, w, h;
138    E_Zone *zone;
139 
140    x = menu_x;
141    y = menu_y;
142    w = menu_w;
143    h = menu_h;
144    zone = e_comp_zone_xy_get(x + (w / 2), y + (h / 2));
145    e_menu_activate_mouse(menu_pending, zone, x, y, w, h, menu_dir, 0);
146    menu_pending = NULL;
147    menu_timer = NULL;
148    return EINA_FALSE;
149 }
150 
151 static void
item_menu_open(E_DBusMenu_Item * item,E_Gadcon * gadcon,Evas_Coord x,Evas_Coord y,Evas_Coord w,Evas_Coord h)152 item_menu_open(E_DBusMenu_Item *item, E_Gadcon *gadcon, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
153 {
154    E_Menu *m = item_submenu_new(item, NULL);
155    int dir = E_MENU_POP_DIRECTION_AUTO;
156 
157    EINA_SAFETY_ON_NULL_RETURN(m);
158    e_gadcon_locked_set(gadcon, 1);
159    e_menu_post_deactivate_callback_set(m, menu_post_deactivate, gadcon);
160 
161    if      ((gadcon->orient == E_GADCON_ORIENT_TOP) ||
162             (gadcon->orient == E_GADCON_ORIENT_CORNER_TL) ||
163             (gadcon->orient == E_GADCON_ORIENT_CORNER_TR))
164      dir = E_MENU_POP_DIRECTION_DOWN;
165    else if ((gadcon->orient == E_GADCON_ORIENT_BOTTOM) ||
166             (gadcon->orient == E_GADCON_ORIENT_CORNER_BL) ||
167             (gadcon->orient == E_GADCON_ORIENT_CORNER_BR))
168      dir = E_MENU_POP_DIRECTION_UP;
169    else if ((gadcon->orient == E_GADCON_ORIENT_LEFT) ||
170             (gadcon->orient == E_GADCON_ORIENT_CORNER_LT) ||
171             (gadcon->orient == E_GADCON_ORIENT_CORNER_LB))
172      dir = E_MENU_POP_DIRECTION_RIGHT;
173    else if ((gadcon->orient == E_GADCON_ORIENT_RIGHT) ||
174             (gadcon->orient == E_GADCON_ORIENT_CORNER_RT) ||
175             (gadcon->orient == E_GADCON_ORIENT_CORNER_RB))
176      dir = E_MENU_POP_DIRECTION_LEFT;
177 
178    if (menu_pending) e_object_del(E_OBJECT(menu_pending));
179    menu_pending = m;
180    menu_dir = dir;
181    menu_x = x;
182    menu_y = y;
183    menu_w = w;
184    menu_h = h;
185    if (menu_timer) ecore_timer_del(menu_timer);
186    menu_timer = ecore_timer_loop_add(0.33, item_menu_delay, NULL);
187 }
188 
189 static void
clicked_toolbar_item(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj,void * event EINA_UNUSED)190 clicked_toolbar_item(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event EINA_UNUSED)
191 {
192    E_DBusMenu_Item *item = data;
193    E_Gadcon *gadcon = evas_object_data_get(obj, "gadcon");
194    Evas_Coord x, y, w, h;
195 
196    evas_object_geometry_get(obj, &x, &y, &w, &h);
197    item_menu_open(item, gadcon, x, y, w, h);
198 }
199 
200 void
appmenu_menu_of_instance_render(E_AppMenu_Instance * inst,E_AppMenu_Window * window)201 appmenu_menu_of_instance_render(E_AppMenu_Instance *inst, E_AppMenu_Window *window)
202 {
203    E_DBusMenu_Item *child;
204    Evas_Coord w, h, sum_w = 0, sum_h = 0, padding = 0;
205    Eina_List *l;
206    Evas_Object *item;
207 
208    l = evas_object_box_children_get(inst->box);
209    EINA_LIST_FREE(l, item)
210      evas_object_del(item);
211    e_gadcon_client_min_size_set(inst->gcc, 0, 0);
212 
213    if (!window || !window->root_item)
214      return;
215 
216    EINA_INLIST_FOREACH(window->root_item->sub_items, child)
217      {
218         if (!child->label)
219           continue;
220 
221         item = edje_object_add(inst->evas);
222         e_theme_edje_object_set(item, "base/themes", "e/modules/appmenu/item");
223         edje_object_part_text_set(item, "text", child->label);
224         edje_object_size_min_calc(item, &w, &h);
225 
226         if (!padding)
227           {
228              const char *padding_txt;
229              if (inst->orientation_horizontal)
230                padding_txt = edje_object_data_get(item, "padding_horizontal");
231              else
232                padding_txt = edje_object_data_get(item, "padding_vertical");
233              padding = atoi(padding_txt);
234           }
235 
236         if (inst->orientation_horizontal)
237           {
238              h = inst->gcc->gadcon->shelf->h;
239              w = w + padding;
240              sum_w = sum_w + w;
241           }
242         else
243           {
244              w = inst->gcc->gadcon->shelf->w;
245              h = h + padding;
246              sum_h = sum_h + h;
247           }
248         evas_object_resize(item, w, h);
249         evas_object_size_hint_min_set(item, w, h);
250         evas_object_box_append(inst->box, item);
251         evas_object_show(item);
252         evas_object_data_set(item, "gadcon", inst->gcc->gadcon);
253         evas_object_event_callback_add(item, EVAS_CALLBACK_MOUSE_DOWN,
254                                        clicked_toolbar_item, child);
255      }
256    e_gadcon_client_min_size_set(inst->gcc, sum_w, sum_h);
257 }
258 
259 void
appmenu_menu_render(E_AppMenu_Context * ctxt,E_AppMenu_Window * window)260 appmenu_menu_render(E_AppMenu_Context *ctxt, E_AppMenu_Window *window)
261 {
262    Eina_List *list;
263    E_AppMenu_Instance *inst;
264 
265    appmenu_cancel();
266 
267    ctxt->window = window;
268 
269    EINA_LIST_FOREACH(ctxt->instances, list, inst)
270      appmenu_menu_of_instance_render(inst, window);
271 }
272