1 #include "e.h"
2 
3 /* TODO List:
4  *
5  * * support change of menu items after realize
6  * * support add/del of menu items after realize
7  * * support text/color classes
8  * * refcount menu up while looping thru and calling other fn's
9  * * support alignment (x, y) as well as spawn direction
10  * * need different menu style support for different menus
11  * * add menu icon/title support
12  * * use event timestamps not clock for "click and release" detect
13  * * menu icons can set if/how they will be scaled
14  * * support move/resize of "box" that spawned the menu
15  * * add image item (label is replaced by image/icon)
16  * * add generic evas object item type (label replaced by object)
17  * * allow menus to stretch width/height to fit spawner widget/box
18  * * allow menus to auto-shrink (horizontally) if forced to
19  * * support auto left/right direction spawn
20  * * support obscures to indicate offscreen/not visible menu parts
21  */
22 
23 /* local subsystem data types */
24 typedef struct _E_Menu_Category E_Menu_Category;
25 
26 struct _E_Menu_Category
27 {
28    void      *data;
29    Eina_List *callbacks;
30 };
31 
32 /* local subsystem functions */
33 static void         _e_menu_free(E_Menu *m);
34 static void         _e_menu_item_free(E_Menu_Item *mi);
35 static void         _e_menu_item_realize(E_Menu_Item *mi);
36 static void         _e_menu_realize(E_Menu *m);
37 static void         _e_menu_items_layout_update(E_Menu *m);
38 static void         _e_menu_item_unrealize(E_Menu_Item *mi);
39 static void         _e_menu_unrealize(E_Menu *m);
40 static void         _e_menu_activate_internal(E_Menu *m, E_Zone *zone);
41 static void         _e_menu_deactivate_all(void);
42 static void         _e_menu_deactivate_above(E_Menu *m);
43 static void         _e_menu_submenu_activate(E_Menu_Item *mi);
44 static void         _e_menu_submenu_deactivate(E_Menu_Item *mi);
45 static void         _e_menu_reposition(E_Menu *m);
46 static int          _e_menu_active_call(void);
47 static int          _e_menu_realize_call(E_Menu_Item *mi);
48 static void         _e_menu_item_activate_next(void);
49 static void         _e_menu_item_activate_previous(void);
50 static void         _e_menu_item_activate_first(void);
51 static void         _e_menu_item_activate_last(void);
52 static void         _e_menu_item_activate_nth(int n);
53 static void         _e_menu_item_activate_char(const char *key_compose);
54 static void         _e_menu_activate_next(void);
55 static void         _e_menu_activate_previous(void);
56 static void         _e_menu_activate_first(void);
57 static void         _e_menu_activate_last(void);
58 #if 0
59 static void         _e_menu_activate_nth(int n);
60 #endif
61 static E_Menu      *_e_menu_active_get(void);
62 static E_Menu_Item *_e_menu_item_active_get(void);
63 static Eina_List   *_e_menu_list_item_active_get(void);
64 static int          _e_menu_outside_bounds_get(int xdir, int ydir);
65 static void         _e_menu_scroll_by(int dx, int dy);
66 static void         _e_menu_mouse_autoscroll_check(void);
67 static void         _e_menu_item_ensure_onscreen(E_Menu_Item *mi);
68 static int          _e_menu_auto_place(E_Menu *m, int x, int y, int w, int h);
69 static void         _e_menu_cb_intercept_item_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y);
70 static void         _e_menu_cb_intercept_item_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h);
71 static void         _e_menu_cb_intercept_container_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y);
72 static void         _e_menu_cb_intercept_container_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h);
73 static void         _e_menu_cb_item_in(void *data, Evas *evas, Evas_Object *obj, void *event_info);
74 static void         _e_menu_cb_item_out(void *data, Evas *evas, Evas_Object *obj, void *event_info);
75 static Eina_Bool    _e_menu_cb_key_down(void *data EINA_UNUSED, Ecore_Event_Key *ev);
76 static Eina_Bool    _e_menu_cb_mouse_down(void *data, int type, void *event);
77 static Eina_Bool    _e_menu_cb_mouse_up(void *data, int type, void *event);
78 static Eina_Bool    _e_menu_cb_mouse_move(void *data, int type, void *event);
79 static Eina_Bool    _e_menu_cb_mouse_wheel(void *data, int type, void *event);
80 static Eina_Bool    _e_menu_cb_scroll_animator(void *data);
81 static void         _e_menu_cb_item_submenu_post_default(void *data, E_Menu *m, E_Menu_Item *mi);
82 static void         _e_menu_category_free_cb(E_Menu_Category *cat);
83 static void         _e_menu_cb_mouse_evas_down(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED);
84 static void         _e_menu_hide_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED);
85 
86 typedef enum
87 {
88    NAV_BY_NONE,
89    NAV_BY_MOUSE,
90    NAV_BY_WHEEL,
91    NAV_BY_KEY
92 } Nav_By;
93 
94 /* local subsystem globals */
95 static Ecore_Window _e_menu_win = UINT_MAX;
96 static Eina_Bool _e_menu_grabbed = EINA_FALSE;
97 static Eina_List *_e_active_menus = NULL;
98 static E_Menu_Item *_e_active_menu_item = NULL;
99 static E_Menu_Item *_e_prev_active_menu_item = NULL;
100 /*static Eina_Hash	   *_e_menu_category_items	= NULL;*/
101 static Eina_Hash *_e_menu_categories = NULL;
102 static unsigned int _e_menu_activate_time = 0;
103 static int _e_menu_activate_floating = 0;
104 static int _e_menu_activate_maybe_drag = 0;
105 static int _e_menu_activate_dragging = 0;
106 static Ecore_Animator *_e_menu_scroll_animator = NULL;
107 static double _e_menu_scroll_start = 0.0;
108 static int _e_menu_x = 0;
109 static int _e_menu_y = 0;
110 static unsigned int _e_menu_time = 0;
111 static int _e_menu_autoscroll_x = 0;
112 static int _e_menu_autoscroll_y = 0;
113 static Eina_List *handlers = NULL;
114 static Eina_Bool _e_menu_lock = EINA_FALSE;
115 static Nav_By _e_menu_nav_by = NAV_BY_NONE;
116 
117 static Eina_Bool pending_feed;
118 static unsigned int pending_activate_time;
119 
120 static Eina_List *
_e_active_menus_copy_ref(void)121 _e_active_menus_copy_ref(void)
122 {
123    E_Object *o;
124    Eina_List *l, *ret = NULL;
125 
126    EINA_LIST_FOREACH(_e_active_menus, l, o)
127      {
128         ret = eina_list_append(ret, o);
129         e_object_ref(o);
130      }
131    return ret;
132 }
133 
134 static Eina_List *
_e_menu_list_free_unref(Eina_List * l)135 _e_menu_list_free_unref(Eina_List *l)
136 {
137    E_Object *o;
138    Eina_List *ll, *lll;
139 
140    /* list must be freed in reverse to ensure that submenus
141     * (which are added to the end of the list)
142     * are deleted before their parents
143     */
144    EINA_LIST_REVERSE_FOREACH_SAFE(l, ll, lll, o)
145    {
146       e_object_unref(o);
147       l = eina_list_remove_list(l, ll);
148    }
149    return l;
150 }
151 
152 /* macros for debugging menu refcounts */
153 #if 0
154 #define e_object_ref(X)   do {      \
155        int xx;                      \
156        xx = e_object_ref(X);        \
157        INF("REF: %p || %d", X, xx); \
158   } while (0)
159 #define e_object_unref(X) do {        \
160        int xx;                        \
161        xx = e_object_unref(X);        \
162        INF("UNREF: %p || %d", X, xx); \
163   } while (0)
164 #endif
165 
166 /* externally accessible functions */
167 EINTERN int
e_menu_init(void)168 e_menu_init(void)
169 {
170    E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_menu_cb_mouse_down, NULL);
171    E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_UP, _e_menu_cb_mouse_up, NULL);
172    E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_MOVE, _e_menu_cb_mouse_move, NULL);
173    E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_WHEEL, _e_menu_cb_mouse_wheel, NULL);
174    _e_menu_categories = eina_hash_string_superfast_new((Eina_Free_Cb)_e_menu_category_free_cb);
175 
176    e_int_menus_init();
177    return 1;
178 }
179 
180 EINTERN int
e_menu_shutdown(void)181 e_menu_shutdown(void)
182 {
183    E_FREE_LIST(handlers, ecore_event_handler_del);
184 
185    if (!x_fatal)
186      e_menu_hide_all();
187    _e_active_menus = NULL;
188    E_FREE_FUNC(_e_menu_categories, eina_hash_free);
189 
190    _e_menu_lock = EINA_FALSE;
191    e_int_menus_shutdown();
192 
193    return 1;
194 }
195 
196 E_API void
e_menu_hide_all(void)197 e_menu_hide_all(void)
198 {
199    E_Menu *m;
200 
201    EINA_LIST_FREE(_e_active_menus, m)
202      {
203         if (m->post_deactivate_cb.func)
204           m->post_deactivate_cb.func(m->post_deactivate_cb.data, m);
205         m->active = 0;
206         if (m->comp_object == e_comp->autoclose.obj)
207           e_comp_object_util_autoclose(NULL, NULL, NULL, NULL);
208         _e_menu_unrealize(m);
209         m->in_active_list = 0;
210         e_object_unref(E_OBJECT(m));
211      }
212    if (_e_menu_grabbed)
213      {
214         e_comp_ungrab_input(1, 1);
215         _e_menu_grabbed = EINA_FALSE;
216      }
217 }
218 
219 E_API E_Menu *
e_menu_new(void)220 e_menu_new(void)
221 {
222    E_Menu *m;
223 
224    m = E_OBJECT_ALLOC(E_Menu, E_MENU_TYPE, _e_menu_free);
225    if (!m) return NULL;
226    m->cur.w = 1;
227    m->cur.h = 1;
228    m->category = NULL;
229    m->hold_mode = EINA_TRUE;
230    return m;
231 }
232 
233 E_API void
e_menu_hold_mode_set(E_Menu * m,Eina_Bool hold_mode)234 e_menu_hold_mode_set(E_Menu *m, Eina_Bool hold_mode)
235 {
236    E_OBJECT_CHECK(m);
237    E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
238    m->hold_mode = hold_mode;
239 }
240 
241 E_API void
e_menu_activate_key(E_Menu * m,E_Zone * zone,int x,int y,int w,int h,int dir)242 e_menu_activate_key(E_Menu *m, E_Zone *zone, int x, int y, int w, int h, int dir)
243 {
244    E_OBJECT_CHECK(m);
245    E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
246    E_OBJECT_CHECK(zone);
247    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
248    if (_e_active_menus) e_menu_hide_all();
249    _e_menu_activate_time = 0;
250    _e_menu_activate_floating = 0;
251    _e_menu_activate_internal(m, zone);
252    if (!m->zone)
253      {
254         e_menu_deactivate(m);
255         return;
256      }
257    _e_menu_nav_by = NAV_BY_KEY;
258    switch (dir)
259      {
260       case E_MENU_POP_DIRECTION_LEFT:
261         _e_menu_realize(m);
262         m->cur.x = x - m->cur.w;
263         m->cur.y = y;
264         if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
265           m->cur.y = y + h - m->cur.h;
266         _e_menu_activate_first();
267         break;
268 
269       case E_MENU_POP_DIRECTION_RIGHT:
270         _e_menu_realize(m);
271         m->cur.x = x + w;
272         m->cur.y = y;
273         _e_menu_activate_first();
274         break;
275 
276       case E_MENU_POP_DIRECTION_UP:
277         _e_menu_realize(m);
278         m->cur.x = x;
279         if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
280           m->cur.x = x + w - m->cur.w;
281         m->cur.y = y - m->cur.h;
282         _e_menu_activate_last();
283         break;
284 
285       case E_MENU_POP_DIRECTION_DOWN:
286         _e_menu_realize(m);
287         m->cur.x = x;
288         if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
289           m->cur.x = x + w - m->cur.w;
290         m->cur.y = y + h;
291         if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
292           m->cur.y = y + h - m->cur.h;
293         _e_menu_activate_first();
294         break;
295 
296       case E_MENU_POP_DIRECTION_AUTO:
297       {
298          int pos = 0;
299 
300          pos = _e_menu_auto_place(m, x, y, w, h);
301          if (pos == 4)
302            _e_menu_activate_last();
303          else
304            _e_menu_activate_first();
305       }
306       break;
307 
308       default:
309         m->cur.x = x + w;
310         m->cur.y = y + h;
311         _e_menu_activate_first();
312         break;
313      }
314 }
315 
316 E_API void
e_menu_activate_mouse(E_Menu * m,E_Zone * zone,int x,int y,int w,int h,int dir,unsigned int activate_time)317 e_menu_activate_mouse(E_Menu *m, E_Zone *zone, int x, int y, int w, int h, int dir, unsigned int activate_time)
318 {
319    E_Menu_Item *pmi;
320 
321    E_OBJECT_CHECK(m);
322    E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
323    E_OBJECT_CHECK(zone);
324    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
325 
326    e_object_ref(E_OBJECT(m));
327    e_menu_hide_all();
328    _e_menu_activate_time = 0;
329    _e_menu_activate_floating = 0;
330    _e_menu_activate_internal(m, zone);
331    if (!m->zone)
332      {
333         e_menu_deactivate(m);
334         e_object_unref(E_OBJECT(m));
335         return;
336      }
337    _e_menu_nav_by = NAV_BY_MOUSE;
338    switch (dir)
339      {
340       case E_MENU_POP_DIRECTION_LEFT:
341         _e_menu_realize(m);
342         m->cur.x = x - m->cur.w;
343         m->cur.y = y;
344         if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
345           m->cur.y = y + h - m->cur.h;
346         break;
347 
348       case E_MENU_POP_DIRECTION_RIGHT:
349         _e_menu_realize(m);
350         m->cur.x = x + w;
351         m->cur.y = y;
352         break;
353 
354       case E_MENU_POP_DIRECTION_UP:
355         _e_menu_realize(m);
356         m->cur.x = x;
357         if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
358           m->cur.x = x + w - m->cur.w;
359         m->cur.y = y - m->cur.h;
360         break;
361 
362       case E_MENU_POP_DIRECTION_DOWN:
363         _e_menu_realize(m);
364         m->cur.x = x;
365         if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
366           m->cur.x = x + w - m->cur.w;
367         m->cur.y = y + h;
368         if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
369           m->cur.y = y + h - m->cur.h;
370         break;
371 
372       case E_MENU_POP_DIRECTION_AUTO:
373         _e_menu_auto_place(m, x, y, w, h);
374         break;
375 
376       default:
377         m->cur.x = x + w;
378         m->cur.y = y + h;
379         break;
380      }
381    pmi = _e_menu_item_active_get();
382    if (pmi) e_menu_item_active_set(pmi, 0);
383    pending_feed = 1;
384    if (!activate_time) activate_time = lround(ecore_loop_time_get() * 1000);
385    _e_menu_activate_time = pending_activate_time = activate_time;
386    e_object_unref(E_OBJECT(m));
387 }
388 
389 E_API void
e_menu_activate(E_Menu * m,E_Zone * zone,int x,int y,int w,int h,int dir)390 e_menu_activate(E_Menu *m, E_Zone *zone, int x, int y, int w, int h, int dir)
391 {
392    E_Menu_Item *pmi;
393 
394    E_OBJECT_CHECK(m);
395    E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
396    E_OBJECT_CHECK(zone);
397    E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
398    if (_e_active_menus) e_menu_hide_all();
399    _e_menu_activate_time = 0;
400    _e_menu_activate_floating = 0;
401    _e_menu_activate_internal(m, zone);
402    if (!m->zone)
403      {
404         e_menu_deactivate(m);
405         return;
406      }
407    _e_menu_nav_by = NAV_BY_NONE;
408    switch (dir)
409      {
410       case E_MENU_POP_DIRECTION_LEFT:
411         _e_menu_realize(m);
412         m->cur.x = x - m->cur.w;
413         m->cur.y = y;
414         if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
415           m->cur.y = y + h - m->cur.h;
416         _e_menu_activate_first();
417         break;
418 
419       case E_MENU_POP_DIRECTION_RIGHT:
420         _e_menu_realize(m);
421         m->cur.x = x + w;
422         m->cur.y = y;
423         _e_menu_activate_first();
424         break;
425 
426       case E_MENU_POP_DIRECTION_UP:
427         _e_menu_realize(m);
428         m->cur.x = x;
429         if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
430           m->cur.x = x + w - m->cur.w;
431         m->cur.y = y - m->cur.h;
432         _e_menu_activate_last();
433         break;
434 
435       case E_MENU_POP_DIRECTION_DOWN:
436         _e_menu_realize(m);
437         m->cur.x = x;
438         if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
439           m->cur.x = x + w - m->cur.w;
440         m->cur.y = y + h;
441         if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
442           m->cur.y = y + h - m->cur.h;
443         _e_menu_activate_first();
444         break;
445 
446       case E_MENU_POP_DIRECTION_AUTO:
447         _e_menu_auto_place(m, x, y, w, h);
448         break;
449 
450       default:
451         m->cur.x = x + w;
452         m->cur.y = y + h;
453         break;
454      }
455    pmi = _e_menu_item_active_get();
456    if (pmi) e_menu_item_active_set(pmi, 0);
457 }
458 
459 E_API void
e_menu_deactivate(E_Menu * m)460 e_menu_deactivate(E_Menu *m)
461 {
462    Eina_List *l;
463    E_Menu_Item *mi;
464 
465    E_OBJECT_CHECK(m);
466    E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
467    if (!m->active) return;
468 
469    EINA_LIST_FOREACH(m->items, l, mi)
470      {
471         if (mi->submenu) e_menu_deactivate(mi->submenu);
472      }
473 
474    m->cur.visible = 0;
475    m->active = 0;
476    if (m->post_deactivate_cb.func)
477      m->post_deactivate_cb.func(m->post_deactivate_cb.data, m);
478 }
479 
480 E_API int
e_menu_freeze(E_Menu * m)481 e_menu_freeze(E_Menu *m)
482 {
483    E_OBJECT_CHECK_RETURN(m, 0);
484    E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, 0);
485    m->frozen++;
486    return m->frozen;
487 }
488 
489 E_API int
e_menu_thaw(E_Menu * m)490 e_menu_thaw(E_Menu *m)
491 {
492    E_OBJECT_CHECK_RETURN(m, 0);
493    E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, 0);
494    m->frozen--;
495    if (m->frozen < 0) m->frozen = 0;
496    return m->frozen;
497 }
498 
499 E_API void
e_menu_title_set(E_Menu * m,const char * title)500 e_menu_title_set(E_Menu *m, const char *title)
501 {
502    E_OBJECT_CHECK(m);
503    E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
504    if ((m->header.title) && (title) && (!strcmp(m->header.title, title)))
505      return;
506    if (m->header.title)
507      {
508         eina_stringshare_del(m->header.title);
509         m->header.title = NULL;
510      }
511    if (title) m->header.title = eina_stringshare_add(title);
512    else m->header.title = NULL;
513    m->changed = 1;
514    if (!m->realized) return;
515    edje_object_part_text_set(m->bg_object, "e.text.title", m->header.title);
516    if (m->header.title)
517      edje_object_signal_emit(m->bg_object, "e,action,show,title", "e");
518    else
519      edje_object_signal_emit(m->bg_object, "e,action,hide,title", "e");
520    edje_object_message_signal_process(m->bg_object);
521 }
522 
523 E_API void
e_menu_icon_file_set(E_Menu * m EINA_UNUSED,const char * icon EINA_UNUSED)524 e_menu_icon_file_set(E_Menu *m EINA_UNUSED, const char *icon EINA_UNUSED)
525 {
526    /* FIXME: support menu icons
527       E_OBJECT_CHECK(m);
528       E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
529     */
530 }
531 
532 E_API void
e_menu_category_set(E_Menu * m,const char * category)533 e_menu_category_set(E_Menu *m, const char *category)
534 {
535    E_OBJECT_CHECK(m);
536    E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
537    if (m->category)
538      {
539         eina_stringshare_del(m->category);
540         m->category = NULL;
541      }
542    if (category)
543      m->category = eina_stringshare_add(category);
544    else
545      m->category = NULL;
546    m->changed = 1;
547 }
548 
549 E_API void
e_menu_category_data_set(char * category,void * data)550 e_menu_category_data_set(char *category, void *data)
551 {
552    E_Menu_Category *cat;
553 
554    cat = eina_hash_find(_e_menu_categories, category);
555    if (cat)
556      cat->data = data;
557    else   /* if it isn't found create the new hash */
558      {
559         cat = calloc(1, sizeof(E_Menu_Category));
560         cat->data = data;
561         eina_hash_add(_e_menu_categories, category, cat);
562      }
563 }
564 
565 E_API E_Menu_Category_Callback *
e_menu_category_callback_add(char * category,void (* create_cb)(void * data,E_Menu * m,void * category_data),Ecore_Cb free_cb,void * data)566 e_menu_category_callback_add(char *category, void (*create_cb)(void *data, E_Menu *m, void *category_data), Ecore_Cb free_cb, void *data)
567 {
568    E_Menu_Category *cat;
569    E_Menu_Category_Callback *cb = NULL;
570 
571    cat = eina_hash_find(_e_menu_categories, category);
572    if (!cat)   /* if it isn't found create the new hash */
573      {
574         cat = calloc(1, sizeof(E_Menu_Category));
575         eina_hash_add(_e_menu_categories, category, cat);
576      }
577    if (cat)
578      {
579         cb = calloc(1, sizeof(E_Menu_Category_Callback));
580         if (cb)
581           {
582              cb->data = data;
583              cb->create = create_cb;
584              cb->free = free_cb;
585              cb->category = eina_stringshare_add(category);
586              cat->callbacks = eina_list_append(cat->callbacks, cb);
587           }
588      }
589    return cb;
590 }
591 
592 E_API void
e_menu_category_callback_del(E_Menu_Category_Callback * cb)593 e_menu_category_callback_del(E_Menu_Category_Callback *cb)
594 {
595    E_Menu_Category *cat;
596 
597    if (cb)
598      {
599         cat = eina_hash_find(_e_menu_categories, cb->category);
600         if (cat)
601           cat->callbacks = eina_list_remove(cat->callbacks, cb);
602         eina_stringshare_del(cb->category);
603         free(cb);
604      }
605 }
606 
607 E_API void
e_menu_pre_activate_callback_set(E_Menu * m,void (* func)(void * data,E_Menu * m),void * data)608 e_menu_pre_activate_callback_set(E_Menu *m, void (*func)(void *data, E_Menu *m), void *data)
609 {
610    E_OBJECT_CHECK(m);
611    E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
612    m->pre_activate_cb.func = func;
613    m->pre_activate_cb.data = data;
614 }
615 
616 E_API void
e_menu_post_deactivate_callback_set(E_Menu * m,void (* func)(void * data,E_Menu * m),void * data)617 e_menu_post_deactivate_callback_set(E_Menu *m, void (*func)(void *data, E_Menu *m), void *data)
618 {
619    E_OBJECT_CHECK(m);
620    E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
621    m->post_deactivate_cb.func = func;
622    m->post_deactivate_cb.data = data;
623 }
624 
625 E_API E_Menu *
e_menu_root_get(E_Menu * m)626 e_menu_root_get(E_Menu *m)
627 {
628    E_Menu *ret;
629 
630    E_OBJECT_CHECK_RETURN(m, NULL);
631    E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
632    ret = m;
633    while ((ret->parent_item) && (ret->parent_item->menu))
634      ret = ret->parent_item->menu;
635 
636    return ret;
637 }
638 
639 E_API E_Menu_Item *
e_menu_item_new(E_Menu * m)640 e_menu_item_new(E_Menu *m)
641 {
642    E_Menu_Item *mi;
643 
644    E_OBJECT_CHECK_RETURN(m, NULL);
645    E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
646    mi = E_OBJECT_ALLOC(E_Menu_Item, E_MENU_ITEM_TYPE, _e_menu_item_free);
647    mi->menu = m;
648    mi->menu->items = eina_list_append(mi->menu->items, mi);
649    mi->list_position = eina_list_last(mi->menu->items);
650    return mi;
651 }
652 
653 E_API E_Menu_Item *
e_menu_item_new_relative(E_Menu * m,E_Menu_Item * rel)654 e_menu_item_new_relative(E_Menu *m, E_Menu_Item *rel)
655 {
656    E_Menu_Item *mi;
657    E_OBJECT_CHECK_RETURN(m, NULL);
658    E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
659    if (rel)
660      {
661         E_OBJECT_CHECK_RETURN(rel, NULL);
662         E_OBJECT_TYPE_CHECK_RETURN(rel, E_MENU_ITEM_TYPE, NULL);
663         if (rel->menu != m) return NULL;
664      }
665 
666    mi = E_OBJECT_ALLOC(E_Menu_Item, E_MENU_ITEM_TYPE, _e_menu_item_free);
667    mi->menu = m;
668 
669    if (rel)
670      {
671         Eina_List *l;
672 
673         l = eina_list_data_find_list(m->items, rel);
674         m->items = eina_list_append_relative_list(m->items, mi, l);
675         mi->list_position = l->next;
676      }
677    else
678      {
679         m->items = eina_list_prepend(m->items, mi);
680         mi->list_position = m->items;
681      }
682 
683    return mi;
684 }
685 
686 E_API E_Menu_Item *
e_menu_item_nth(E_Menu * m,int n)687 e_menu_item_nth(E_Menu *m, int n)
688 {
689    E_OBJECT_CHECK_RETURN(m, NULL);
690    E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
691    return (E_Menu_Item *)eina_list_nth(m->items, n);
692 }
693 
694 E_API int
e_menu_item_num_get(const E_Menu_Item * mi)695 e_menu_item_num_get(const E_Menu_Item *mi)
696 {
697    const Eina_List *l;
698    const E_Menu_Item *mi2;
699    int i = 0;
700 
701    E_OBJECT_CHECK_RETURN(mi, -1);
702    E_OBJECT_CHECK_RETURN(mi->menu, -1);
703    E_OBJECT_TYPE_CHECK_RETURN(mi, E_MENU_TYPE, -1);
704    EINA_LIST_FOREACH(mi->menu->items, l, mi2)
705      {
706         if (mi2 == mi) return i;
707         i++;
708      }
709    return -1;
710 }
711 
712 E_API void
e_menu_item_icon_file_set(E_Menu_Item * mi,const char * icon)713 e_menu_item_icon_file_set(E_Menu_Item *mi, const char *icon)
714 {
715    E_OBJECT_CHECK(mi);
716    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
717    if (((mi->icon) && (icon) && (!strcmp(icon, mi->icon))) ||
718        ((!mi->icon) && (!icon)))
719      return;
720    if (mi->icon) eina_stringshare_del(mi->icon);
721    if (mi->icon_key) eina_stringshare_del(mi->icon_key);
722    mi->icon = NULL;
723    mi->icon_key = NULL;
724    if (icon)
725      {
726         mi->icon = eina_stringshare_add(icon);
727         if (eina_str_has_extension(mi->icon, ".edj"))
728           mi->icon_key = eina_stringshare_add("icon");
729      }
730    mi->changed = 1;
731    mi->menu->changed = 1;
732 }
733 
734 E_API void
e_menu_item_icon_edje_set(E_Menu_Item * mi,const char * icon,const char * key)735 e_menu_item_icon_edje_set(E_Menu_Item *mi, const char *icon, const char *key)
736 {
737    E_OBJECT_CHECK(mi);
738    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
739    if (((mi->icon) && (icon) && (!strcmp(icon, mi->icon))) ||
740        ((!mi->icon) && (!icon)) ||
741        ((key) && (mi->icon_key) && (!strcmp(key, mi->icon_key))))
742      return;
743    eina_stringshare_replace(&mi->icon, icon);
744    eina_stringshare_replace(&mi->icon_key, key);
745    mi->changed = 1;
746    mi->menu->changed = 1;
747 }
748 
749 E_API void
e_menu_item_label_set(E_Menu_Item * mi,const char * label)750 e_menu_item_label_set(E_Menu_Item *mi, const char *label)
751 {
752    E_OBJECT_CHECK(mi);
753    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
754    if (((mi->label) && (label) && (!strcmp(label, mi->label))) ||
755        ((!mi->label) && (!label)))
756      return;
757    if (mi->label) eina_stringshare_del(mi->label);
758    mi->label = NULL;
759    if (label) mi->label = eina_stringshare_add(label);
760    mi->changed = 1;
761    mi->menu->changed = 1;
762 }
763 
764 E_API void
e_menu_item_submenu_set(E_Menu_Item * mi,E_Menu * sub)765 e_menu_item_submenu_set(E_Menu_Item *mi, E_Menu *sub)
766 {
767    Eina_Bool submenu = EINA_FALSE;
768    Evas_Object *o;
769    Eina_List *tmp = NULL;
770    int ww, hh;
771    E_OBJECT_CHECK(mi);
772    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
773 
774    if (mi->submenu == sub) return;
775    tmp = _e_active_menus_copy_ref();
776    submenu = !!mi->submenu;
777    if (mi->submenu) e_object_unref(E_OBJECT(mi->submenu));
778    if (sub) e_object_ref(E_OBJECT(sub));
779    mi->submenu = sub;
780    mi->changed = 1;
781    mi->menu->changed = 1;
782    if (!!sub == submenu) goto out;
783    if (!mi->bg_object) goto out;
784    if (sub) e_object_ref(E_OBJECT(sub));
785    _e_menu_lock = EINA_TRUE;
786    if ((mi->submenu) || (mi->submenu_pre_cb.func))
787      {
788         if (mi->submenu_object)
789           {
790              if (isedje(mi->submenu_object))
791                {
792                   /* already have a correct submenu object, don't re-set it */
793                   _e_menu_lock = EINA_FALSE;
794                   if (sub) e_object_unref(E_OBJECT(sub));
795                   edje_object_size_min_calc(mi->submenu_object, &ww, &hh);
796                   mi->submenu_w = ww;
797                   mi->submenu_h = hh;
798                   E_WEIGHT(mi->submenu_object, 0, 1);
799                   E_FILL(mi->submenu_object);
800                   evas_object_size_hint_min_set(mi->submenu_object, ww, hh);
801                   goto out;
802                }
803              evas_object_del(mi->submenu_object);
804           }
805         o = edje_object_add(mi->menu->evas);
806         if (sub && (mi->submenu != sub)) e_object_ref(E_OBJECT(sub));
807         mi->submenu = sub;
808         mi->submenu_object = o;
809         e_theme_edje_object_set(o, "base/theme/menus",
810                                 "e/widgets/menu/default/submenu");
811         evas_object_pass_events_set(o, 1);
812         elm_box_pack_end(mi->container_object, o);
813         evas_object_show(o);
814         edje_object_size_min_calc(mi->submenu_object, &ww, &hh);
815         mi->submenu_w = ww;
816         mi->submenu_h = hh;
817         E_WEIGHT(mi->submenu_object, 0, 1);
818         E_FILL(mi->submenu_object);
819         evas_object_size_hint_min_set(mi->submenu_object, ww, hh);
820         edje_object_part_swallow(mi->bg_object, "e.swallow.content",
821                                  mi->container_object);
822         edje_object_size_min_calc(mi->bg_object, &ww, &hh);
823         E_WEIGHT(mi->bg_object, 1, 0);
824         E_FILL(mi->bg_object);
825         evas_object_size_hint_min_set(mi->bg_object, ww, hh);
826      }
827    else
828      {
829         if (mi->submenu_object) evas_object_del(mi->submenu_object);
830         o = evas_object_rectangle_add(mi->menu->evas);
831         mi->submenu_object = o;
832         evas_object_color_set(o, 0, 0, 0, 0);
833         evas_object_pass_events_set(o, 1);
834         elm_box_pack_end(mi->container_object, o);
835      }
836    _e_menu_lock = EINA_FALSE;
837    if (sub) e_object_unref(E_OBJECT(sub));
838    if ((mi->submenu) || (mi->submenu_pre_cb.func))
839      {
840         if (e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
841                                     "e/widgets/menu/default/submenu_bg"))
842           goto out;
843      }
844 
845    e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
846                            "e/widgets/menu/default/item_bg");
847 out:
848    _e_menu_list_free_unref(tmp);
849 }
850 
851 E_API void
e_menu_item_separator_set(E_Menu_Item * mi,int sep)852 e_menu_item_separator_set(E_Menu_Item *mi, int sep)
853 {
854    E_OBJECT_CHECK(mi);
855    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
856    if (((mi->separator) && (sep)) || ((!mi->separator) && (!sep))) return;
857    mi->separator = sep;
858    mi->changed = 1;
859    mi->menu->changed = 1;
860 }
861 
862 E_API void
e_menu_item_check_set(E_Menu_Item * mi,int chk)863 e_menu_item_check_set(E_Menu_Item *mi, int chk)
864 {
865    E_OBJECT_CHECK(mi);
866    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
867    if (((mi->check) && (chk)) || ((!mi->check) && (!chk))) return;
868    mi->check = chk;
869    mi->changed = 1;
870    mi->menu->changed = 1;
871 }
872 
873 E_API void
e_menu_item_radio_set(E_Menu_Item * mi,int rad)874 e_menu_item_radio_set(E_Menu_Item *mi, int rad)
875 {
876    E_OBJECT_CHECK(mi);
877    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
878    if (((mi->radio) && (rad)) || ((!mi->radio) && (!rad))) return;
879    mi->radio = rad;
880    mi->changed = 1;
881    mi->menu->changed = 1;
882 }
883 
884 E_API void
e_menu_item_radio_group_set(E_Menu_Item * mi,int radg)885 e_menu_item_radio_group_set(E_Menu_Item *mi, int radg)
886 {
887    E_OBJECT_CHECK(mi);
888    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
889    if (mi->radio_group == radg) return;
890    mi->radio_group = radg;
891    mi->changed = 1;
892    mi->menu->changed = 1;
893 }
894 
895 E_API void
e_menu_item_toggle_set(E_Menu_Item * mi,int tog)896 e_menu_item_toggle_set(E_Menu_Item *mi, int tog)
897 {
898    E_OBJECT_CHECK(mi);
899    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
900    if (mi->separator) return;
901    if (tog)
902      {
903         mi->toggle = 1;
904         if (mi->bg_object)
905           edje_object_signal_emit(mi->bg_object, "e,state,on", "e");
906         if (mi->icon_bg_object)
907           edje_object_signal_emit(mi->icon_bg_object, "e,state,on", "e");
908         if (isedje(mi->label_object))
909           edje_object_signal_emit(mi->label_object, "e,state,on", "e");
910         if (isedje(mi->submenu_object))
911           edje_object_signal_emit(mi->submenu_object, "e,state,on", "e");
912         if (isedje(mi->toggle_object))
913           edje_object_signal_emit(mi->toggle_object, "e,state,on", "e");
914         if (mi->menu->bg_object)
915           edje_object_signal_emit(mi->menu->bg_object, "e,state,on", "e");
916      }
917    else
918      {
919         mi->toggle = 0;
920         if (mi->bg_object)
921           edje_object_signal_emit(mi->bg_object, "e,state,off", "e");
922         if (mi->icon_bg_object)
923           edje_object_signal_emit(mi->icon_bg_object, "e,state,off", "e");
924         if (isedje(mi->label_object))
925           edje_object_signal_emit(mi->label_object, "e,state,off", "e");
926         if (isedje(mi->submenu_object))
927           edje_object_signal_emit(mi->submenu_object, "e,state,off", "e");
928         if (isedje(mi->toggle_object))
929           edje_object_signal_emit(mi->toggle_object, "e,state,off", "e");
930         if (mi->menu->bg_object)
931           edje_object_signal_emit(mi->menu->bg_object, "e,state,off", "e");
932      }
933    if (tog)
934      {
935         if (mi->radio)
936           {
937              const Eina_List *l;
938              E_Menu_Item *mi2;
939 
940              EINA_LIST_FOREACH(mi->menu->items, l, mi2)
941                {
942                   if ((mi2 != mi) && (mi2->radio) &&
943                       (mi2->radio_group == mi->radio_group))
944                     e_menu_item_toggle_set(mi2, 0);
945                }
946           }
947      }
948 }
949 
950 E_API int
e_menu_item_toggle_get(E_Menu_Item * mi)951 e_menu_item_toggle_get(E_Menu_Item *mi)
952 {
953    E_OBJECT_CHECK_RETURN(mi, 0);
954    E_OBJECT_TYPE_CHECK_RETURN(mi, E_MENU_ITEM_TYPE, 0);
955    return mi->toggle;
956 }
957 
958 E_API void
e_menu_item_callback_set(E_Menu_Item * mi,void (* func)(void * data,E_Menu * m,E_Menu_Item * mi),const void * data)959 e_menu_item_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), const void *data)
960 {
961    E_OBJECT_CHECK(mi);
962    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
963    mi->cb.func = func;
964    mi->cb.data = (void *)data;
965 }
966 
967 E_API void
e_menu_item_realize_callback_set(E_Menu_Item * mi,void (* func)(void * data,E_Menu * m,E_Menu_Item * mi),void * data)968 e_menu_item_realize_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), void *data)
969 {
970    E_OBJECT_CHECK(mi);
971    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
972    mi->realize_cb.func = func;
973    mi->realize_cb.data = data;
974 }
975 
976 E_API void
e_menu_item_submenu_pre_callback_set(E_Menu_Item * mi,void (* func)(void * data,E_Menu * m,E_Menu_Item * mi),const void * data)977 e_menu_item_submenu_pre_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), const void *data)
978 {
979    E_OBJECT_CHECK(mi);
980    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
981    mi->submenu_pre_cb.func = func;
982    mi->submenu_pre_cb.data = (void *)data;
983    if (!mi->submenu_post_cb.func)
984      mi->submenu_post_cb.func = _e_menu_cb_item_submenu_post_default;
985 }
986 
987 E_API void
e_menu_item_submenu_post_callback_set(E_Menu_Item * mi,void (* func)(void * data,E_Menu * m,E_Menu_Item * mi),const void * data)988 e_menu_item_submenu_post_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), const void *data)
989 {
990    E_OBJECT_CHECK(mi);
991    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
992    mi->submenu_post_cb.func = func;
993    mi->submenu_post_cb.data = (void *)data;
994 }
995 
996 E_API void
e_menu_item_drag_callback_set(E_Menu_Item * mi,void (* func)(void * data,E_Menu * m,E_Menu_Item * mi),void * data)997 e_menu_item_drag_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), void *data)
998 {
999    E_OBJECT_CHECK(mi);
1000    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
1001    mi->drag_cb.func = func;
1002    mi->drag_cb.data = data;
1003 }
1004 
1005 E_API void
e_menu_item_active_set(E_Menu_Item * mi,int active)1006 e_menu_item_active_set(E_Menu_Item *mi, int active)
1007 {
1008    Eina_List *tmp = NULL;
1009 
1010    E_OBJECT_CHECK(mi);
1011    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
1012    if (mi->separator) return;
1013    active = !!active;
1014    if (active == mi->active) return;
1015    if ((active) && (!mi->active))
1016      {
1017         E_Menu_Item *pmi;
1018 
1019         if (mi->disable) return;
1020         pmi = _e_menu_item_active_get();
1021         if (mi == pmi) return;
1022         if (pmi)
1023           {
1024              tmp = _e_active_menus_copy_ref();
1025              e_menu_item_active_set(pmi, 0);
1026           }
1027         if (_e_prev_active_menu_item && (mi != _e_prev_active_menu_item))
1028           {
1029              if (mi->menu->parent_item && (_e_prev_active_menu_item != mi->menu->parent_item))
1030                _e_menu_submenu_deactivate(_e_prev_active_menu_item);
1031           }
1032         mi->active = 1;
1033         _e_active_menu_item = mi;
1034         if (mi->bg_object)
1035           edje_object_signal_emit(mi->bg_object, "e,state,selected", "e");
1036         if (mi->icon_bg_object)
1037           edje_object_signal_emit(mi->icon_bg_object, "e,state,selected", "e");
1038         if (isedje(mi->label_object))
1039           edje_object_signal_emit(mi->label_object, "e,state,selected", "e");
1040         if (isedje(mi->submenu_object))
1041           edje_object_signal_emit(mi->submenu_object, "e,state,selected", "e");
1042         if (isedje(mi->toggle_object))
1043           edje_object_signal_emit(mi->toggle_object, "e,state,selected", "e");
1044         if (mi->icon_key)
1045           {
1046              if (mi->icon_object)
1047                {
1048                   if (isedje(mi->icon_object))
1049                     edje_object_signal_emit(mi->icon_object, "e,state,selected", "e");
1050                   else
1051                     e_icon_selected_set(mi->icon_object, EINA_TRUE);
1052                }
1053           }
1054         edje_object_signal_emit(mi->menu->bg_object, "e,state,selected", "e");
1055         _e_menu_submenu_activate(mi);
1056      }
1057    else if ((!active) && (mi->active))
1058      {
1059         tmp = _e_active_menus_copy_ref();
1060         mi->active = 0;
1061         _e_prev_active_menu_item = mi;
1062         _e_active_menu_item = NULL;
1063         if (mi->bg_object)
1064           edje_object_signal_emit(mi->bg_object, "e,state,unselected", "e");
1065         if (mi->icon_bg_object)
1066           edje_object_signal_emit(mi->icon_bg_object, "e,state,unselected", "e");
1067         if (isedje(mi->label_object))
1068           edje_object_signal_emit(mi->label_object, "e,state,unselected", "e");
1069         if (isedje(mi->submenu_object))
1070           edje_object_signal_emit(mi->submenu_object, "e,state,unselected", "e");
1071         if (isedje(mi->toggle_object))
1072           edje_object_signal_emit(mi->toggle_object, "e,state,unselected", "e");
1073         if (mi->icon_key)
1074           {
1075              if (mi->icon_object)
1076                {
1077                   if (isedje(mi->icon_object))
1078                     edje_object_signal_emit(mi->icon_object, "e,state,unselected", "e");
1079                   else
1080                     e_icon_selected_set(mi->icon_object, EINA_FALSE);
1081                }
1082           }
1083         edje_object_signal_emit(mi->menu->bg_object, "e,state,unselected", "e");
1084      }
1085    _e_menu_list_free_unref(tmp);
1086 }
1087 
1088 E_API E_Menu_Item *
e_menu_item_active_get(void)1089 e_menu_item_active_get(void)
1090 {
1091    return _e_active_menu_item;
1092 }
1093 
1094 E_API void
e_menu_active_item_activate(void)1095 e_menu_active_item_activate(void)
1096 {
1097    _e_menu_active_call();
1098    _e_menu_deactivate_all();
1099 }
1100 
1101 E_API void
e_menu_item_disabled_set(E_Menu_Item * mi,int disable)1102 e_menu_item_disabled_set(E_Menu_Item *mi, int disable)
1103 {
1104    E_OBJECT_CHECK(mi);
1105    E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
1106    if (mi->separator) return;
1107    if ((disable))
1108      {
1109         if (mi->active) e_menu_item_active_set(mi, 0);
1110         mi->disable = 1;
1111         if (mi->icon_bg_object)
1112           edje_object_signal_emit(mi->icon_bg_object, "e,state,disable", "e");
1113         if (isedje(mi->label_object))
1114           edje_object_signal_emit(mi->label_object, "e,state,disable", "e");
1115         if (isedje(mi->toggle_object))
1116           edje_object_signal_emit(mi->toggle_object, "e,state,disable", "e");
1117      }
1118    else
1119      {
1120         mi->disable = 0;
1121         if (mi->icon_bg_object)
1122           edje_object_signal_emit(mi->icon_bg_object, "e,state,enable", "e");
1123         if (isedje(mi->label_object))
1124           edje_object_signal_emit(mi->label_object, "e,state,enable", "e");
1125         if (isedje(mi->toggle_object))
1126           edje_object_signal_emit(mi->toggle_object, "e,state,enable", "e");
1127      }
1128 }
1129 
1130 E_API void
e_menu_idler_before(void)1131 e_menu_idler_before(void)
1132 {
1133    /* when e goes "idle" this gets called so leave all our hard work till */
1134    /* idle time to avoid falling behind the user. just evaluate the high */
1135    /* level state machine */
1136    Eina_List *l, *removals = NULL, *tmp;
1137    E_Menu *m;
1138    int active_count = 0;
1139 
1140    if (pending_feed)
1141      {
1142         e_comp_canvas_feed_mouse_up(pending_activate_time);
1143         pending_feed = 0;
1144      }
1145 
1146    /* add refcount to all menus we will work with */
1147    tmp = _e_active_menus_copy_ref();
1148    /* phase 1. hide all the menus that want to be hidden */
1149    EINA_LIST_FOREACH(_e_active_menus, l, m)
1150      {
1151         if ((!m->cur.visible) && (m->prev.visible))
1152           {
1153              m->prev.visible = m->cur.visible;
1154              e_object_ref(E_OBJECT(m));
1155              evas_object_pass_events_set(m->comp_object, 1);
1156              if (m->container_object)
1157                {
1158                   evas_object_intercept_move_callback_del(m->container_object, _e_menu_cb_intercept_container_move);
1159                   evas_object_intercept_resize_callback_del(m->container_object, _e_menu_cb_intercept_container_resize);
1160                }
1161              evas_object_hide(m->comp_object);
1162           }
1163      }
1164    /* phase 2. move & reisze all the menus that want to moves/resized */
1165    EINA_LIST_FOREACH(_e_active_menus, l, m)
1166      {
1167         if (m->frozen || (!m->active) || (!m->zone)) continue;
1168         if (!m->realized) _e_menu_realize(m);
1169         if (!m->realized) continue;
1170         if (((m->cur.w) != (m->prev.w)) ||
1171             ((m->cur.h) != (m->prev.h)))
1172           {
1173              int w, h;
1174 
1175              m->prev.w = m->cur.w;
1176              m->prev.h = m->cur.h;
1177              w = m->cur.w;
1178              h = m->cur.h;
1179              evas_object_resize(m->comp_object, w, h);
1180           }
1181         if (((m->cur.x) != (m->prev.x)) ||
1182             ((m->cur.y) != (m->prev.y)))
1183           {
1184              if (!m->parent_item)
1185                {
1186                   int x, y, w, h;
1187 
1188                   e_zone_useful_geometry_get(m->zone, &x, &y, &w, &h);
1189                   if (m->cur.w <= w)
1190                     {
1191                        if ((m->cur.x + m->cur.w) > (x + w))
1192                          m->cur.x = x + w - m->cur.w;
1193                     }
1194                   if (m->cur.h <= h)
1195                     {
1196                        if ((m->cur.y + m->cur.h) > (y + h))
1197                          m->cur.y = y + h - m->cur.h;
1198                     }
1199                }
1200              m->prev.x = m->cur.x;
1201              m->prev.y = m->cur.y;
1202              _e_menu_lock = 1;
1203              evas_object_move(m->comp_object, m->cur.x, m->cur.y);
1204              _e_menu_lock = 0;
1205           }
1206      }
1207    /* phase 3. show all the menus that want to be shown */
1208    EINA_LIST_FOREACH(_e_active_menus, l, m)
1209      {
1210         if (m->frozen) continue;
1211         if (!m->realized) continue;
1212         if (m->cur.visible)
1213           {
1214              m->prev.visible = m->cur.visible;
1215              evas_object_pass_events_set(m->comp_object, 0);
1216              evas_object_show(m->comp_object);
1217           }
1218      }
1219    /* phase 4. de-activate... */
1220    EINA_LIST_REVERSE_FOREACH(_e_active_menus, l, m)
1221      {
1222         if (!m->active)
1223           {
1224              if ((m->realized) &&
1225                  (!evas_object_visible_get(m->comp_object)))
1226                {
1227                   _e_menu_unrealize(m);
1228                   removals = eina_list_append(removals, m);
1229                }
1230           }
1231      }
1232    EINA_LIST_FREE(removals, m)
1233      {
1234         if (m->in_active_list)
1235           {
1236              _e_active_menus = eina_list_remove(_e_active_menus, m);
1237              m->in_active_list = 0;
1238              e_object_unref(E_OBJECT(m));
1239           }
1240      }
1241    /* del refcount to all menus we worked with */
1242    _e_menu_list_free_unref(tmp);
1243 
1244    EINA_LIST_FOREACH(_e_active_menus, l, m)
1245      {
1246         if (m->active) active_count++;
1247      }
1248    if (!active_count)
1249      {
1250         if (_e_menu_win == e_comp->ee_win)
1251           {
1252              if (_e_menu_grabbed)
1253                {
1254                   e_comp_ungrab_input(1, 1);
1255                   _e_menu_grabbed = EINA_FALSE;
1256                }
1257              _e_menu_win = UINT_MAX;
1258              e_bindings_disabled_set(0);
1259           }
1260      }
1261 }
1262 
1263 E_API Eina_Bool
e_menu_is_active(void)1264 e_menu_is_active(void)
1265 {
1266    return _e_menu_win == e_comp->ee_win;
1267 }
1268 
1269 E_API E_Menu *
e_menu_active_get(void)1270 e_menu_active_get(void)
1271 {
1272    return _e_active_menus ? eina_list_last_data_get(_e_active_menus) : NULL;
1273 }
1274 
1275 /* local subsystem functions */
1276 static void
_e_menu_dangling_cb(void * data)1277 _e_menu_dangling_cb(void *data)
1278 {
1279    E_Menu *m = data;
1280 
1281    WRN("DANGLING SUBMENU: REF(%d)||MENU(%p)", e_object_ref_get(data), data);
1282    m->dangling_job = NULL;
1283 }
1284 
1285 static void
_e_menu_free(E_Menu * m)1286 _e_menu_free(E_Menu *m)
1287 {
1288    Eina_List *l, *l_next;
1289    E_Menu_Item *mi;
1290    E_Menu_Category *cat = NULL;
1291 
1292    /* the foreign menu items */
1293    if (m->category) cat = eina_hash_find(_e_menu_categories, m->category);
1294    if (cat)
1295      {
1296         E_Menu_Category_Callback *cb;
1297 
1298         EINA_LIST_FOREACH(cat->callbacks, l, cb)
1299           {
1300              if (cb->free) cb->free(cb->data);
1301           }
1302      }
1303    eina_stringshare_replace(&m->category, NULL);
1304    if (m->parent_item)
1305      m->parent_item->submenu = NULL;
1306    _e_menu_unrealize(m);
1307    if (m->realized) return;
1308    EINA_LIST_FOREACH_SAFE(m->items, l, l_next, mi)
1309      e_object_del(E_OBJECT(mi));
1310    if (m->in_active_list)
1311      {
1312         _e_active_menus = eina_list_remove(_e_active_menus, m);
1313         m->in_active_list = 0;
1314      }
1315    if (m->header.title) eina_stringshare_del(m->header.title);
1316    if (m->header.icon_file) eina_stringshare_del(m->header.icon_file);
1317    if (m->dangling_job) ecore_job_del(m->dangling_job);
1318    free(m);
1319 }
1320 
1321 static void
_e_menu_item_free(E_Menu_Item * mi)1322 _e_menu_item_free(E_Menu_Item *mi)
1323 {
1324    if (mi == _e_active_menu_item) _e_active_menu_item = NULL;
1325    if (mi == _e_prev_active_menu_item) _e_prev_active_menu_item = NULL;
1326    if (mi->submenu)
1327      {
1328         int ref = 0;
1329 
1330         /* parent_item gets unset in a few places, reapply it for use in cleanup */
1331         if (!mi->submenu->parent_item)
1332           mi->submenu->parent_item = mi;
1333         /* menu may not have been deactivated, ensure deactivate callback is called */
1334         if (mi->active)
1335           _e_menu_submenu_deactivate(mi);
1336         /* submenus CANNOT exist without their parent menu+item, so ensure that they get deleted */
1337         if (mi->submenu)
1338           {
1339              ref = e_object_ref_get(E_OBJECT(mi->submenu)) - 1;
1340              e_object_unref(E_OBJECT(mi->submenu));
1341           }
1342         if (ref)
1343           {
1344              if (!mi->submenu->dangling_job)
1345                mi->submenu->dangling_job = ecore_job_add(_e_menu_dangling_cb, mi->submenu);
1346              mi->submenu->parent_item = NULL;
1347           }
1348      }
1349    if (mi->menu->realized) _e_menu_item_unrealize(mi);
1350    mi->menu->items = eina_list_remove(mi->menu->items, mi);
1351    if (mi->icon) eina_stringshare_del(mi->icon);
1352    if (mi->icon_key) eina_stringshare_del(mi->icon_key);
1353    if (mi->label) eina_stringshare_del(mi->label);
1354    free(mi);
1355 }
1356 
1357 static void
_e_menu_cb_intercept_item_move(void * data,Evas_Object * o,Evas_Coord x,Evas_Coord y)1358 _e_menu_cb_intercept_item_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y)
1359 {
1360    E_Menu_Item *mi;
1361 
1362    mi = data;
1363    mi->x = x;
1364    mi->y = y;
1365    evas_object_move(o, x, y);
1366    if ((mi->submenu) && (mi->submenu->parent_item))
1367      {
1368         mi->submenu->zone = mi->menu->zone;
1369         _e_menu_reposition(mi->submenu);
1370      }
1371 }
1372 
1373 static void
_e_menu_cb_intercept_item_resize(void * data,Evas_Object * o,Evas_Coord w,Evas_Coord h)1374 _e_menu_cb_intercept_item_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h)
1375 {
1376    E_Menu_Item *mi;
1377 
1378    mi = data;
1379    mi->w = w;
1380    mi->h = h;
1381    evas_object_resize(o, w, h);
1382    if ((mi->submenu) && (mi->submenu->parent_item))
1383      _e_menu_reposition(mi->submenu);
1384 }
1385 
1386 static void
_e_menu_cb_intercept_container_move(void * data,Evas_Object * o,Evas_Coord x,Evas_Coord y)1387 _e_menu_cb_intercept_container_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y)
1388 {
1389    E_Menu *m;
1390 
1391    m = data;
1392    m->container_x = x;
1393    m->container_y = y;
1394    if (m->parent_item) _e_menu_reposition(m);
1395    evas_object_move(o, x, y);
1396 }
1397 
1398 static void
_e_menu_cb_intercept_container_resize(void * data,Evas_Object * o,Evas_Coord w,Evas_Coord h)1399 _e_menu_cb_intercept_container_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h)
1400 {
1401    E_Menu *m;
1402 
1403    m = data;
1404    m->container_w = w;
1405    m->container_h = h;
1406    if (m->parent_item) _e_menu_reposition(m);
1407    evas_object_resize(o, w, h);
1408 }
1409 
1410 static void
_e_menu_hide_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)1411 _e_menu_hide_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
1412 {
1413    e_object_unref(data);
1414 }
1415 
1416 static void
_e_menu_item_realize(E_Menu_Item * mi)1417 _e_menu_item_realize(E_Menu_Item *mi)
1418 {
1419    Evas_Object *o;
1420    Evas_Coord ww = 1, hh = 1;
1421 
1422    /* and set up initial item state */
1423    if (mi->separator)
1424      {
1425         o = edje_object_add(mi->menu->evas);
1426         mi->separator_object = o;
1427         e_theme_edje_object_set(o, "base/theme/menus",
1428                                 "e/widgets/menu/default/separator");
1429         edje_object_size_min_calc(mi->separator_object, &ww, &hh);
1430         E_FILL(mi->separator_object);
1431         mi->separator_w = ww;
1432         mi->separator_h = hh;
1433         evas_object_size_hint_min_set(mi->separator_object, ww, hh);
1434         elm_box_pack_end(mi->menu->container_object, mi->separator_object);
1435         evas_object_show(o);
1436      }
1437    else
1438      {
1439         o = edje_object_add(mi->menu->evas);
1440         mi->bg_object = o;
1441         evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_IN, _e_menu_cb_item_in, mi);
1442         evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_OUT, _e_menu_cb_item_out, mi);
1443         evas_object_intercept_move_callback_add(o, _e_menu_cb_intercept_item_move, mi);
1444         evas_object_intercept_resize_callback_add(o, _e_menu_cb_intercept_item_resize, mi);
1445         if ((mi->submenu) || (mi->submenu_pre_cb.func))
1446           {
1447              if (!e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
1448                                           "e/widgets/menu/default/submenu_bg"))
1449                goto no_submenu_item;
1450           }
1451         else
1452           {
1453 no_submenu_item:
1454              e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
1455                                      "e/widgets/menu/default/item_bg");
1456           }
1457         o = elm_box_add(e_comp->elm);
1458         mi->container_object = o;
1459         elm_box_horizontal_set(o, 1);
1460         evas_object_show(o);
1461 
1462 
1463         if (mi->check)
1464           {
1465              o = edje_object_add(mi->menu->evas);
1466              mi->toggle_object = o;
1467              e_theme_edje_object_set(o, "base/theme/menus",
1468                                      "e/widgets/menu/default/check");
1469              edje_object_size_min_calc(mi->toggle_object, &ww, &hh);
1470              mi->toggle_w = ww;
1471              mi->toggle_h = hh;
1472              E_WEIGHT(mi->toggle_object, 0, 1);
1473              E_FILL(mi->toggle_object);
1474              evas_object_size_hint_min_set(mi->toggle_object, ww, hh);
1475              elm_box_pack_end(mi->container_object, o);
1476              evas_object_show(o);
1477           }
1478         else if (mi->radio)
1479           {
1480              o = edje_object_add(mi->menu->evas);
1481              mi->toggle_object = o;
1482              e_theme_edje_object_set(o, "base/theme/menus",
1483                                      "e/widgets/menu/default/radio");
1484              edje_object_size_min_calc(mi->toggle_object, &ww, &hh);
1485              mi->toggle_w = ww;
1486              mi->toggle_h = hh;
1487              E_WEIGHT(mi->toggle_object, 0, 1);
1488              E_FILL(mi->toggle_object);
1489              evas_object_size_hint_min_set(mi->toggle_object, ww, hh);
1490              elm_box_pack_end(mi->container_object, o);
1491              evas_object_show(o);
1492           }
1493         else
1494           {
1495              o = evas_object_rectangle_add(mi->menu->evas);
1496              mi->toggle_object = o;
1497              evas_object_color_set(o, 0, 0, 0, 0);
1498              elm_box_pack_end(mi->container_object, o);
1499           }
1500         if ((!e_config->menu_icons_hide) && ((mi->icon) || (mi->realize_cb.func)))
1501           {
1502              int icon_w = 0, icon_h = 0;
1503 
1504              o = edje_object_add(mi->menu->evas);
1505              if (e_theme_edje_object_set(o, "base/theme/menus",
1506                                          "e/widgets/menu/default/icon"))
1507                {
1508                   mi->icon_bg_object = o;
1509                }
1510              else
1511                {
1512                   evas_object_del(o);
1513                   o = NULL;
1514                }
1515              //if (o) evas_object_pass_events_set(o, 1);
1516 
1517              /* FIXME: Not sure why there are two different tries to get the icon size, surely only the last one is needed. */
1518              /* FIXME: Do it this way later, when e_app_icon_add() just registers a request for an icon to be filled in when it's ready.
1519                 if (mi->app)
1520                 {
1521                   o = e_app_icon_add(mi->menu->evas, mi->app);
1522                   mi->icon_object = o;
1523                   e_icon_size_get(mi->icon_object, &icon_w, &icon_h);
1524                 }
1525                 else
1526               */
1527              if (mi->icon)
1528                {
1529                   /* This is done this way to match up with how e_app_icon_add does it. */
1530                   if (mi->icon_key)
1531                     {
1532                        Evas_Coord iww, ihh;
1533 
1534                        o = edje_object_add(mi->menu->evas);
1535                        if (edje_object_file_set(o, mi->icon, mi->icon_key))
1536                          {
1537                             mi->icon_object = o;
1538                             edje_object_size_max_get(o, &iww, &ihh);
1539                             icon_w = iww;
1540                             icon_h = ihh;
1541                          }
1542                        else
1543                          {
1544                             evas_object_del(o);
1545                             o = NULL;
1546                          }
1547                     }
1548                   if (!mi->icon_object)
1549                     {
1550                        o = e_icon_add(mi->menu->evas);
1551                        mi->icon_object = o;
1552                        e_icon_scale_size_set(o, e_util_icon_size_normalize(96 * e_scale));
1553                        e_icon_preload_set(mi->icon_object, 1);
1554                        e_icon_file_set(o, mi->icon);
1555                        e_icon_fill_inside_set(mi->icon_object, 1);
1556                        e_icon_size_get(mi->icon_object, &icon_w, &icon_h);
1557                     }
1558                }
1559              if (_e_menu_realize_call(mi))
1560                {
1561                   o = mi->icon_object;
1562                   e_icon_fill_inside_set(o, 1);
1563                   e_icon_size_get(o, &icon_w, &icon_h);
1564                }
1565 
1566              evas_object_show(o);
1567 
1568              if (mi->icon_bg_object)
1569                {
1570                   evas_object_size_hint_min_set(mi->icon_object, 0, 0);
1571                   edje_object_part_swallow(mi->icon_bg_object,
1572                                            "e.swallow.content",
1573                                            mi->icon_object);
1574                   edje_object_size_min_calc(mi->icon_bg_object, &ww, &hh);
1575                   mi->icon_w = ww;
1576                   mi->icon_h = hh;
1577                   evas_object_size_hint_min_set(mi->icon_bg_object, ww, hh);
1578                   E_WEIGHT(mi->icon_bg_object, 0, 1);
1579                   E_FILL(mi->icon_bg_object);
1580                   elm_box_pack_end(mi->container_object, mi->icon_bg_object);
1581                   evas_object_show(mi->icon_bg_object);
1582                }
1583              else
1584                {
1585                   o = edje_object_add(mi->menu->evas);
1586                   e_icon_size_get(mi->icon_object, &icon_w, &icon_h);
1587                   mi->icon_w = icon_w;
1588                   mi->icon_h = icon_h;
1589                   E_WEIGHT(mi->icon_object, 0, 1);
1590                   E_FILL(mi->icon_object);
1591                   evas_object_size_hint_min_set(mi->icon_object, ww, hh);
1592                   elm_box_pack_end(mi->container_object, o);
1593                   evas_object_show(o);
1594                }
1595           }
1596         else
1597           {
1598              o = evas_object_rectangle_add(mi->menu->evas);
1599              mi->icon_object = o;
1600              evas_object_color_set(o, 0, 0, 0, 0);
1601              elm_box_pack_end(mi->container_object, o);
1602           }
1603 
1604         if (mi->label)
1605           {
1606              o = edje_object_add(mi->menu->evas);
1607              mi->label_object = o;
1608              e_theme_edje_object_set(o, "base/theme/menus",
1609                                      "e/widgets/menu/default/label");
1610              /* default label */
1611              edje_object_part_text_set(o, "e.text.label", mi->label);
1612              edje_object_size_min_calc(mi->label_object, &ww, &hh);
1613              mi->label_w = ww;
1614              mi->label_h = hh;
1615              evas_object_size_hint_min_set(mi->label_object, ww, hh);
1616              E_EXPAND(mi->label_object);
1617              E_FILL(mi->label_object);
1618              elm_box_pack_end(mi->container_object, o);
1619              evas_object_show(o);
1620           }
1621         else
1622           {
1623              o = evas_object_rectangle_add(mi->menu->evas);
1624              mi->label_object = o;
1625              evas_object_color_set(o, 0, 0, 0, 0);
1626              elm_box_pack_end(mi->container_object, o);
1627           }
1628         if ((mi->submenu) || (mi->submenu_pre_cb.func))
1629           {
1630              o = edje_object_add(mi->menu->evas);
1631              mi->submenu_object = o;
1632              e_theme_edje_object_set(o, "base/theme/menus",
1633                                      "e/widgets/menu/default/submenu");
1634              edje_object_size_min_calc(mi->submenu_object, &ww, &hh);
1635              mi->submenu_w = ww;
1636              mi->submenu_h = hh;
1637              E_WEIGHT(mi->submenu_object, 0, 1);
1638              E_FILL(mi->submenu_object);
1639              evas_object_size_hint_min_set(mi->submenu_object, ww, hh);
1640              elm_box_pack_end(mi->container_object, o);
1641              evas_object_show(o);
1642           }
1643         else
1644           {
1645              o = evas_object_rectangle_add(mi->menu->evas);
1646              mi->submenu_object = o;
1647              evas_object_color_set(o, 0, 0, 0, 0);
1648              elm_box_pack_end(mi->container_object, o);
1649           }
1650 
1651         edje_object_part_swallow(mi->bg_object, "e.swallow.content",
1652                                  mi->container_object);
1653 
1654         elm_box_pack_end(mi->menu->container_object, mi->bg_object);
1655         evas_object_show(mi->container_object);
1656         evas_object_show(mi->bg_object);
1657      }
1658    if (mi->active) e_menu_item_active_set(mi, 1);
1659    if (mi->toggle) e_menu_item_toggle_set(mi, 1);
1660    if (mi->disable) e_menu_item_disabled_set(mi, 1);
1661 }
1662 
1663 static void
_e_menu_realize(E_Menu * m)1664 _e_menu_realize(E_Menu *m)
1665 {
1666    Evas_Object *o;
1667    Eina_List *l;
1668    E_Menu_Item *mi;
1669 
1670    if (m->realized || (!m->items)) return;
1671 
1672    if (m->parent_item && m->parent_item->menu)
1673      m->zone = m->parent_item->menu->zone;
1674    if (!m->zone) return; //menu not ready!
1675    m->evas = evas_object_evas_get(e_comp->elm);
1676    evas_event_freeze(m->evas);
1677 
1678    o = edje_object_add(m->evas);
1679    m->bg_object = o;
1680    e_theme_edje_object_set(o, "base/theme/menus", "e/widgets/menu/default/background");
1681    if (m->header.title)
1682      {
1683         edje_object_part_text_set(o, "e.text.title", m->header.title);
1684         edje_object_signal_emit(o, "e,action,show,title", "e");
1685         edje_object_message_signal_process(o);
1686      }
1687 
1688    m->comp_object = e_comp_object_util_add(o, E_COMP_OBJECT_TYPE_MENU);
1689    if (!m->parent_item)
1690      e_comp_object_util_autoclose(m->comp_object, _e_menu_cb_mouse_evas_down, _e_menu_cb_key_down, m);
1691    evas_object_event_callback_add(m->comp_object, EVAS_CALLBACK_HIDE, _e_menu_hide_cb, m);
1692    evas_object_layer_set(m->comp_object, E_LAYER_MENU);
1693    evas_object_geometry_set(m->comp_object, m->cur.x, m->cur.y, m->cur.w, m->cur.h);
1694 
1695    o = elm_box_add(e_comp->elm);
1696    m->container_object = o;
1697    evas_object_intercept_move_callback_add(o, _e_menu_cb_intercept_container_move, m);
1698    evas_object_intercept_resize_callback_add(o, _e_menu_cb_intercept_container_resize, m);
1699 
1700    EINA_LIST_FOREACH(m->items, l, mi)
1701      _e_menu_item_realize(mi);
1702 
1703    edje_object_part_swallow(m->bg_object, "e.swallow.content", m->container_object);
1704 
1705    _e_menu_items_layout_update(m);
1706 
1707 
1708    evas_event_thaw(m->evas);
1709    evas_event_thaw_eval(m->evas);
1710    m->realized = 1;
1711 }
1712 
1713 static void
_e_menu_items_layout_update(E_Menu * m)1714 _e_menu_items_layout_update(E_Menu *m)
1715 {
1716    Eina_List *l;
1717    E_Menu_Item *mi;
1718    Evas_Coord bw, bh, mw = 0, mh = 0;
1719    int toggles_on = 0;
1720    int icons_on = 0;
1721    int labels_on = 0;
1722    int submenus_on = 0;
1723    int min_icon_w = 0, min_icon_h = 0;
1724    int min_label_w = 0, min_label_h = 0;
1725    int min_submenu_w = 0, min_submenu_h = 0;
1726    int min_toggle_w = 0, min_toggle_h = 0;
1727    int min_w = 0, min_h = 1;
1728    int zh = 0, ms = 0, maxh = 0;
1729    unsigned int cur_items = 0, max_items = -1;
1730 
1731    if (!m->zone) return;
1732    EINA_LIST_FOREACH(m->items, l, mi)
1733      {
1734         if (mi->icon) icons_on = 1;
1735         if (mi->icon_object) icons_on = 1;
1736         if (mi->label) labels_on = 1;
1737         if (mi->submenu) submenus_on = 1;
1738         if (mi->submenu_pre_cb.func) submenus_on = 1;
1739         if (mi->check) toggles_on = 1;
1740         if (mi->radio) toggles_on = 1;
1741 
1742         if (mi->icon_w > min_icon_w) min_icon_w = mi->icon_w;
1743         if (mi->icon_h > min_icon_h) min_icon_h = mi->icon_h;
1744         if (mi->label_w > min_label_w) min_label_w = mi->label_w;
1745         if (mi->label_h > min_label_h) min_label_h = mi->label_h;
1746         if (mi->submenu_w > min_submenu_w) min_submenu_w = mi->submenu_w;
1747         if (mi->submenu_h > min_submenu_h) min_submenu_h = mi->submenu_h;
1748         if (mi->toggle_w > min_toggle_w) min_toggle_w = mi->toggle_w;
1749         if (mi->toggle_h > min_toggle_h) min_toggle_h = mi->toggle_h;
1750      }
1751    if (labels_on)
1752      {
1753         if (submenus_on)
1754           {
1755              if (min_label_h < min_submenu_h)
1756                min_label_h = min_submenu_h;
1757           }
1758         if (toggles_on)
1759           {
1760              if (min_label_h < min_toggle_h)
1761                min_label_h = min_toggle_h;
1762           }
1763         if ((icons_on) && (min_icon_h > 0))
1764           {
1765              min_icon_w = (min_icon_w * min_label_h) / min_icon_h;
1766              min_icon_h = min_label_h;
1767           }
1768         min_w = min_label_w + min_icon_w + min_submenu_w + min_toggle_w;
1769         min_h = min_label_h;
1770      }
1771    else if (icons_on)
1772      {
1773         if (submenus_on)
1774           {
1775              if (min_icon_h < min_submenu_h)
1776                min_icon_h = min_submenu_h;
1777           }
1778         if (toggles_on)
1779           {
1780              if (min_icon_h < min_toggle_h)
1781                min_icon_h = min_toggle_h;
1782           }
1783         min_w = min_icon_w + min_toggle_w + min_submenu_w;
1784         min_h = min_icon_h;
1785      }
1786    else if (toggles_on)
1787      {
1788         if (submenus_on)
1789           {
1790              if (min_toggle_h < min_submenu_h)
1791                min_toggle_h = min_submenu_h;
1792           }
1793         min_w = min_toggle_w + min_submenu_w;
1794         min_h = min_toggle_h;
1795      }
1796    if (min_h * eina_list_count(m->items) >= (unsigned int)m->zone->h)
1797      {
1798         e_zone_useful_geometry_get(m->zone, NULL, NULL, NULL, &zh);
1799         maxh = zh * 4;
1800         if (maxh > 30000) maxh = 30000;  // 32k x 32k mx coord limit for wins
1801         max_items = (maxh / min_h) - 1;
1802      }
1803    EINA_LIST_FOREACH(m->items, l, mi)
1804      {
1805         if (cur_items >= max_items)
1806           {
1807              _e_menu_item_unrealize(mi);
1808              continue;
1809           }
1810         cur_items++;
1811         if (mi->separator)
1812           {
1813              E_WEIGHT(mi->separator_object, 1, 0);
1814              E_FILL(mi->separator_object);
1815              evas_object_size_hint_min_set(mi->separator_object, mi->separator_w, mi->separator_h);
1816              evas_object_size_hint_max_set(mi->separator_object, -1, mi->separator_h);
1817              ms += mi->separator_h;
1818              continue;
1819           }
1820         E_WEIGHT(mi->toggle_object, 0, toggles_on);
1821         E_FILL(mi->toggle_object);
1822         evas_object_size_hint_min_set(mi->toggle_object, min_toggle_w * toggles_on, min_toggle_h * toggles_on);
1823         if (icons_on)
1824           {
1825              E_WEIGHT(mi->icon_bg_object ?: mi->icon_object, 0, 1);
1826              E_FILL(mi->icon_bg_object ?: mi->icon_object);
1827              evas_object_size_hint_min_set(mi->icon_bg_object ?: mi->icon_object, min_icon_w, min_icon_h);
1828           }
1829         else
1830           {
1831              E_WEIGHT(mi->icon_object, 0, 1);
1832              E_FILL(mi->icon_object);
1833              evas_object_size_hint_min_set(mi->icon_object, 0, 0);
1834           }
1835 
1836         E_WEIGHT(mi->label_object, 0, 1 * labels_on);
1837         E_FILL(mi->label_object);
1838         evas_object_size_hint_min_set(mi->label_object, min_label_w * labels_on, min_label_h * labels_on);
1839 
1840         E_WEIGHT(mi->submenu_object, 0, 1 * submenus_on);
1841         E_FILL(mi->submenu_object);
1842         evas_object_size_hint_min_set(mi->submenu_object, min_submenu_w * submenus_on, min_submenu_h * submenus_on);
1843 
1844         evas_object_size_hint_min_set(mi->container_object,
1845                                         min_w, min_h);
1846         edje_object_size_min_calc(mi->bg_object, &mw, &mh);
1847         E_WEIGHT(mi->bg_object, 0, 1);
1848         E_FILL(mi->bg_object);
1849         evas_object_size_hint_min_set(mi->bg_object, mw, mh);
1850         ms += mh;
1851      }
1852    elm_box_recalculate(m->container_object);
1853    evas_object_size_hint_min_get(m->container_object, &bw, &bh);
1854    evas_object_size_hint_max_set(m->container_object, bw, bh);
1855    edje_object_size_min_calc(m->bg_object, &mw, &mh);
1856    m->cur.w = mw;
1857    m->cur.h = mh;
1858 }
1859 
1860 static void
_e_menu_item_unrealize(E_Menu_Item * mi)1861 _e_menu_item_unrealize(E_Menu_Item *mi)
1862 {
1863    if (mi->separator_object) evas_object_del(mi->separator_object);
1864    mi->separator_object = NULL;
1865    if (mi->bg_object) evas_object_del(mi->bg_object);
1866    mi->bg_object = NULL;
1867    if (mi->container_object) evas_object_del(mi->container_object);
1868    mi->container_object = NULL;
1869    if (mi->toggle_object) evas_object_del(mi->toggle_object);
1870    mi->toggle_object = NULL;
1871    if (mi->icon_bg_object) evas_object_del(mi->icon_bg_object);
1872    mi->icon_bg_object = NULL;
1873    if (mi->icon_object) evas_object_del(mi->icon_object);
1874    mi->icon_object = NULL;
1875    if (mi->label_object) evas_object_del(mi->label_object);
1876    mi->label_object = NULL;
1877    if (mi->submenu_object) evas_object_del(mi->submenu_object);
1878    mi->submenu_object = NULL;
1879 }
1880 
1881 static void
_e_menu_unrealize(E_Menu * m)1882 _e_menu_unrealize(E_Menu *m)
1883 {
1884    Eina_List *l;
1885    E_Menu_Item *mi;
1886 
1887    if (!m->realized) return;
1888    /* freeze+thaw here breaks the universe. don't do it. */
1889    //evas_event_freeze(m->evas);
1890    if (m->comp_object)
1891      evas_object_event_callback_del(m->comp_object, EVAS_CALLBACK_HIDE, _e_menu_hide_cb);
1892    if (m->cur.visible && m->comp_object && (!stopping))
1893      {
1894         /* force unref in smart object */
1895         if (m->container_object)
1896           {
1897              evas_object_intercept_move_callback_del(m->container_object, _e_menu_cb_intercept_container_move);
1898              evas_object_intercept_resize_callback_del(m->container_object, _e_menu_cb_intercept_container_resize);
1899           }
1900         evas_object_pass_events_set(m->comp_object, 1);
1901         evas_object_hide(m->comp_object);
1902         E_FREE_FUNC(m->comp_object, evas_object_del);
1903         return;
1904      }
1905    evas_object_hide(m->comp_object);
1906    evas_object_del(m->comp_object);
1907    if (stopping && m->comp_object) evas_object_unref(m->comp_object);
1908    EINA_LIST_FOREACH(m->items, l, mi)
1909      _e_menu_item_unrealize(mi);
1910    E_FREE_FUNC(m->header.icon, evas_object_del);
1911    E_FREE_FUNC(m->bg_object, evas_object_del);
1912    E_FREE_FUNC(m->container_object, evas_object_del);
1913    m->cur.visible = 0;
1914    m->prev.visible = 0;
1915    m->realized = 0;
1916    m->zone = NULL;
1917    //evas_event_thaw(m->evas);
1918    m->evas = NULL;
1919 }
1920 
1921 static void
_e_menu_activate_internal(E_Menu * m,E_Zone * zone)1922 _e_menu_activate_internal(E_Menu *m, E_Zone *zone)
1923 {
1924    E_Menu_Category *cat = NULL;
1925    Eina_List *l;
1926 
1927    if (m->pre_activate_cb.func)
1928      m->pre_activate_cb.func(m->pre_activate_cb.data, m);
1929    m->fast_mouse = 0;
1930    m->pending_new_submenu = 0;
1931    if (_e_menu_win != e_comp->ee_win)
1932      {
1933         _e_menu_win = e_comp->ee_win;
1934         if (!e_comp_grab_input(1, 1))
1935           {
1936              _e_menu_win = UINT_MAX;
1937              return;
1938           }
1939         _e_menu_grabbed = EINA_TRUE;
1940         e_bindings_disabled_set(1);
1941      }
1942    m->zone = zone;
1943    if (!m->active)
1944      {
1945         /* this remove is in case the menu is marked as inactive but hasn't */
1946         /* been removed from the list yet */
1947         if (m->in_active_list)
1948           _e_active_menus = eina_list_remove(_e_active_menus, m);
1949         _e_active_menus = eina_list_append(_e_active_menus, m);
1950         if (!m->in_active_list)
1951           e_object_ref(E_OBJECT(m));
1952         m->in_active_list = 1;
1953         m->active = 1;
1954      }
1955    /* the foreign menu items */
1956    if (m->category)
1957      {
1958         cat = eina_hash_find(_e_menu_categories, m->category);
1959         if (cat)
1960           {
1961              E_Menu_Category_Callback *cb;
1962              EINA_LIST_FOREACH(cat->callbacks, l, cb)
1963                if (cb->create) cb->create(cb->data, m, cat->data);
1964           }
1965      }
1966    m->cur.visible = 1;
1967 }
1968 
1969 static void
_e_menu_deactivate_all(void)1970 _e_menu_deactivate_all(void)
1971 {
1972    Eina_List *tmp;
1973    E_Menu *m;
1974 
1975    tmp = _e_active_menus_copy_ref();
1976 
1977    EINA_LIST_FREE(tmp, m)
1978      {
1979         e_menu_deactivate(m);
1980         m->parent_item = NULL;
1981         e_object_unref(E_OBJECT(m));
1982      }
1983    _e_menu_activate_floating = 0;
1984    _e_menu_activate_maybe_drag = 0;
1985    _e_menu_activate_dragging = 0;
1986 }
1987 
1988 static void
_e_menu_deactivate_above(E_Menu * ma)1989 _e_menu_deactivate_above(E_Menu *ma)
1990 {
1991    Eina_List *tmp;
1992    int above = 0;
1993    E_Menu *m;
1994 
1995    tmp = _e_active_menus_copy_ref();
1996 
1997    EINA_LIST_FREE(tmp, m)
1998      {
1999         if (above)
2000           {
2001              e_menu_deactivate(m);
2002              m->parent_item = NULL;
2003           }
2004         if (ma == m) above = 1;
2005         e_object_unref(E_OBJECT(m));
2006      }
2007 }
2008 
2009 static void
_e_menu_submenu_activate(E_Menu_Item * mi)2010 _e_menu_submenu_activate(E_Menu_Item *mi)
2011 {
2012    if (!mi->menu->active) return;
2013    if (mi->submenu && mi->submenu->active) return;
2014    if (mi->menu->fast_mouse)
2015      {
2016         mi->menu->pending_new_submenu = 1;
2017         return;
2018      }
2019    mi->menu->pending_new_submenu = 0;
2020    _e_menu_deactivate_above(mi->menu);
2021    if (mi->submenu_pre_cb.func)
2022      mi->submenu_pre_cb.func(mi->submenu_pre_cb.data, mi->menu, mi);
2023    if (mi->submenu)
2024      {
2025         E_Menu *m;
2026 
2027         m = mi->submenu;
2028         e_object_ref(E_OBJECT(m));
2029         m->parent_item = mi;
2030         _e_menu_activate_internal(m, mi->menu->zone);
2031         _e_menu_reposition(m);
2032         e_object_unref(E_OBJECT(m));
2033         mi->menu->have_submenu = 1;
2034      }
2035 }
2036 
2037 static void
_e_menu_submenu_deactivate(E_Menu_Item * mi)2038 _e_menu_submenu_deactivate(E_Menu_Item *mi)
2039 {
2040    if (!mi->menu->active) return;
2041    mi->menu->have_submenu = 0;
2042    if (mi->submenu_post_cb.func)
2043      mi->submenu_post_cb.func(mi->submenu_post_cb.data, mi->menu, mi);
2044 }
2045 
2046 static void
_e_menu_reposition(E_Menu * m)2047 _e_menu_reposition(E_Menu *m)
2048 {
2049    Eina_List *l, *tmp;
2050    E_Menu_Item *mi;
2051    int parent_item_bottom;
2052 
2053    if (!m->zone) return;
2054    if (!m->parent_item) return;
2055    m->cur.x = m->parent_item->menu->cur.x + m->parent_item->menu->cur.w;
2056 
2057    parent_item_bottom = m->parent_item->y;
2058    if (m->cur.h > m->zone->h)
2059      {
2060 #if 0 // we can't win - we just flip back and forth, so let it go off and use scrolling
2061         /* menu is larger than screen */
2062         if (parent_item_bottom > (m->zone->y + (m->zone->h / 2)))
2063           /* more is shown if menu goes up */
2064           m->cur.y = (parent_item_bottom - (m->zone->h + 1));
2065         else
2066           /* more is shown if menu goes down */
2067           m->cur.y = parent_item_bottom - m->zone->y;
2068 #endif
2069      }
2070    else
2071      {
2072         /* menu is on top or bottom half of screen */
2073         if (parent_item_bottom > (m->zone->y + (m->zone->h / 2)))
2074           m->cur.y = parent_item_bottom - m->cur.h + m->parent_item->h;
2075         else
2076           m->cur.y = parent_item_bottom;
2077      }
2078 
2079    /* FIXME: this will suck for big menus */
2080    tmp = _e_active_menus_copy_ref();
2081 
2082    EINA_LIST_FOREACH(m->items, l, mi)
2083      if ((mi->active) && (mi->submenu)) _e_menu_reposition(mi->submenu);
2084 
2085    _e_menu_list_free_unref(tmp);
2086 }
2087 
2088 static int
_e_menu_active_call(void)2089 _e_menu_active_call(void)
2090 {
2091    E_Menu_Item *mi;
2092 
2093    mi = _e_menu_item_active_get();
2094    if (mi)
2095      {
2096         if (mi->check)
2097           e_menu_item_toggle_set(mi, !mi->toggle);
2098         if ((mi->radio) && (!e_menu_item_toggle_get(mi)))
2099           e_menu_item_toggle_set(mi, 1);
2100         if (mi->cb.func)
2101           mi->cb.func(mi->cb.data, mi->menu, mi);
2102         return 1;
2103      }
2104    return -1;
2105 }
2106 
2107 static int
_e_menu_realize_call(E_Menu_Item * mi)2108 _e_menu_realize_call(E_Menu_Item *mi)
2109 {
2110    if (mi)
2111      {
2112         if (mi->realize_cb.func)
2113           {
2114              mi->realize_cb.func(mi->realize_cb.data, mi->menu, mi);
2115              return 1;
2116           }
2117      }
2118    return 0;
2119 }
2120 
2121 static void
_e_menu_item_activate_next(void)2122 _e_menu_item_activate_next(void)
2123 {
2124    E_Menu_Item *mi;
2125    Eina_List *ll;
2126 
2127    ll = _e_menu_list_item_active_get();
2128    mi = _e_menu_item_active_get();
2129    if (ll && mi)
2130      {
2131         /* Look at the next item and then cycle until we're not on
2132          * a separator. */
2133         do
2134           {
2135              if (!eina_list_next(ll))
2136                ll = mi->menu->items;
2137              else
2138                ll = eina_list_next(ll);
2139              mi = eina_list_data_get(ll);
2140           }
2141         while (mi->separator || mi->disable);
2142 
2143         e_menu_item_active_set(mi, 1);
2144         _e_menu_item_ensure_onscreen(mi);
2145         return;
2146      }
2147 
2148    _e_menu_activate_first();
2149 }
2150 
2151 static void
_e_menu_item_activate_previous(void)2152 _e_menu_item_activate_previous(void)
2153 {
2154    E_Menu_Item *mi;
2155    Eina_List *ll;
2156 
2157    ll = _e_menu_list_item_active_get();
2158    mi = _e_menu_item_active_get();
2159    if (ll && mi)
2160      {
2161         /* Look at the prev item and then cycle until we're not on
2162          * a separator. */
2163         do
2164           {
2165              if (!eina_list_prev(ll))
2166                ll = eina_list_last(ll);
2167              else
2168                ll = eina_list_prev(ll);
2169              mi = eina_list_data_get(ll);
2170           }
2171         while ((mi->separator) || (mi->disable));
2172 
2173         e_menu_item_active_set(mi, 1);
2174         _e_menu_item_ensure_onscreen(mi);
2175         return;
2176      }
2177 
2178    _e_menu_activate_first();
2179 }
2180 
2181 static void
_e_menu_item_activate_first(void)2182 _e_menu_item_activate_first(void)
2183 {
2184    E_Menu *m;
2185    Eina_List *ll;
2186    E_Menu_Item *mi;
2187 
2188    m = _e_menu_active_get();
2189    if (m)
2190      {
2191         ll = m->items;
2192         mi = eina_list_data_get(ll);
2193         while ((mi->separator) && eina_list_next(ll))
2194           {
2195              ll = eina_list_next(ll);
2196              mi = eina_list_data_get(ll);
2197           }
2198         if (mi->separator) return;
2199         e_menu_item_active_set(mi, 1);
2200         _e_menu_item_ensure_onscreen(mi);
2201         return;
2202      }
2203    _e_menu_activate_first();
2204 }
2205 
2206 static void
_e_menu_item_activate_last(void)2207 _e_menu_item_activate_last(void)
2208 {
2209    E_Menu *m;
2210    Eina_List *ll;
2211    E_Menu_Item *mi;
2212 
2213    m = _e_menu_active_get();
2214    if (m)
2215      {
2216         ll = eina_list_last(m->items);
2217         mi = eina_list_data_get(ll);
2218         while ((mi->separator) && eina_list_prev(ll))
2219           {
2220              ll = eina_list_prev(ll);
2221              mi = eina_list_data_get(ll);
2222           }
2223         if (mi->separator) return;
2224         e_menu_item_active_set(mi, 1);
2225         _e_menu_item_ensure_onscreen(mi);
2226         return;
2227      }
2228    _e_menu_activate_first();
2229 }
2230 
2231 static void
_e_menu_item_activate_nth(int n)2232 _e_menu_item_activate_nth(int n)
2233 {
2234    E_Menu *m;
2235    E_Menu_Item *mi;
2236    Eina_List *ll;
2237    int i = -1;
2238 
2239    mi = _e_menu_item_active_get();
2240    if (!mi)
2241      {
2242         _e_menu_activate_first();
2243         mi = _e_menu_item_active_get();
2244         if (!mi) return;
2245      }
2246    m = mi->menu;
2247    EINA_LIST_FOREACH(m->items, ll, mi)
2248      {
2249         if (!mi->separator) i++;
2250         if (i == n) break;
2251      }
2252    if (!mi) return;
2253    e_menu_item_active_set(mi, 1);
2254    _e_menu_item_ensure_onscreen(mi);
2255 }
2256 
2257 static void
_e_menu_item_activate_char(const char * key_compose)2258 _e_menu_item_activate_char(const char *key_compose)
2259 {
2260    E_Menu *m;
2261    E_Menu_Item *mi;
2262    Eina_List *ll, *ll_orig;
2263 
2264    /* Ignore modifiers and such. */
2265    if (!key_compose) return;
2266 
2267    /* Check we've got a menu and it's active. */
2268    m = _e_menu_active_get();
2269    if (!m)
2270      {
2271         if (!_e_active_menus) return;
2272         m = eina_list_data_get(_e_active_menus);
2273         if (!m) return;
2274      }
2275 
2276    ll = _e_menu_list_item_active_get();
2277    /* If we don't have an active item, start from the top of the list. */
2278    if (!ll)
2279      {
2280         ll = m->items;
2281         mi = eina_list_data_get(ll);
2282         /* Only check the current item if it wasn't active before. */
2283         if (!mi->separator && mi->label && !strncasecmp(key_compose, mi->label, strlen(key_compose)))
2284           {
2285              e_menu_item_active_set(mi, 1);
2286              _e_menu_item_ensure_onscreen(mi);
2287              return;
2288           }
2289      }
2290 
2291    ll_orig = ll;
2292 
2293    mi = eina_list_data_get(ll);
2294    if (!eina_list_next(ll))
2295      ll = mi->menu->items;
2296    else
2297      ll = eina_list_next(ll);
2298    mi = eina_list_data_get(ll);
2299 
2300    /* While we don't have a label OR we don't match  AND we haven't
2301     * wrapped around */
2302    while ((!mi->label || strncasecmp(key_compose, mi->label, strlen(key_compose)))
2303           && ll != ll_orig)
2304      {
2305         do
2306           {
2307              if (!eina_list_next(ll))
2308                ll = mi->menu->items;
2309              else
2310                ll = eina_list_next(ll);
2311              mi = eina_list_data_get(ll);
2312           }
2313         while (mi->separator);
2314      }
2315 
2316    e_menu_item_active_set(mi, 1);
2317    _e_menu_item_ensure_onscreen(mi);
2318    return;
2319 }
2320 
2321 static void
_e_menu_activate_next(void)2322 _e_menu_activate_next(void)
2323 {
2324    E_Menu_Item *mi;
2325 
2326    mi = _e_menu_item_active_get();
2327    if (mi)
2328      {
2329         if (mi->submenu)
2330           {
2331              if (mi->submenu->items)
2332                {
2333                   Eina_List *l;
2334                   EINA_LIST_FOREACH(mi->submenu->items, l, mi)
2335                     if (!mi->disable)
2336                       {
2337                          e_menu_item_active_set(mi, 1);
2338                          _e_menu_item_ensure_onscreen(mi);
2339                          break;
2340                       }
2341                }
2342           }
2343         return;
2344      }
2345    _e_menu_activate_first();
2346 }
2347 
2348 static void
_e_menu_activate_previous(void)2349 _e_menu_activate_previous(void)
2350 {
2351    E_Menu_Item *mi;
2352 
2353    mi = _e_menu_item_active_get();
2354    if (mi)
2355      {
2356         if (mi->menu->parent_item)
2357           {
2358              mi = mi->menu->parent_item;
2359              e_menu_item_active_set(mi, 1);
2360              _e_menu_item_ensure_onscreen(mi);
2361           }
2362         return;
2363      }
2364    _e_menu_activate_last();
2365 }
2366 
2367 static void
_e_menu_activate_first(void)2368 _e_menu_activate_first(void)
2369 {
2370    E_Menu *m;
2371    E_Menu_Item *mi;
2372    Eina_List *ll;
2373 
2374    if (!_e_active_menus) return;
2375    m = eina_list_data_get(_e_active_menus);
2376    if (!m->items) return;
2377    ll = m->items;
2378    mi = eina_list_data_get(ll);
2379    while ((mi->separator) && eina_list_next(ll))
2380      {
2381         ll = eina_list_next(ll);
2382         mi = eina_list_data_get(ll);
2383      }
2384    if (mi->separator) return;
2385    e_menu_item_active_set(mi, 1);
2386    _e_menu_item_ensure_onscreen(mi);
2387 }
2388 
2389 static void
_e_menu_activate_last(void)2390 _e_menu_activate_last(void)
2391 {
2392    E_Menu *m;
2393    E_Menu_Item *mi;
2394    Eina_List *ll;
2395 
2396    if (!_e_active_menus) return;
2397    m = eina_list_data_get(_e_active_menus);
2398    if (!m->items) return;
2399    ll = eina_list_last(m->items);
2400    mi = eina_list_data_get(ll);
2401    while ((mi->separator) && eina_list_prev(ll))
2402      {
2403         ll = eina_list_prev(ll);
2404         mi = eina_list_data_get(ll);
2405      }
2406    if (mi->separator) return;
2407    e_menu_item_active_set(mi, 1);
2408    _e_menu_item_ensure_onscreen(mi);
2409 }
2410 
2411 #if 0
2412 static void
2413 _e_menu_activate_nth(int n)
2414 {
2415    E_Menu *m;
2416    E_Menu_Item *mi;
2417    Eina_List *ll;
2418    int i = -1;
2419 
2420    mi = _e_menu_item_active_get();
2421    if (!mi)
2422      {
2423         _e_menu_activate_first();
2424         mi = _e_menu_item_active_get();
2425         if (!mi) return;
2426      }
2427    m = mi->menu;
2428    EINA_LIST_FOREACH(m->items, ll, mi)
2429      {
2430         if (!mi->separator) i++;
2431         if (i == n)
2432           {
2433              e_menu_item_active_set(mi, 1);
2434              _e_menu_item_ensure_onscreen(mi);
2435              return;
2436           }
2437      }
2438 }
2439 
2440 #endif
2441 
2442 static E_Menu *
_e_menu_active_get(void)2443 _e_menu_active_get(void)
2444 {
2445    if (_e_active_menu_item) return _e_active_menu_item->menu;
2446    return NULL;
2447 }
2448 
2449 static E_Menu_Item *
_e_menu_item_active_get(void)2450 _e_menu_item_active_get(void)
2451 {
2452    return _e_active_menu_item;
2453 }
2454 
2455 static Eina_List *
_e_menu_list_item_active_get(void)2456 _e_menu_list_item_active_get(void)
2457 {
2458    if (_e_active_menu_item)
2459      return _e_active_menu_item->list_position;
2460    else
2461      return NULL;
2462 }
2463 
2464 static int
_e_menu_outside_bounds_get(int xdir,int ydir)2465 _e_menu_outside_bounds_get(int xdir, int ydir)
2466 {
2467    Eina_List *l;
2468    E_Menu *m;
2469    int outl = 0;
2470    int outr = 0;
2471    int outt = 0;
2472    int outb = 0;
2473    int i = 0;
2474 
2475    EINA_LIST_FOREACH(_e_active_menus, l, m)
2476      {
2477         if (!m->zone) continue;
2478         if (m->cur.x < m->zone->x + e_config->menu_autoscroll_margin)
2479           {
2480              i = m->zone->x - m->cur.x + e_config->menu_autoscroll_margin;
2481              if (i > outl) outl = i;
2482           }
2483         if (m->cur.y < m->zone->y + e_config->menu_autoscroll_margin)
2484           {
2485              i = m->zone->y - m->cur.y + e_config->menu_autoscroll_margin;
2486              if (i > outt) outt = i;
2487           }
2488         if ((m->cur.x + m->cur.w) > (m->zone->w - e_config->menu_autoscroll_margin))
2489           {
2490              i = m->cur.x + m->cur.w - (m->zone->x + m->zone->w - e_config->menu_autoscroll_margin);
2491              if (i > outr) outr = i;
2492           }
2493         if ((m->cur.y + m->cur.h) > (m->zone->h - e_config->menu_autoscroll_margin))
2494           {
2495              i = m->cur.y + m->cur.h - (m->zone->y + m->zone->h - e_config->menu_autoscroll_margin);
2496              if (i > outb) outb = i;
2497           }
2498      }
2499    if (xdir == -1)
2500      {
2501         if (outl) return outl;
2502      }
2503    else if (xdir == 1)
2504      {
2505         if (outr) return outr;
2506      }
2507    else if (ydir == -1)
2508      {
2509         if (outt) return outt;
2510      }
2511    else if (ydir == 1)
2512      {
2513         if (outb) return outb;
2514      }
2515    return 0;
2516 }
2517 
2518 static void
_e_menu_scroll_by(int dx,int dy)2519 _e_menu_scroll_by(int dx, int dy)
2520 {
2521    Eina_List *l;
2522    E_Menu *m;
2523 
2524    EINA_LIST_FOREACH(_e_active_menus, l, m)
2525      {
2526         m->cur.x += dx;
2527         m->cur.y += dy;
2528      }
2529 }
2530 
2531 static void
_e_menu_mouse_autoscroll_check(void)2532 _e_menu_mouse_autoscroll_check(void)
2533 {
2534    int autoscroll_x = 0;
2535    int autoscroll_y = 0;
2536    E_Menu *m = NULL;
2537    int mx, my;
2538 
2539    mx = _e_menu_x;
2540    my = _e_menu_y;
2541    if (_e_active_menus)
2542      {
2543         m = eina_list_data_get(_e_active_menus);
2544         if ((m) && (m->zone))
2545           {
2546              mx -= m->zone->x;
2547              my -= m->zone->y;
2548           }
2549      }
2550    if (mx - e_config->menu_autoscroll_cursor_margin <= 0)
2551      {
2552         if (_e_menu_outside_bounds_get(-1, 0)) autoscroll_x = -1;
2553      }
2554    if (my - e_config->menu_autoscroll_cursor_margin <= 0)
2555      {
2556         if (_e_menu_outside_bounds_get(0, -1)) autoscroll_y = -1;
2557      }
2558    if ((!autoscroll_x) && (!autoscroll_y))
2559      {
2560         if ((m) && (m->zone))
2561           {
2562              if (mx + e_config->menu_autoscroll_cursor_margin >= (m->zone->w - 1))
2563                {
2564                   if (_e_menu_outside_bounds_get(1, 0)) autoscroll_x = 1;
2565                }
2566              if (my + e_config->menu_autoscroll_cursor_margin >= (m->zone->h - 1))
2567                {
2568                   if (_e_menu_outside_bounds_get(0, 1)) autoscroll_y = 1;
2569                }
2570           }
2571      }
2572    _e_menu_autoscroll_x = autoscroll_x;
2573    _e_menu_autoscroll_y = autoscroll_y;
2574    if ((!autoscroll_x) && (!autoscroll_y)) return;
2575    if (_e_menu_scroll_animator) return;
2576    _e_menu_scroll_animator = ecore_animator_add(_e_menu_cb_scroll_animator,
2577                                                 NULL);
2578    _e_menu_scroll_start = ecore_loop_time_get();
2579 }
2580 
2581 static void
_e_menu_item_ensure_onscreen(E_Menu_Item * mi)2582 _e_menu_item_ensure_onscreen(E_Menu_Item *mi)
2583 {
2584    int x = 0, y = 0, w = 0, h = 0;
2585    int dx = 0, dy = 0;
2586 
2587    if (!mi->menu) return;
2588    if (!mi->menu->zone) return;
2589    evas_object_geometry_get(mi->container_object, &x, &y, &w, &h);
2590    if ((x + w) > (mi->menu->zone->x + mi->menu->zone->w))
2591      dx = (mi->menu->zone->x + mi->menu->zone->w) - (x + w);
2592    else if (x < mi->menu->zone->x)
2593      dx = mi->menu->zone->x - x;
2594    if ((y + h) > (mi->menu->zone->y + mi->menu->zone->h))
2595      dy = (mi->menu->zone->y + mi->menu->zone->h) - (y + h);
2596    else if (y < mi->menu->zone->y)
2597      dy = mi->menu->zone->y - y;
2598    if ((dx != 0) || (dy != 0))
2599      _e_menu_scroll_by(dx, dy);
2600 }
2601 
2602 static void
_e_menu_auto_place_vert(E_Menu * m,int x,int y,int w,int h)2603 _e_menu_auto_place_vert(E_Menu *m, int x, int y, int w, int h)
2604 {
2605    int zx, zy, zw, zh;
2606 
2607    if (!m->zone) return;
2608    e_zone_useful_geometry_get(m->zone, &zx, &zy, &zw, &zh);
2609    if (E_CONTAINS(zx, zy, zw, zh, m->cur.x, y, m->cur.w, m->cur.h))
2610      {
2611         if (w + h > 2)
2612           {
2613              if (E_INTERSECTS(m->cur.x, y, m->cur.w, m->cur.h, x, y, w, h))
2614                m->cur.y = y + h - m->cur.h;
2615              else
2616                m->cur.y = y;
2617           }
2618         else
2619           m->cur.y = y;
2620      }
2621    else
2622      m->cur.y = y + h - m->cur.h;
2623 }
2624 
2625 static int
_e_menu_auto_place(E_Menu * m,int x,int y,int w,int h)2626 _e_menu_auto_place(E_Menu *m, int x, int y, int w, int h)
2627 {
2628    double xr, yr;
2629 
2630    _e_menu_realize(m);
2631    /* +-----+
2632     * |\ T /|
2633     * | \ / |
2634     * |L X R|
2635     * | / \ |
2636     * |/ B \|
2637     * +-----+
2638     *
2639     * quadrants... which one
2640     */
2641    if (!m->zone) return 0;
2642    if (w != m->zone->w)
2643      xr = (double)(x - m->zone->x) /
2644        (double)(m->zone->w - w);
2645    else
2646      xr = 0.0;
2647    if (h != m->zone->h)
2648      yr = (double)(y - m->zone->y) /
2649        (double)(m->zone->h - h);
2650    else
2651      yr = 0.0;
2652 
2653    if ((xr + yr) < 0.99) /* top or left */
2654      {
2655         if (((1.0 - yr) + xr) <= 1.0)
2656           {
2657              /* L */
2658              m->cur.x = x + w;
2659              _e_menu_auto_place_vert(m, x, y, w, h);
2660              return 1;
2661           }
2662         else
2663           {
2664              /* T */
2665              m->cur.y = y + h;
2666              if (x < (m->zone->x + ((m->zone->w * 1) / 3)))
2667                m->cur.x = x;
2668              else if (x < (m->zone->x + ((m->zone->w * 2) / 3)))
2669                m->cur.x = x + ((w - m->cur.w) / 2);
2670              else
2671                m->cur.x = x + w - m->cur.w;
2672              return 3;
2673           }
2674      }
2675    else /* bottom or right */
2676      {
2677         if (((1.0 - yr) + xr) <= 1.01)
2678           {
2679              /* B */
2680              m->cur.y = y - m->cur.h;
2681              if (x < (m->zone->x + ((m->zone->w * 1) / 3)))
2682                m->cur.x = x;
2683              else if (x < (m->zone->x + ((m->zone->w * 2) / 3)))
2684                m->cur.x = x + ((w - m->cur.w) / 2);
2685              else
2686                m->cur.x = x + w - m->cur.w;
2687              return 4;
2688           }
2689         else
2690           {
2691              /* R */
2692              m->cur.x = x - m->cur.w;
2693              _e_menu_auto_place_vert(m, x, y, w, h);
2694              return 2;
2695           }
2696      }
2697    return 0;
2698 }
2699 
2700 static void
_e_menu_cb_item_in(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)2701 _e_menu_cb_item_in(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
2702 {
2703    E_Menu_Item *mi = data;
2704 
2705    if (_e_menu_lock) return;
2706    // ignore in/out not due to deliberate mouse move by user
2707    if (_e_menu_nav_by != NAV_BY_MOUSE) return;
2708    /* this can be triggered when creating menus if the new menu is on top of its parent */
2709    if (!mi->menu->realized) return;
2710    e_menu_item_active_set(mi, 1);
2711 }
2712 
2713 static void
_e_menu_cb_item_out(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)2714 _e_menu_cb_item_out(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
2715 {
2716    E_Menu_Item *mi = data;
2717    // ignore in/out not due to deliberate mouse move by user
2718    if (_e_menu_nav_by != NAV_BY_MOUSE) return;
2719    /* this can be triggered when creating menus if the new menu is on top of its parent */
2720    if (!mi->menu->realized) return;
2721    e_menu_item_active_set(mi, 0);
2722 }
2723 
2724 static Eina_Bool
_e_menu_cb_key_down(void * data EINA_UNUSED,Ecore_Event_Key * ev)2725 _e_menu_cb_key_down(void *data EINA_UNUSED, Ecore_Event_Key *ev)
2726 {
2727    _e_menu_nav_by = NAV_BY_KEY;
2728    if ((!strcmp(ev->key, "Up")) || (!strcmp(ev->key, "KP_Up")))
2729      _e_menu_item_activate_previous();
2730    else if ((!strcmp(ev->key, "Down")) || (!strcmp(ev->key, "KP_Down")))
2731      _e_menu_item_activate_next();
2732    else if ((!strcmp(ev->key, "Left")) || (!strcmp(ev->key, "KP_Left")))
2733      _e_menu_activate_previous();
2734    else if ((!strcmp(ev->key, "Right")) || (!strcmp(ev->key, "KP_Right")))
2735      _e_menu_activate_next();
2736    else if ((!strcmp(ev->key, "Home")) || (!strcmp(ev->key, "KP_Home")))
2737      _e_menu_item_activate_first();
2738    else if ((!strcmp(ev->key, "End")) || (!strcmp(ev->key, "KP_End")))
2739      _e_menu_item_activate_last();
2740    else if (!strcmp(ev->key, "space"))
2741      _e_menu_active_call();
2742    else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
2743      {
2744         _e_menu_active_call();
2745         _e_menu_deactivate_all();
2746      }
2747    else if (!strcmp(ev->key, "Escape"))
2748      _e_menu_deactivate_all();
2749    else if ((!strcmp(ev->key, "1")) || (!strcmp(ev->key, "KP_1")))
2750      _e_menu_item_activate_first();
2751    else if ((!strcmp(ev->key, "2")) || (!strcmp(ev->key, "KP_2")))
2752      _e_menu_item_activate_nth(1);
2753    else if ((!strcmp(ev->key, "3")) || (!strcmp(ev->key, "KP_3")))
2754      _e_menu_item_activate_nth(2);
2755    else if ((!strcmp(ev->key, "4")) || (!strcmp(ev->key, "KP_4")))
2756      _e_menu_item_activate_nth(3);
2757    else if ((!strcmp(ev->key, "5")) || (!strcmp(ev->key, "KP_5")))
2758      _e_menu_item_activate_nth(4);
2759    else if ((!strcmp(ev->key, "6")) || (!strcmp(ev->key, "KP_6")))
2760      _e_menu_item_activate_nth(5);
2761    else if ((!strcmp(ev->key, "7")) || (!strcmp(ev->key, "KP_7")))
2762      _e_menu_item_activate_nth(6);
2763    else if ((!strcmp(ev->key, "8")) || (!strcmp(ev->key, "KP_8")))
2764      _e_menu_item_activate_nth(7);
2765    else if ((!strcmp(ev->key, "9")) || (!strcmp(ev->key, "KP_9")))
2766      _e_menu_item_activate_nth(8);
2767    else if ((!strcmp(ev->key, "0")) || (!strcmp(ev->key, "KP_0")))
2768      _e_menu_item_activate_last();
2769    else if (ev->compose)
2770      _e_menu_item_activate_char(ev->compose);
2771    return ECORE_CALLBACK_PASS_ON;
2772 }
2773 
2774 /* we need all of these because menus are special and grab the mouse and
2775  * keyboard and thus the normal event mechanism doesn't work, so we feed
2776  * events directly to the canvases from our grab window
2777  */
2778 
2779 static void
_e_menu_cb_mouse_evas_down(void * data,Evas_Object * obj EINA_UNUSED)2780 _e_menu_cb_mouse_evas_down(void *data, Evas_Object *obj EINA_UNUSED)
2781 {
2782    E_Menu *m = data;
2783 
2784    while (m->parent_item)
2785      m = m->parent_item->menu;
2786    e_menu_deactivate(m);
2787 }
2788 
2789 static Eina_Bool
_e_menu_cb_mouse_down(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)2790 _e_menu_cb_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
2791 {
2792    Ecore_Event_Mouse_Button *ev;
2793 
2794    ev = event;
2795    _e_menu_nav_by = NAV_BY_MOUSE;
2796    if (ev->window != _e_menu_win)
2797      {
2798         if (_e_menu_active_get())
2799           _e_menu_deactivate_all();
2800         return ECORE_CALLBACK_PASS_ON;
2801      }
2802 
2803    _e_menu_lock = 1;
2804    e_comp_canvas_feed_mouse_up(0);
2805    _e_menu_lock = 0;
2806 
2807    /* Only allow dragging from floating menus for now.
2808     * The reason for this is that for non floating menus,
2809     * the mouse is already down and dragging, so the decision
2810     * to start a drag is much more complex.
2811     */
2812    if (_e_menu_activate_floating)
2813      _e_menu_activate_maybe_drag = 1;
2814 
2815    return ECORE_CALLBACK_PASS_ON;
2816 }
2817 
2818 static Eina_Bool
_e_menu_cb_mouse_up(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)2819 _e_menu_cb_mouse_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
2820 {
2821    Ecore_Event_Mouse_Button *ev;
2822    E_Menu *m;
2823    Eina_List *l;
2824    unsigned int t;
2825    int ret = 0;
2826 
2827    if (_e_menu_lock) return ECORE_CALLBACK_RENEW;
2828    ev = event;
2829    if (ev->window != _e_menu_win) return ECORE_CALLBACK_RENEW;
2830 
2831    _e_menu_nav_by = NAV_BY_MOUSE;
2832    if (!_e_menu_activate_floating)
2833      {
2834         EINA_LIST_FOREACH(_e_active_menus, l, m)
2835           {
2836              if (!m->hold_mode)
2837                {
2838                   _e_menu_activate_floating = 1;
2839                   return ECORE_CALLBACK_PASS_ON;
2840                }
2841           }
2842      }
2843 
2844    t = ev->timestamp - _e_menu_activate_time;
2845    if ((_e_menu_activate_time != 0) &&
2846        (t < (e_config->menus_click_drag_timeout * 1000)))
2847      {
2848         _e_menu_activate_floating = 1;
2849         return ECORE_CALLBACK_PASS_ON;
2850      }
2851 
2852    if (_e_menu_activate_dragging)
2853      {
2854         /* FIXME: This is a drop, which is not allowed for now.
2855          * Once dragging is working, this will be subject to some experimentation.
2856          */
2857      }
2858    else
2859      {
2860         E_Menu_Item *mi;
2861 
2862         mi = _e_menu_item_active_get();
2863         if ((!mi) ||
2864             (E_INSIDE(e_comp_canvas_x_root_adjust(ev->root.x),
2865                       e_comp_canvas_y_root_adjust(ev->root.y),
2866                       mi->x, mi->y, mi->w, mi->h))
2867            )
2868           ret = _e_menu_active_call();
2869      }
2870    _e_menu_activate_maybe_drag = 0;
2871    _e_menu_activate_dragging = 0;
2872    if (ret == 1)
2873      {
2874 /* allow mouse to pop down menu if clicked elsewhere */
2875 /*	if (_e_menu_activate_time != 0) */
2876         _e_menu_deactivate_all();
2877      }
2878    else if (ret == -1)
2879      _e_menu_deactivate_all();
2880    else if (!_e_menu_activate_floating)
2881      _e_menu_deactivate_all();
2882    return ECORE_CALLBACK_PASS_ON;
2883 }
2884 
2885 static Eina_Bool
_e_menu_cb_mouse_move(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)2886 _e_menu_cb_mouse_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
2887 {
2888    Ecore_Event_Mouse_Move *ev;
2889    Eina_List *l, *tmp;
2890    E_Menu *m;
2891    int dx, dy, d;
2892    double dt;
2893    double fast_move_threshold;
2894    int is_fast = 0;
2895 
2896    ev = event;
2897    if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2898    _e_menu_nav_by = NAV_BY_MOUSE;
2899    fast_move_threshold = e_config->menus_fast_mouse_move_threshhold;
2900    dx = ev->x - _e_menu_x;
2901    dy = ev->y - _e_menu_y;
2902    d = (dx * dx) + (dy * dy);
2903    dt = (double)(ev->timestamp - _e_menu_time) / 1000.0;
2904    dt = dt * dt;
2905    if ((dt > 0.0) && ((d / dt) >= (fast_move_threshold * fast_move_threshold)))
2906      is_fast = 1;
2907 
2908    tmp = _e_active_menus_copy_ref();
2909 
2910    EINA_LIST_FOREACH(_e_active_menus, l, m)
2911      {
2912         if ((!m->realized) || (!m->cur.visible)) continue;
2913         if (is_fast)
2914           m->fast_mouse = 1;
2915         else if (dt > 0.0)
2916           {
2917              m->fast_mouse = 0;
2918              if (m->pending_new_submenu)
2919                {
2920                   E_Menu_Item *mi;
2921 
2922                   mi = _e_menu_item_active_get();
2923                   if (mi)
2924                     _e_menu_submenu_activate(mi);
2925                }
2926           }
2927        if (!_e_menu_activate_maybe_drag)
2928          /* this is useless while the mouse is down */
2929          evas_event_feed_mouse_move(m->evas, ev->x, ev->y, ev->timestamp, NULL);
2930      }
2931    if (_e_menu_activate_maybe_drag)
2932      {
2933         if (_e_active_menu_item)
2934           {
2935              if (!E_INSIDE(ev->x, ev->y, _e_active_menu_item->x, _e_active_menu_item->y, _e_active_menu_item->w, _e_active_menu_item->h))
2936                {
2937                   if (_e_active_menu_item->drag_cb.func)
2938                     {
2939                        /* User is dragging a draggable item elsewhere. */
2940                        _e_active_menu_item->drag.x = ev->x - (ev->x - _e_active_menu_item->x);
2941                        _e_active_menu_item->drag.y = ev->y - (ev->y - _e_active_menu_item->y);
2942                        _e_menu_deactivate_all();
2943                        _e_active_menu_item->drag_cb.func(_e_active_menu_item->drag_cb.data, _e_active_menu_item->menu, _e_active_menu_item);
2944                     }
2945                   /* Either way, the maybe drag stops here. */
2946                   _e_menu_activate_maybe_drag = 0;
2947                }
2948           }
2949      }
2950 
2951    _e_menu_list_free_unref(tmp);
2952 
2953    _e_menu_x = ev->x;
2954    _e_menu_y = ev->y;
2955    _e_menu_time = ev->timestamp;
2956    _e_menu_mouse_autoscroll_check();
2957    return ECORE_CALLBACK_PASS_ON;
2958 }
2959 
2960 static Eina_Bool
_e_menu_cb_mouse_wheel(void * data EINA_UNUSED,int type EINA_UNUSED,void * event)2961 _e_menu_cb_mouse_wheel(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
2962 {
2963    Ecore_Event_Mouse_Wheel *ev;
2964 
2965    ev = event;
2966    if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2967    _e_menu_nav_by = NAV_BY_WHEEL;
2968    if (ev->z < 0) /* up */
2969      {
2970         int i;
2971 
2972         for (i = ev->z; i < 0; i++)
2973           _e_menu_item_activate_previous();
2974      }
2975    else if (ev->z > 0) /* down */
2976      {
2977         int i;
2978 
2979         for (i = ev->z; i > 0; i--)
2980           _e_menu_item_activate_next();
2981      }
2982    return ECORE_CALLBACK_PASS_ON;
2983 }
2984 
2985 static Eina_Bool
_e_menu_cb_scroll_animator(void * data EINA_UNUSED)2986 _e_menu_cb_scroll_animator(void *data EINA_UNUSED)
2987 {
2988    double t, dt;
2989    double dx, dy;
2990    int out;
2991    double spd;
2992 
2993    t = ecore_loop_time_get();
2994    spd = e_config->menus_scroll_speed;
2995    dt = t - _e_menu_scroll_start;
2996    _e_menu_scroll_start = t;
2997    dx = 0;
2998    dy = 0;
2999    if (_e_menu_autoscroll_x)
3000      {
3001         out = _e_menu_outside_bounds_get(_e_menu_autoscroll_x, 0);
3002         dx = (-_e_menu_autoscroll_x) * spd * dt;
3003         if (_e_menu_autoscroll_x == -1)
3004           {
3005              if (dx > out) dx = out;
3006           }
3007         else
3008           {
3009              if (dx < -out) dx = -out;
3010           }
3011      }
3012    if (_e_menu_autoscroll_y)
3013      {
3014         out = _e_menu_outside_bounds_get(0, _e_menu_autoscroll_y);
3015         dy = (-_e_menu_autoscroll_y) * spd * dt;
3016         if (_e_menu_autoscroll_y == -1)
3017           {
3018              if (dy > out) dy = out;
3019           }
3020         else
3021           {
3022              if (dy < -out) dy = -out;
3023           }
3024      }
3025    _e_menu_scroll_by(dx, dy);
3026    _e_menu_mouse_autoscroll_check();
3027    if ((_e_menu_autoscroll_x == 0) && (_e_menu_autoscroll_y == 0))
3028      {
3029         _e_menu_scroll_animator = NULL;
3030         return 0;
3031      }
3032    return 1;
3033 }
3034 
3035 static void
_e_menu_cb_item_submenu_post_default(void * data EINA_UNUSED,E_Menu * m EINA_UNUSED,E_Menu_Item * mi)3036 _e_menu_cb_item_submenu_post_default(void *data EINA_UNUSED, E_Menu *m EINA_UNUSED, E_Menu_Item *mi)
3037 {
3038    if (!mi->submenu) return;
3039    e_menu_item_submenu_set(mi, NULL); // unis unrefs previous submenu
3040 }
3041 
3042 static void
_e_menu_category_free_cb(E_Menu_Category * cat)3043 _e_menu_category_free_cb(E_Menu_Category *cat)
3044 {
3045    E_FREE_LIST(cat->callbacks, free);
3046    free(cat);
3047 }
3048 
3049