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
23 /* local subsystem data types */
24 typedef struct _E_Menu_Category E_Menu_Category;
26 struct _E_Menu_Category
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);
59 static void _e_menu_activate_nth(int n);
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_ecore_evas_resize(Ecore_Evas *ee);
74 static void _e_menu_cb_item_in(void *data, Evas *evas, Evas_Object *obj, void *event_info);
75 static void _e_menu_cb_item_out(void *data, Evas *evas, Evas_Object *obj, void *event_info);
76 static Eina_Bool _e_menu_cb_key_down(void *data, int type, void *event);
77 static Eina_Bool _e_menu_cb_key_up(void *data, int type, void *event);
78 static Eina_Bool _e_menu_cb_mouse_down(void *data, int type, void *event);
79 static Eina_Bool _e_menu_cb_mouse_up(void *data, int type, void *event);
80 static Eina_Bool _e_menu_cb_mouse_move(void *data, int type, void *event);
81 static Eina_Bool _e_menu_cb_mouse_wheel(void *data, int type, void *event);
82 static Eina_Bool _e_menu_cb_scroll_animator(void *data);
83 static Eina_Bool _e_menu_cb_window_shape(void *data, int ev_type, void *ev);
84 static void _e_menu_cb_item_submenu_post_default(void *data, E_Menu *m, E_Menu_Item *mi);
85 static Eina_Bool _e_menu_categories_free_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata);
87 #define MAX_MENU_SIZE 2048
89 /* local subsystem globals */
90 static Ecore_X_Window _e_menu_win = 0;
91 static Eina_List *_e_active_menus = NULL;
92 static Eina_Hash *_e_menu_hash = NULL;
93 static E_Menu_Item *_e_active_menu_item = NULL;
94 static E_Menu_Item *_e_prev_active_menu_item = NULL;
95 /*static Eina_Hash *_e_menu_category_items = NULL;*/
96 static Eina_Hash *_e_menu_categories = NULL;
97 static Ecore_X_Time _e_menu_activate_time = 0;
98 static int _e_menu_activate_floating = 0;
99 static int _e_menu_activate_maybe_drag = 0;
100 static int _e_menu_activate_dragging = 0;
101 static Ecore_Animator *_e_menu_scroll_animator = NULL;
102 static double _e_menu_scroll_start = 0.0;
103 static int _e_menu_x = 0;
104 static int _e_menu_y = 0;
105 static Ecore_X_Time _e_menu_time = 0;
106 static int _e_menu_autoscroll_x = 0;
107 static int _e_menu_autoscroll_y = 0;
108 static Ecore_Event_Handler *_e_menu_key_down_handler = NULL;
109 static Ecore_Event_Handler *_e_menu_key_up_handler = NULL;
110 static Ecore_Event_Handler *_e_menu_mouse_down_handler = NULL;
111 static Ecore_Event_Handler *_e_menu_mouse_up_handler = NULL;
112 static Ecore_Event_Handler *_e_menu_mouse_move_handler = NULL;
113 static Ecore_Event_Handler *_e_menu_mouse_wheel_handler = NULL;
114 static Ecore_Event_Handler *_e_menu_window_shape_handler = NULL;
115 static Eina_Bool _e_menu_lock = EINA_FALSE;
118 _e_active_menus_copy_ref(void)
121 Eina_List *l, *ret = NULL;
123 EINA_LIST_FOREACH(_e_active_menus, l, o)
125 ret = eina_list_append(ret, o);
132 _e_menu_list_free_unref(Eina_List *l)
137 /* list must be freed in reverse to ensure that submenus
138 * (which are added to the end of the list)
139 * are deleted before their parents
141 EINA_LIST_REVERSE_FOREACH_SAFE(l, ll, lll, o)
144 l = eina_list_remove_list(l, ll);
149 /* macros for debugging menu refcounts */
151 #define e_object_ref(X) do {\
153 xx = e_object_ref(X); \
154 INF("REF: %p || %d", X, xx); \
156 #define e_object_unref(X) do {\
158 xx = e_object_unref(X); \
159 INF("UNREF: %p || %d", X, xx); \
163 /* externally accessible functions */
167 _e_menu_key_down_handler =
168 ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_menu_cb_key_down, NULL);
169 _e_menu_key_up_handler =
170 ecore_event_handler_add(ECORE_EVENT_KEY_UP, _e_menu_cb_key_up, NULL);
171 _e_menu_mouse_down_handler =
172 ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN,
173 _e_menu_cb_mouse_down, NULL);
174 _e_menu_mouse_up_handler =
175 ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
176 _e_menu_cb_mouse_up, NULL);
177 _e_menu_mouse_move_handler =
178 ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
179 _e_menu_cb_mouse_move, NULL);
180 _e_menu_mouse_wheel_handler =
181 ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL,
182 _e_menu_cb_mouse_wheel, NULL);
183 _e_menu_window_shape_handler =
184 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHAPE,
185 _e_menu_cb_window_shape, NULL);
186 _e_menu_categories = eina_hash_string_superfast_new(NULL);
188 if (!_e_menu_hash) _e_menu_hash = eina_hash_string_superfast_new(NULL);
193 e_menu_shutdown(void)
197 E_FN_DEL(ecore_event_handler_del, _e_menu_key_down_handler);
198 E_FN_DEL(ecore_event_handler_del, _e_menu_key_up_handler);
199 E_FN_DEL(ecore_event_handler_del, _e_menu_mouse_down_handler);
200 E_FN_DEL(ecore_event_handler_del, _e_menu_mouse_up_handler);
201 E_FN_DEL(ecore_event_handler_del, _e_menu_mouse_move_handler);
202 E_FN_DEL(ecore_event_handler_del, _e_menu_mouse_wheel_handler);
203 E_FN_DEL(ecore_event_handler_del, _e_menu_window_shape_handler);
207 EINA_LIST_FREE(_e_active_menus, m)
210 _e_menu_unrealize(m);
211 m->in_active_list = 0;
212 e_object_unref(E_OBJECT(m));
215 _e_active_menus = NULL;
216 if (_e_menu_categories)
218 eina_hash_foreach(_e_menu_categories, _e_menu_categories_free_cb, NULL);
219 eina_hash_free(_e_menu_categories);
220 _e_menu_categories = NULL;
225 eina_hash_free(_e_menu_hash);
228 _e_menu_lock = EINA_FALSE;
238 m = E_OBJECT_ALLOC(E_Menu, E_MENU_TYPE, _e_menu_free);
247 e_menu_activate_key(E_Menu *m, E_Zone *zone, int x, int y, int w, int h, int dir)
250 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
251 E_OBJECT_CHECK(zone);
252 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
253 _e_menu_activate_time = 0;
254 _e_menu_activate_floating = 0;
255 _e_menu_activate_internal(m, zone);
258 e_menu_deactivate(m);
263 case E_MENU_POP_DIRECTION_LEFT:
265 m->cur.x = x - m->cur.w;
267 if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
268 m->cur.y = y + h - m->cur.h;
269 _e_menu_activate_first();
272 case E_MENU_POP_DIRECTION_RIGHT:
275 _e_menu_activate_first();
278 case E_MENU_POP_DIRECTION_UP:
281 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
282 m->cur.x = x + w - m->cur.w;
283 m->cur.y = y - m->cur.h;
284 _e_menu_activate_last();
287 case E_MENU_POP_DIRECTION_DOWN:
290 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
291 m->cur.x = x + w - m->cur.w;
293 if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
294 m->cur.y = y + h - m->cur.h;
295 _e_menu_activate_first();
298 case E_MENU_POP_DIRECTION_AUTO:
302 pos = _e_menu_auto_place(m, x, y, w, h);
304 _e_menu_activate_last();
306 _e_menu_activate_first();
313 _e_menu_activate_first();
319 e_menu_activate_mouse(E_Menu *m, E_Zone *zone, int x, int y, int w, int h, int dir, Ecore_X_Time activate_time)
324 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
325 E_OBJECT_CHECK(zone);
326 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
327 _e_menu_activate_time = activate_time;
328 _e_menu_activate_floating = 0;
329 _e_menu_activate_internal(m, zone);
332 e_menu_deactivate(m);
337 case E_MENU_POP_DIRECTION_LEFT:
339 m->cur.x = x - m->cur.w;
341 if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
342 m->cur.y = y + h - m->cur.h;
345 case E_MENU_POP_DIRECTION_RIGHT:
351 case E_MENU_POP_DIRECTION_UP:
354 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
355 m->cur.x = x + w - m->cur.w;
356 m->cur.y = y - m->cur.h;
359 case E_MENU_POP_DIRECTION_DOWN:
362 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
363 m->cur.x = x + w - m->cur.w;
365 if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
366 m->cur.y = y + h - m->cur.h;
369 case E_MENU_POP_DIRECTION_AUTO:
370 _e_menu_auto_place(m, x, y, w, h);
378 pmi = _e_menu_item_active_get();
379 if (pmi) e_menu_item_active_set(pmi, 0);
383 e_menu_activate(E_Menu *m, E_Zone *zone, int x, int y, int w, int h, int dir)
388 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
389 E_OBJECT_CHECK(zone);
390 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
391 _e_menu_activate_time = 0;
392 _e_menu_activate_floating = 0;
393 _e_menu_activate_internal(m, zone);
396 e_menu_deactivate(m);
401 case E_MENU_POP_DIRECTION_LEFT:
403 m->cur.x = x - m->cur.w;
405 if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
406 m->cur.y = y + h - m->cur.h;
407 _e_menu_activate_first();
410 case E_MENU_POP_DIRECTION_RIGHT:
414 _e_menu_activate_first();
417 case E_MENU_POP_DIRECTION_UP:
420 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
421 m->cur.x = x + w - m->cur.w;
422 m->cur.y = y - m->cur.h;
423 _e_menu_activate_last();
426 case E_MENU_POP_DIRECTION_DOWN:
429 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
430 m->cur.x = x + w - m->cur.w;
432 if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
433 m->cur.y = y + h - m->cur.h;
434 _e_menu_activate_first();
437 case E_MENU_POP_DIRECTION_AUTO:
438 _e_menu_auto_place(m, x, y, w, h);
446 pmi = _e_menu_item_active_get();
447 if (pmi) e_menu_item_active_set(pmi, 0);
451 e_menu_deactivate(E_Menu *m)
454 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
457 if (m->post_deactivate_cb.func)
458 m->post_deactivate_cb.func(m->post_deactivate_cb.data, m);
462 e_menu_freeze(E_Menu *m)
464 E_OBJECT_CHECK_RETURN(m, 0);
465 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, 0);
471 e_menu_thaw(E_Menu *m)
473 E_OBJECT_CHECK_RETURN(m, 0);
474 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, 0);
476 if (m->frozen < 0) m->frozen = 0;
481 e_menu_title_set(E_Menu *m, const char *title)
484 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
485 if ((m->header.title) && (title) && (!strcmp(m->header.title, title)))
489 eina_stringshare_del(m->header.title);
490 m->header.title = NULL;
492 if (title) m->header.title = eina_stringshare_add(title);
493 else m->header.title = NULL;
495 edje_object_part_text_set(m->bg_object, "e.text.title", m->header.title);
497 edje_object_signal_emit(m->bg_object, "e,action,show,title", "e");
499 edje_object_signal_emit(m->bg_object, "e,action,hide,title", "e");
500 edje_object_message_signal_process(m->bg_object);
504 e_menu_icon_file_set(E_Menu *m __UNUSED__, const char *icon __UNUSED__)
506 /* FIXME: support menu icons
508 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
513 e_menu_category_set(E_Menu *m, const char *category)
516 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
519 eina_stringshare_del(m->category);
523 m->category = eina_stringshare_add(category);
530 e_menu_category_data_set(char *category, void *data)
532 E_Menu_Category *cat;
534 cat = eina_hash_find(_e_menu_categories, category);
537 else /* if it isn't found create the new hash */
539 cat = calloc(1, sizeof(E_Menu_Category));
541 eina_hash_add(_e_menu_categories, category, cat);
545 EAPI E_Menu_Category_Callback *
546 e_menu_category_callback_add(char *category, void (*create_cb)(E_Menu *m, void *category_data, void *data), void (*free_cb)(void *data), void *data)
548 E_Menu_Category *cat;
549 E_Menu_Category_Callback *cb = NULL;
551 cat = eina_hash_find(_e_menu_categories, category);
552 if (!cat) /* if it isn't found create the new hash */
554 cat = calloc(1, sizeof(E_Menu_Category));
555 eina_hash_add(_e_menu_categories, category, cat);
559 cb = calloc(1, sizeof(E_Menu_Category_Callback));
563 cb->create = create_cb;
565 cb->category = eina_stringshare_add(category);
566 cat->callbacks = eina_list_append(cat->callbacks, cb);
573 e_menu_category_callback_del(E_Menu_Category_Callback *cb)
575 E_Menu_Category *cat;
579 cat = eina_hash_find(_e_menu_categories, cb->category);
581 cat->callbacks = eina_list_remove(cat->callbacks, cb);
582 eina_stringshare_del(cb->category);
588 e_menu_pre_activate_callback_set(E_Menu *m, void (*func)(void *data, E_Menu *m), void *data)
591 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
592 m->pre_activate_cb.func = func;
593 m->pre_activate_cb.data = data;
597 e_menu_post_deactivate_callback_set(E_Menu *m, void (*func)(void *data, E_Menu *m), void *data)
600 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
601 m->post_deactivate_cb.func = func;
602 m->post_deactivate_cb.data = data;
606 e_menu_root_get(E_Menu *m)
610 E_OBJECT_CHECK_RETURN(m, NULL);
611 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
613 while ((ret->parent_item) && (ret->parent_item->menu))
614 ret = ret->parent_item->menu;
620 e_menu_item_new(E_Menu *m)
624 E_OBJECT_CHECK_RETURN(m, NULL);
625 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
626 mi = E_OBJECT_ALLOC(E_Menu_Item, E_MENU_ITEM_TYPE, _e_menu_item_free);
628 mi->menu->items = eina_list_append(mi->menu->items, mi);
629 mi->list_position = eina_list_last(mi->menu->items);
634 e_menu_item_new_relative(E_Menu *m, E_Menu_Item *rel)
637 E_OBJECT_CHECK_RETURN(m, NULL);
638 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
641 E_OBJECT_CHECK_RETURN(rel, NULL);
642 E_OBJECT_TYPE_CHECK_RETURN(rel, E_MENU_ITEM_TYPE, NULL);
643 if (rel->menu != m) return NULL;
646 mi = E_OBJECT_ALLOC(E_Menu_Item, E_MENU_ITEM_TYPE, _e_menu_item_free);
653 l = eina_list_data_find_list(m->items, rel);
654 m->items = eina_list_append_relative_list(m->items, mi, l);
655 mi->list_position = l->next;
659 m->items = eina_list_prepend(m->items, mi);
660 mi->list_position = m->items;
667 e_menu_item_nth(E_Menu *m, int n)
669 E_OBJECT_CHECK_RETURN(m, NULL);
670 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
671 return (E_Menu_Item *)eina_list_nth(m->items, n);
675 e_menu_item_num_get(const E_Menu_Item *mi)
678 const E_Menu_Item *mi2;
681 E_OBJECT_CHECK_RETURN(mi, -1);
682 E_OBJECT_CHECK_RETURN(mi->menu, -1);
683 E_OBJECT_TYPE_CHECK_RETURN(mi, E_MENU_TYPE, -1);
684 EINA_LIST_FOREACH(mi->menu->items, l, mi2)
686 if (mi2 == mi) return i;
693 e_menu_item_icon_file_set(E_Menu_Item *mi, const char *icon)
697 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
698 if (((mi->icon) && (icon) && (!strcmp(icon, mi->icon))) ||
699 ((!mi->icon) && (!icon)))
701 if (mi->icon) eina_stringshare_del(mi->icon);
702 if (mi->icon_key) eina_stringshare_del(mi->icon_key);
707 mi->icon = eina_stringshare_add(icon);
709 if ((len > 4) && (!strcasecmp(icon + len - 4, ".edj")))
710 mi->icon_key = eina_stringshare_add("icon");
713 mi->menu->changed = 1;
717 e_menu_item_icon_edje_set(E_Menu_Item *mi, const char *icon, const char *key)
720 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
721 if (((mi->icon) && (icon) && (!strcmp(icon, mi->icon))) ||
722 ((!mi->icon) && (!icon)) ||
723 ((key) && (mi->icon_key) && (!strcmp(key, mi->icon_key))))
725 if (mi->icon) eina_stringshare_del(mi->icon);
726 if (mi->icon_key) eina_stringshare_del(mi->icon_key);
729 if (icon) mi->icon = eina_stringshare_add(icon);
730 if (key) mi->icon_key = eina_stringshare_add(key);
732 mi->menu->changed = 1;
736 e_menu_item_label_set(E_Menu_Item *mi, const char *label)
739 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
740 if (((mi->label) && (label) && (!strcmp(label, mi->label))) ||
741 ((!mi->label) && (!label)))
743 if (mi->label) eina_stringshare_del(mi->label);
745 if (label) mi->label = eina_stringshare_add(label);
747 mi->menu->changed = 1;
751 e_menu_item_submenu_set(E_Menu_Item *mi, E_Menu *sub)
753 Eina_Bool submenu = EINA_FALSE;
757 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
758 submenu = !!mi->submenu;
759 if (mi->submenu) e_object_unref(E_OBJECT(mi->submenu));
760 if (sub) e_object_ref(E_OBJECT(sub));
763 mi->menu->changed = 1;
764 if (!!sub == submenu) return;
765 if (!mi->bg_object) return;
766 if (sub) e_object_ref(E_OBJECT(sub));
767 _e_menu_lock = EINA_TRUE;
768 if ((mi->submenu) || (mi->submenu_pre_cb.func))
770 if (mi->submenu_object) evas_object_del(mi->submenu_object);
771 o = edje_object_add(mi->menu->evas);
772 if (sub && (mi->submenu != sub)) e_object_ref(E_OBJECT(sub));
774 mi->submenu_object = o;
775 e_theme_edje_object_set(o, "base/theme/menus",
776 "e/widgets/menu/default/submenu");
777 evas_object_pass_events_set(o, 1);
779 e_box_pack_end(mi->container_object, o);
780 edje_object_size_min_calc(mi->submenu_object, &ww, &hh);
786 if (mi->submenu_object) evas_object_del(mi->submenu_object);
787 o = evas_object_rectangle_add(mi->menu->evas);
788 mi->submenu_object = o;
789 evas_object_color_set(o, 0, 0, 0, 0);
790 evas_object_pass_events_set(o, 1);
791 e_box_pack_end(mi->container_object, o);
793 _e_menu_lock = EINA_FALSE;
794 if (sub) e_object_unref(E_OBJECT(sub));
795 if ((mi->submenu) || (mi->submenu_pre_cb.func))
797 if (e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
798 "e/widgets/menu/default/submenu_bg"))
802 e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
803 "e/widgets/menu/default/item_bg");
807 e_menu_item_separator_set(E_Menu_Item *mi, int sep)
810 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
811 if (((mi->separator) && (sep)) || ((!mi->separator) && (!sep))) return;
814 mi->menu->changed = 1;
818 e_menu_item_check_set(E_Menu_Item *mi, int chk)
821 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
822 if (((mi->check) && (chk)) || ((!mi->check) && (!chk))) return;
825 mi->menu->changed = 1;
829 e_menu_item_radio_set(E_Menu_Item *mi, int rad)
832 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
833 if (((mi->radio) && (rad)) || ((!mi->radio) && (!rad))) return;
836 mi->menu->changed = 1;
840 e_menu_item_radio_group_set(E_Menu_Item *mi, int radg)
843 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
844 if (mi->radio_group == radg) return;
845 mi->radio_group = radg;
847 mi->menu->changed = 1;
851 e_menu_item_toggle_set(E_Menu_Item *mi, int tog)
854 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
855 if (mi->separator) return;
860 edje_object_signal_emit(mi->bg_object, "e,state,on", "e");
861 if (mi->icon_bg_object)
862 edje_object_signal_emit(mi->icon_bg_object, "e,state,on", "e");
863 if (mi->label_object)
864 edje_object_signal_emit(mi->label_object, "e,state,on", "e");
865 if (mi->submenu_object)
866 edje_object_signal_emit(mi->submenu_object, "e,state,on", "e");
867 if (mi->toggle_object)
868 edje_object_signal_emit(mi->toggle_object, "e,state,on", "e");
869 if (mi->menu->bg_object)
870 edje_object_signal_emit(mi->menu->bg_object, "e,state,on", "e");
876 edje_object_signal_emit(mi->bg_object, "e,state,off", "e");
877 if (mi->icon_bg_object)
878 edje_object_signal_emit(mi->icon_bg_object, "e,state,off", "e");
879 if (mi->label_object)
880 edje_object_signal_emit(mi->label_object, "e,state,off", "e");
881 if (mi->submenu_object)
882 edje_object_signal_emit(mi->submenu_object, "e,state,off", "e");
883 if (mi->toggle_object)
884 edje_object_signal_emit(mi->toggle_object, "e,state,off", "e");
885 if (mi->menu->bg_object)
886 edje_object_signal_emit(mi->menu->bg_object, "e,state,off", "e");
895 EINA_LIST_FOREACH(mi->menu->items, l, mi2)
897 if ((mi2 != mi) && (mi2->radio) &&
898 (mi2->radio_group == mi->radio_group))
899 e_menu_item_toggle_set(mi2, 0);
906 e_menu_item_toggle_get(E_Menu_Item *mi)
908 E_OBJECT_CHECK_RETURN(mi, 0);
909 E_OBJECT_TYPE_CHECK_RETURN(mi, E_MENU_ITEM_TYPE, 0);
914 e_menu_item_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), const void *data)
917 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
919 mi->cb.data = (void*)data;
923 e_menu_item_realize_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), void *data)
926 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
927 mi->realize_cb.func = func;
928 mi->realize_cb.data = data;
932 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)
935 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
936 mi->submenu_pre_cb.func = func;
937 mi->submenu_pre_cb.data = (void*)data;
938 if (!mi->submenu_post_cb.func)
939 mi->submenu_post_cb.func = _e_menu_cb_item_submenu_post_default;
943 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)
946 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
947 mi->submenu_post_cb.func = func;
948 mi->submenu_post_cb.data = (void*)data;
952 e_menu_item_drag_callback_set(E_Menu_Item *mi, void (*func)(void *data, E_Menu *m, E_Menu_Item *mi), void *data)
955 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
956 mi->drag_cb.func = func;
957 mi->drag_cb.data = data;
961 e_menu_item_active_set(E_Menu_Item *mi, int active)
964 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
965 if (mi->separator) return;
966 if ((active) && (!mi->active))
970 if (mi->disable) return;
971 pmi = _e_menu_item_active_get();
972 if (mi == pmi) return;
974 e_menu_item_active_set(pmi, 0);
975 if (_e_prev_active_menu_item && (mi != _e_prev_active_menu_item))
977 if (_e_prev_active_menu_item != mi->menu->parent_item)
978 _e_menu_submenu_deactivate(_e_prev_active_menu_item);
981 _e_active_menu_item = mi;
983 edje_object_signal_emit(mi->bg_object, "e,state,selected", "e");
984 if (mi->icon_bg_object)
985 edje_object_signal_emit(mi->icon_bg_object, "e,state,selected", "e");
986 if (mi->label_object)
987 edje_object_signal_emit(mi->label_object, "e,state,selected", "e");
988 if (mi->submenu_object)
989 edje_object_signal_emit(mi->submenu_object, "e,state,selected", "e");
990 if (mi->toggle_object)
991 edje_object_signal_emit(mi->toggle_object, "e,state,selected", "e");
996 if (strcmp(evas_object_type_get(mi->icon_object), "e_icon"))
997 edje_object_signal_emit(mi->icon_object, "e,state,selected", "e");
999 e_icon_selected_set(mi->icon_object, EINA_TRUE);
1002 edje_object_signal_emit(mi->menu->bg_object, "e,state,selected", "e");
1003 _e_menu_submenu_activate(mi);
1005 else if ((!active) && (mi->active))
1008 _e_prev_active_menu_item = mi;
1009 _e_active_menu_item = NULL;
1011 edje_object_signal_emit(mi->bg_object, "e,state,unselected", "e");
1012 if (mi->icon_bg_object)
1013 edje_object_signal_emit(mi->icon_bg_object, "e,state,unselected", "e");
1014 if (mi->label_object)
1015 edje_object_signal_emit(mi->label_object, "e,state,unselected", "e");
1016 if (mi->submenu_object)
1017 edje_object_signal_emit(mi->submenu_object, "e,state,unselected", "e");
1018 if (mi->toggle_object)
1019 edje_object_signal_emit(mi->toggle_object, "e,state,unselected", "e");
1022 if (mi->icon_object)
1024 if (strcmp(evas_object_type_get(mi->icon_object), "e_icon"))
1025 edje_object_signal_emit(mi->icon_object, "e,state,unselected", "e");
1027 e_icon_selected_set(mi->icon_object, EINA_FALSE);
1030 edje_object_signal_emit(mi->menu->bg_object, "e,state,unselected", "e");
1035 e_menu_item_active_get(void)
1037 return _e_active_menu_item;
1041 e_menu_active_item_activate(void)
1043 _e_menu_active_call();
1044 _e_menu_deactivate_all();
1048 e_menu_item_disabled_set(E_Menu_Item *mi, int disable)
1051 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
1052 if (mi->separator) return;
1055 if (mi->active) e_menu_item_active_set(mi, 0);
1057 if (mi->icon_bg_object)
1058 edje_object_signal_emit(mi->icon_bg_object, "e,state,disable", "e");
1059 if (mi->label_object)
1060 edje_object_signal_emit(mi->label_object, "e,state,disable", "e");
1061 if (mi->toggle_object)
1062 edje_object_signal_emit(mi->toggle_object, "e,state,disable", "e");
1067 if (mi->icon_bg_object)
1068 edje_object_signal_emit(mi->icon_bg_object, "e,state,enable", "e");
1069 if (mi->label_object)
1070 edje_object_signal_emit(mi->label_object, "e,state,enable", "e");
1071 if (mi->toggle_object)
1072 edje_object_signal_emit(mi->toggle_object, "e,state,enable", "e");
1077 e_menu_idler_before(void)
1079 /* when e goes "idle" this gets called so leave all our hard work till */
1080 /* idle time to avoid falling behind the user. just evaluate the high */
1081 /* level state machine */
1082 Eina_List *l, *removals = NULL, *tmp;
1085 /* add refcount to all menus we will work with */
1086 tmp = _e_active_menus_copy_ref();
1087 /* phase 1. hide all the menus that want to be hidden */
1088 EINA_LIST_FOREACH(_e_active_menus, l, m)
1090 if ((!m->cur.visible) && (m->prev.visible))
1092 m->prev.visible = m->cur.visible;
1093 ecore_evas_hide(m->ecore_evas);
1094 e_container_shape_hide(m->shape);
1097 /* phase 2. move & reisze all the menus that want to moves/resized */
1098 EINA_LIST_FOREACH(_e_active_menus, l, m)
1100 if (m->frozen) continue;
1101 if (!m->realized) _e_menu_realize(m);
1104 if (((m->cur.w) != (m->prev.w)) ||
1105 ((m->cur.h) != (m->prev.h)))
1109 m->prev.w = m->cur.w;
1110 m->prev.h = m->cur.h;
1113 if (w > MAX_MENU_SIZE) w = MAX_MENU_SIZE;
1114 if (h > MAX_MENU_SIZE) h = MAX_MENU_SIZE;
1115 ecore_evas_resize(m->ecore_evas, w, h);
1116 e_container_shape_resize(m->shape, w, h);
1118 if (((m->cur.x) != (m->prev.x)) ||
1119 ((m->cur.y) != (m->prev.y)))
1121 m->prev.x = m->cur.x;
1122 m->prev.y = m->cur.y;
1123 ecore_evas_move(m->ecore_evas, m->cur.x, m->cur.y);
1124 e_container_shape_move(m->shape, m->cur.x, m->cur.y);
1128 /* phase 3. show all the menus that want to be shown */
1129 EINA_LIST_FOREACH(_e_active_menus, l, m)
1131 if (m->frozen) continue;
1132 if ((m->cur.visible) && (!m->prev.visible))
1134 m->prev.visible = m->cur.visible;
1135 ecore_evas_raise(m->ecore_evas);
1136 ecore_evas_show(m->ecore_evas);
1137 if (!m->shaped) e_container_shape_show(m->shape);
1140 /* phase 4. de-activate... */
1141 EINA_LIST_FOREACH(_e_active_menus, l, m)
1145 _e_menu_unrealize(m);
1146 removals = eina_list_append(removals, m);
1149 EINA_LIST_FREE(removals, m)
1151 if (m->in_active_list)
1153 _e_active_menus = eina_list_remove(_e_active_menus, m);
1154 m->in_active_list = 0;
1155 e_object_unref(E_OBJECT(m));
1158 /* phase 5. shapes... */
1159 EINA_LIST_FOREACH(_e_active_menus, l, m)
1161 if (m->need_shape_export)
1163 Ecore_X_Rectangle *rects, *orects;
1166 rects = ecore_x_window_shape_rectangles_get(m->evas_win, &num);
1171 if ((num == m->shape_rects_num) && (m->shape_rects))
1175 orects = m->shape_rects;
1176 for (i = 0; i < num; i++)
1178 if ((orects[i].x != rects[i].x) ||
1179 (orects[i].y != rects[i].y) ||
1180 (orects[i].width != rects[i].width) ||
1181 (orects[i].height != rects[i].height))
1187 // TODO: This is meaningless
1192 E_FREE(m->shape_rects);
1193 m->shape_rects = rects;
1194 m->shape_rects_num = num;
1195 e_container_shape_rects_set(m->shape, rects, num);
1202 E_FREE(m->shape_rects);
1203 m->shape_rects = NULL;
1204 m->shape_rects_num = 0;
1205 e_container_shape_rects_set(m->shape, NULL, 0);
1207 m->need_shape_export = 0;
1208 if (m->cur.visible) e_container_shape_show(m->shape);
1211 /* del refcount to all menus we worked with */
1212 _e_menu_list_free_unref(tmp);
1214 if (!_e_active_menus)
1218 ecore_x_window_free(_e_menu_win);
1219 e_grabinput_release(_e_menu_win, _e_menu_win);
1226 e_menu_grab_window_get(void)
1232 e_menu_find_by_window(Ecore_X_Window win)
1236 m = eina_hash_find(_e_menu_hash, e_util_winid_str_get(win));
1237 if ((m) && (m->evas_win != win))
1242 /* local subsystem functions */
1244 _e_menu_free(E_Menu *m)
1246 Eina_List *l, *l_next;
1248 E_Menu_Category *cat = NULL;
1250 /* the foreign menu items */
1251 if (m->category) cat = eina_hash_find(_e_menu_categories, m->category);
1254 E_Menu_Category_Callback *cb;
1256 EINA_LIST_FOREACH(cat->callbacks, l, cb)
1258 if (cb->free) cb->free(cb->data);
1261 if (m->parent_item && (m->parent_item->submenu == m))
1262 m->parent_item->submenu = NULL;
1263 _e_menu_unrealize(m);
1264 E_FREE(m->shape_rects);
1265 m->shape_rects_num = 0;
1266 EINA_LIST_FOREACH_SAFE (m->items, l, l_next, mi)
1267 e_object_del(E_OBJECT(mi));
1268 if (m->in_active_list)
1270 _e_active_menus = eina_list_remove(_e_active_menus, m);
1271 m->in_active_list = 0;
1272 e_object_unref(E_OBJECT(m));
1274 if (m->header.title) eina_stringshare_del(m->header.title);
1275 if (m->header.icon_file) eina_stringshare_del(m->header.icon_file);
1280 _e_menu_item_free(E_Menu_Item *mi)
1282 if (mi == _e_active_menu_item) _e_active_menu_item = NULL;
1283 if (mi == _e_prev_active_menu_item) _e_prev_active_menu_item = NULL;
1288 /* parent_item gets unset in a few places, reapply it for use in cleanup */
1289 if (!mi->submenu->parent_item)
1290 mi->submenu->parent_item = mi;
1291 /* menu may not have been deactivated, ensure deactivate callback is called */
1293 _e_menu_submenu_deactivate(mi);
1294 /* submenus CANNOT exist without their parent menu+item, so ensure that they get deleted */
1297 ref = e_object_ref_get(E_OBJECT(mi->submenu)) - 1;
1298 e_object_unref(E_OBJECT(mi->submenu));
1301 WRN("DANGLING SUBMENU FOR %s: REF(%d)||MENU(%p)", mi->label, ref, mi->submenu);
1303 if (mi->menu->realized) _e_menu_item_unrealize(mi);
1304 mi->menu->items = eina_list_remove(mi->menu->items, mi);
1305 if (mi->icon) eina_stringshare_del(mi->icon);
1306 if (mi->icon_key) eina_stringshare_del(mi->icon_key);
1307 if (mi->label) eina_stringshare_del(mi->label);
1312 _e_menu_cb_intercept_item_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y)
1319 evas_object_move(mi->event_object, x, y);
1320 evas_object_move(o, x, y);
1321 if ((mi->submenu) && (mi->submenu->parent_item))
1322 _e_menu_reposition(mi->submenu);
1326 _e_menu_cb_intercept_item_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h)
1333 evas_object_resize(mi->event_object, w, h);
1334 evas_object_resize(o, w, h);
1335 if ((mi->submenu) && (mi->submenu->parent_item))
1336 _e_menu_reposition(mi->submenu);
1340 _e_menu_cb_intercept_container_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y)
1347 if (m->parent_item) _e_menu_reposition(m);
1348 evas_object_move(o, x, y);
1352 _e_menu_cb_intercept_container_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h)
1359 if (m->parent_item) _e_menu_reposition(m);
1360 evas_object_resize(o, w, h);
1364 _e_menu_item_realize(E_Menu_Item *mi)
1369 /* and set up initial item state */
1372 o = edje_object_add(mi->menu->evas);
1373 mi->separator_object = o;
1374 e_theme_edje_object_set(o, "base/theme/menus",
1375 "e/widgets/menu/default/separator");
1376 evas_object_show(o);
1377 edje_object_size_min_calc(mi->separator_object, &ww, &hh);
1378 mi->separator_w = ww;
1379 mi->separator_h = hh;
1380 e_box_pack_end(mi->menu->container_object, mi->separator_object);
1384 o = edje_object_add(mi->menu->evas);
1386 evas_object_intercept_move_callback_add(o, _e_menu_cb_intercept_item_move, mi);
1387 evas_object_intercept_resize_callback_add(o, _e_menu_cb_intercept_item_resize, mi);
1389 if ((mi->submenu) || (mi->submenu_pre_cb.func))
1391 if (!e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
1392 "e/widgets/menu/default/submenu_bg"))
1393 goto no_submenu_item;
1398 e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
1399 "e/widgets/menu/default/item_bg");
1401 evas_object_show(o);
1403 o = e_box_add(mi->menu->evas);
1404 e_box_homogenous_set(o, 0);
1405 mi->container_object = o;
1406 e_box_orientation_set(o, 1);
1407 evas_object_show(o);
1409 e_box_freeze(mi->container_object);
1413 o = edje_object_add(mi->menu->evas);
1414 mi->toggle_object = o;
1415 e_theme_edje_object_set(o, "base/theme/menus",
1416 "e/widgets/menu/default/check");
1417 evas_object_pass_events_set(o, 1);
1418 evas_object_show(o);
1419 e_box_pack_end(mi->container_object, o);
1420 edje_object_size_min_calc(mi->toggle_object, &ww, &hh);
1426 o = edje_object_add(mi->menu->evas);
1427 mi->toggle_object = o;
1428 e_theme_edje_object_set(o, "base/theme/menus",
1429 "e/widgets/menu/default/radio");
1430 evas_object_pass_events_set(o, 1);
1431 evas_object_show(o);
1432 e_box_pack_end(mi->container_object, o);
1433 edje_object_size_min_calc(mi->toggle_object, &ww, &hh);
1439 o = evas_object_rectangle_add(mi->menu->evas);
1440 mi->toggle_object = o;
1441 evas_object_color_set(o, 0, 0, 0, 0);
1442 evas_object_pass_events_set(o, 1);
1443 e_box_pack_end(mi->container_object, o);
1445 if ((mi->icon) || (mi->realize_cb.func))
1447 int icon_w = 0, icon_h = 0;
1449 o = edje_object_add(mi->menu->evas);
1450 if (e_theme_edje_object_set(o, "base/theme/menus",
1451 "e/widgets/menu/default/icon"))
1453 mi->icon_bg_object = o;
1454 evas_object_show(o);
1462 /* FIXME: Not sure why there are two different tries to get the icon size, surely only the last one si needed. */
1463 /* 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.
1466 o = e_app_icon_add(mi->menu->evas, mi->app);
1467 mi->icon_object = o;
1468 e_icon_size_get(mi->icon_object, &icon_w, &icon_h);
1474 /* This is done this way to match up with how e_app_icon_add does it. */
1477 Evas_Coord iww, ihh;
1479 o = edje_object_add(mi->menu->evas);
1480 if (edje_object_file_set(o, mi->icon, mi->icon_key))
1482 mi->icon_object = o;
1483 edje_object_size_max_get(o, &iww, &ihh);
1493 if (!mi->icon_object)
1495 o = e_icon_add(mi->menu->evas);
1496 mi->icon_object = o;
1497 e_icon_scale_size_set(o, e_util_icon_size_normalize(24 * e_scale));
1498 e_icon_preload_set(mi->icon_object, 1);
1499 e_icon_file_set(o, mi->icon);
1500 e_icon_fill_inside_set(mi->icon_object, 1);
1501 e_icon_size_get(mi->icon_object, &icon_w, &icon_h);
1504 if (_e_menu_realize_call(mi))
1506 o = mi->icon_object;
1507 e_icon_fill_inside_set(o, 1);
1508 e_icon_size_get(o, &icon_w, &icon_h);
1511 evas_object_pass_events_set(o, 1);
1512 evas_object_show(o);
1514 if (mi->icon_bg_object)
1516 edje_extern_object_min_size_set(mi->icon_object,
1518 edje_object_part_swallow(mi->icon_bg_object,
1519 "e.swallow.content",
1521 edje_object_size_min_calc(mi->icon_bg_object, &ww, &hh);
1525 edje_extern_object_min_size_set(mi->icon_object, 0, 0);
1526 edje_object_part_swallow(mi->icon_bg_object,
1527 "e.swallow.content",
1529 e_box_pack_end(mi->container_object, mi->icon_bg_object);
1533 o = edje_object_add(mi->menu->evas);
1534 e_icon_size_get(mi->icon_object, &icon_w, &icon_h);
1535 mi->icon_w = icon_w;
1536 mi->icon_h = icon_h;
1537 e_box_pack_end(mi->container_object, o);
1542 o = evas_object_rectangle_add(mi->menu->evas);
1543 mi->icon_object = o;
1544 evas_object_color_set(o, 0, 0, 0, 0);
1545 evas_object_pass_events_set(o, 1);
1546 e_box_pack_end(mi->container_object, o);
1551 o = edje_object_add(mi->menu->evas);
1552 mi->label_object = o;
1553 e_theme_edje_object_set(o, "base/theme/menus",
1554 "e/widgets/menu/default/label");
1556 edje_object_part_text_set(o, "e.text.label", mi->label);
1557 evas_object_pass_events_set(o, 1);
1558 evas_object_show(o);
1559 e_box_pack_end(mi->container_object, o);
1560 edje_object_size_min_calc(mi->label_object, &ww, &hh);
1566 o = evas_object_rectangle_add(mi->menu->evas);
1567 mi->label_object = o;
1568 evas_object_color_set(o, 0, 0, 0, 0);
1569 evas_object_pass_events_set(o, 1);
1570 e_box_pack_end(mi->container_object, o);
1572 if ((mi->submenu) || (mi->submenu_pre_cb.func))
1574 o = edje_object_add(mi->menu->evas);
1575 mi->submenu_object = o;
1576 e_theme_edje_object_set(o, "base/theme/menus",
1577 "e/widgets/menu/default/submenu");
1578 evas_object_pass_events_set(o, 1);
1579 evas_object_show(o);
1580 e_box_pack_end(mi->container_object, o);
1581 edje_object_size_min_calc(mi->submenu_object, &ww, &hh);
1587 o = evas_object_rectangle_add(mi->menu->evas);
1588 mi->submenu_object = o;
1589 evas_object_color_set(o, 0, 0, 0, 0);
1590 evas_object_pass_events_set(o, 1);
1591 e_box_pack_end(mi->container_object, o);
1594 edje_object_part_swallow(mi->bg_object, "e.swallow.content",
1595 mi->container_object);
1597 o = evas_object_rectangle_add(mi->menu->evas);
1598 evas_object_color_set(o, 0, 0, 0, 0);
1599 evas_object_layer_set(o, 1);
1600 evas_object_repeat_events_set(o, 1);
1601 evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_IN,
1602 _e_menu_cb_item_in, mi);
1603 evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_OUT,
1604 _e_menu_cb_item_out, mi);
1605 evas_object_show(o);
1606 mi->event_object = o;
1608 e_box_thaw(mi->container_object);
1609 e_box_pack_end(mi->menu->container_object, mi->bg_object);
1611 if (mi->active) e_menu_item_active_set(mi, 1);
1612 if (mi->toggle) e_menu_item_toggle_set(mi, 1);
1613 if (mi->disable) e_menu_item_disabled_set(mi, 1);
1617 _e_menu_realize(E_Menu *m)
1625 if (m->realized) return;
1627 m->ecore_evas = e_canvas_new(m->zone->container->win,
1628 m->cur.x, m->cur.y, m->cur.w, m->cur.h, 1, 1,
1630 e_canvas_add(m->ecore_evas);
1631 eina_hash_add(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1632 m->shape = e_container_shape_add(m->zone->container);
1633 e_container_shape_move(m->shape, m->cur.x, m->cur.y);
1636 if (w > MAX_MENU_SIZE) w = MAX_MENU_SIZE;
1637 if (h > MAX_MENU_SIZE) h = MAX_MENU_SIZE;
1638 e_container_shape_resize(m->shape, w, h);
1640 ecore_evas_callback_resize_set(m->ecore_evas, _e_menu_cb_ecore_evas_resize);
1641 m->evas = ecore_evas_get(m->ecore_evas);
1642 evas_event_freeze(m->evas);
1643 /* move cursor out to avoid event cycles during setup */
1644 evas_event_feed_mouse_in(m->evas, ecore_x_current_time_get(), NULL);
1645 evas_event_feed_mouse_move(m->evas, -1000000, -1000000,
1646 ecore_x_current_time_get(), NULL);
1647 ecore_x_window_shape_events_select(m->evas_win, 1);
1648 ecore_evas_name_class_set(m->ecore_evas, "E", "_e_menu_window");
1649 ecore_evas_title_set(m->ecore_evas, "E Menu");
1651 o = edje_object_add(m->evas);
1653 evas_object_name_set(o, "menu/background");
1654 evas_object_data_set(o, "e_menu", m);
1655 evas_object_move(o, 0, 0);
1656 evas_object_resize(o, w, h);
1657 ok = e_theme_edje_object_set(o, "base/theme/menus",
1658 "e/widgets/menu/default/background");
1661 const char *shape_option;
1663 shape_option = edje_object_data_get(o, "shaped");
1666 if (!strcmp(shape_option, "1")) m->shaped = 1;
1669 if (m->header.title)
1671 edje_object_part_text_set(o, "e.text.title", m->header.title);
1672 edje_object_signal_emit(o, "e,action,show,title", "e");
1673 edje_object_message_signal_process(o);
1675 evas_object_show(o);
1679 if (e_config->use_composite)
1681 ecore_evas_alpha_set(m->ecore_evas, m->shaped);
1683 eina_hash_del(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1684 m->evas_win = ecore_evas_software_x11_window_get(m->ecore_evas);
1685 eina_hash_add(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1688 ecore_evas_shaped_set(m->ecore_evas, m->shaped);
1691 ecore_x_netwm_window_type_set(m->evas_win, ECORE_X_WINDOW_TYPE_MENU);
1693 o = e_box_add(m->evas);
1694 m->container_object = o;
1695 evas_object_intercept_move_callback_add(o, _e_menu_cb_intercept_container_move, m);
1696 evas_object_intercept_resize_callback_add(o, _e_menu_cb_intercept_container_resize, m);
1698 evas_object_show(o);
1699 e_box_homogenous_set(o, 0);
1700 edje_object_part_swallow(m->bg_object, "e.swallow.content", m->container_object);
1702 EINA_LIST_FOREACH(m->items, l, mi)
1703 _e_menu_item_realize(mi);
1705 _e_menu_items_layout_update(m);
1706 e_box_thaw(m->container_object);
1707 evas_object_resize(m->bg_object, w, h);
1708 evas_event_thaw(m->evas);
1712 _e_menu_items_layout_update(E_Menu *m)
1716 Evas_Coord bw, bh, mw, mh;
1720 int submenus_on = 0;
1721 int min_icon_w = 0, min_icon_h = 0;
1722 int min_label_w = 0, min_label_h = 0;
1723 int min_submenu_w = 0, min_submenu_h = 0;
1724 int min_toggle_w = 0, min_toggle_h = 0;
1725 int min_w = 0, min_h = 0;
1727 e_box_freeze(m->container_object);
1728 EINA_LIST_FOREACH(m->items, l, mi)
1730 if (mi->icon) icons_on = 1;
1731 if (mi->icon_object) icons_on = 1;
1732 if (mi->label) labels_on = 1;
1733 if (mi->submenu) submenus_on = 1;
1734 if (mi->check) toggles_on = 1;
1735 if (mi->radio) toggles_on = 1;
1737 if (mi->icon_w > min_icon_w) min_icon_w = mi->icon_w;
1738 if (mi->icon_h > min_icon_h) min_icon_h = mi->icon_h;
1739 if (mi->label_w > min_label_w) min_label_w = mi->label_w;
1740 if (mi->label_h > min_label_h) min_label_h = mi->label_h;
1741 if (mi->submenu_w > min_submenu_w) min_submenu_w = mi->submenu_w;
1742 if (mi->submenu_h > min_submenu_h) min_submenu_h = mi->submenu_h;
1743 if (mi->toggle_w > min_toggle_w) min_toggle_w = mi->toggle_w;
1744 if (mi->toggle_h > min_toggle_h) min_toggle_h = mi->toggle_h;
1750 if (min_label_h < min_submenu_h)
1751 min_label_h = min_submenu_h;
1755 if (min_label_h < min_toggle_h)
1756 min_label_h = min_toggle_h;
1758 if ((icons_on) && (min_icon_h > 0))
1760 min_icon_w = (min_icon_w * min_label_h) / min_icon_h;
1761 min_icon_h = min_label_h;
1763 min_w = min_label_w + min_icon_w + min_submenu_w + min_toggle_w;
1764 min_h = min_label_h;
1770 if (min_icon_h < min_submenu_h)
1771 min_icon_h = min_submenu_h;
1775 if (min_icon_h < min_toggle_h)
1776 min_icon_h = min_toggle_h;
1778 min_w = min_icon_w + min_toggle_w + min_submenu_w;
1781 else if (toggles_on)
1785 if (min_toggle_h < min_submenu_h)
1786 min_toggle_h = min_submenu_h;
1788 min_w = min_toggle_w + min_submenu_w;
1789 min_h = min_toggle_h;
1791 EINA_LIST_FOREACH(m->items, l, mi)
1795 e_box_pack_options_set(mi->separator_object,
1798 0.5, 0.5, /* align */
1799 mi->separator_w, mi->separator_h, /* min */
1800 -1, mi->separator_h /* max */
1805 e_box_freeze(mi->container_object);
1807 e_box_pack_options_set(mi->toggle_object,
1810 0.5, 0.5, /* align */
1811 min_toggle_w, min_toggle_h, /* min */
1815 e_box_pack_options_set(mi->toggle_object,
1818 0.5, 0.5, /* align */
1824 if (mi->icon_bg_object)
1825 e_box_pack_options_set(mi->icon_bg_object,
1828 0.5, 0.5, /* align */
1829 min_icon_w, min_icon_h, /* min */
1833 e_box_pack_options_set(mi->icon_object,
1836 0.5, 0.5, /* align */
1837 min_icon_w, min_icon_h, /* min */
1842 e_box_pack_options_set(mi->icon_object,
1845 0.5, 0.5, /* align */
1850 e_box_pack_options_set(mi->label_object,
1853 0.5, 0.5, /* align */
1854 min_label_w, min_label_h, /* min */
1858 e_box_pack_options_set(mi->label_object,
1861 0.5, 0.5, /* align */
1866 e_box_pack_options_set(mi->submenu_object,
1869 0.5, 0.5, /* align */
1870 min_submenu_w, min_submenu_h, /* min */
1874 e_box_pack_options_set(mi->submenu_object,
1877 0.5, 0.5, /* align */
1881 edje_extern_object_min_size_set(mi->container_object,
1883 edje_object_part_swallow(mi->bg_object, "e.swallow.content",
1884 mi->container_object);
1885 edje_object_size_min_calc(mi->bg_object, &mw, &mh);
1886 e_box_pack_options_set(mi->bg_object,
1889 0.5, 0.5, /* align */
1893 e_box_thaw(mi->container_object);
1896 e_box_size_min_get(m->container_object, &bw, &bh);
1897 edje_extern_object_min_size_set(m->container_object, bw, bh);
1898 edje_extern_object_max_size_set(m->container_object, bw, bh);
1899 edje_object_part_swallow(m->bg_object, "e.swallow.content", m->container_object);
1900 edje_object_size_min_calc(m->bg_object, &mw, &mh);
1901 e_box_thaw(m->container_object);
1907 _e_menu_item_unrealize(E_Menu_Item *mi)
1909 if (mi->container_object) e_box_freeze(mi->container_object);
1910 if (mi->separator_object) evas_object_del(mi->separator_object);
1911 mi->separator_object = NULL;
1912 if (mi->bg_object) evas_object_del(mi->bg_object);
1913 mi->bg_object = NULL;
1914 if (mi->container_object) evas_object_del(mi->container_object);
1915 mi->container_object = NULL;
1916 if (mi->toggle_object) evas_object_del(mi->toggle_object);
1917 mi->toggle_object = NULL;
1918 if (mi->icon_bg_object) evas_object_del(mi->icon_bg_object);
1919 mi->icon_bg_object = NULL;
1920 if (mi->icon_object) evas_object_del(mi->icon_object);
1921 mi->icon_object = NULL;
1922 if (mi->label_object) evas_object_del(mi->label_object);
1923 mi->label_object = NULL;
1924 if (mi->submenu_object) evas_object_del(mi->submenu_object);
1925 mi->submenu_object = NULL;
1926 if (mi->event_object) evas_object_del(mi->event_object);
1927 mi->event_object = NULL;
1931 _e_menu_unrealize(E_Menu *m)
1936 if (!m->realized) return;
1937 evas_event_freeze(m->evas);
1938 e_container_shape_hide(m->shape);
1939 e_object_del(E_OBJECT(m->shape));
1941 e_box_freeze(m->container_object);
1942 EINA_LIST_FOREACH(m->items, l, mi)
1943 _e_menu_item_unrealize(mi);
1944 if (m->header.icon) evas_object_del(m->header.icon);
1945 m->header.icon = NULL;
1946 if (m->bg_object) evas_object_del(m->bg_object);
1947 m->bg_object = NULL;
1948 if (m->container_object) evas_object_del(m->container_object);
1949 m->container_object = NULL;
1951 m->prev.visible = 0;
1954 e_canvas_del(m->ecore_evas);
1955 ecore_evas_free(m->ecore_evas);
1956 m->ecore_evas = NULL;
1958 eina_hash_del(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1963 _e_menu_activate_internal(E_Menu *m, E_Zone *zone)
1965 E_Menu_Category *cat = NULL;
1968 if (m->pre_activate_cb.func)
1969 m->pre_activate_cb.func(m->pre_activate_cb.data, m);
1971 m->pending_new_submenu = 0;
1974 _e_menu_win = ecore_x_window_input_new(zone->container->win,
1977 ecore_x_window_show(_e_menu_win);
1978 if (!e_grabinput_get(_e_menu_win, 1, _e_menu_win))
1980 ecore_x_window_free(_e_menu_win);
1985 if ((m->zone) && (m->zone->container != zone->container))
1987 printf("FIXME: cannot move menus between containers yet\n");
1993 /* this remove is in case the menu is marked as inactive but hasn't */
1994 /* been removed from the list yet */
1995 if (m->in_active_list)
1997 _e_active_menus = eina_list_remove(_e_active_menus, m);
1998 m->in_active_list = 0;
1999 e_object_unref(E_OBJECT(m));
2001 _e_active_menus = eina_list_append(_e_active_menus, m);
2002 m->in_active_list = 1;
2004 e_object_ref(E_OBJECT(m));
2006 /* the foreign menu items */
2009 cat = eina_hash_find(_e_menu_categories, m->category);
2012 E_Menu_Category_Callback *cb;
2013 EINA_LIST_FOREACH(cat->callbacks, l, cb)
2014 if (cb->create) cb->create(m, cat->data, cb->data);
2021 _e_menu_deactivate_all(void)
2026 tmp = _e_active_menus_copy_ref();
2028 EINA_LIST_FREE(tmp, m)
2030 e_menu_deactivate(m);
2031 m->parent_item = NULL;
2032 e_object_unref(E_OBJECT(m));
2034 _e_menu_activate_floating = 0;
2035 _e_menu_activate_maybe_drag = 0;
2036 _e_menu_activate_dragging = 0;
2040 _e_menu_deactivate_above(E_Menu *ma)
2046 tmp = _e_active_menus_copy_ref();
2048 EINA_LIST_FREE(tmp, m)
2052 e_menu_deactivate(m);
2053 m->parent_item = NULL;
2055 if (ma == m) above = 1;
2056 e_object_unref(E_OBJECT(m));
2061 _e_menu_submenu_activate(E_Menu_Item *mi)
2063 if (!mi->menu->active) return;
2064 if (mi->menu->fast_mouse)
2066 mi->menu->pending_new_submenu = 1;
2069 mi->menu->pending_new_submenu = 0;
2070 _e_menu_deactivate_above(mi->menu);
2071 if (mi->submenu_pre_cb.func)
2072 mi->submenu_pre_cb.func(mi->submenu_pre_cb.data, mi->menu, mi);
2078 e_object_ref(E_OBJECT(m));
2079 m->parent_item = mi;
2080 _e_menu_activate_internal(m, mi->menu->zone);
2081 _e_menu_reposition(m);
2082 e_object_unref(E_OBJECT(m));
2087 _e_menu_submenu_deactivate(E_Menu_Item *mi)
2089 if (!mi->menu->active) return;
2090 if (mi->submenu_post_cb.func)
2091 mi->submenu_post_cb.func(mi->submenu_post_cb.data, mi->menu, mi);
2095 _e_menu_reposition(E_Menu *m)
2099 int parent_item_bottom;
2101 if (!m->parent_item) return;
2102 m->cur.x = m->parent_item->menu->cur.x + m->parent_item->menu->cur.w;
2104 parent_item_bottom = m->parent_item->menu->cur.y + m->parent_item->y;
2105 if (m->cur.h > m->zone->h)
2107 /* menu is larger than screen */
2108 if (parent_item_bottom > (m->zone->h / 2))
2109 /* more is shown if menu goes up */
2110 m->cur.y = (parent_item_bottom - (m->container_h + 1));
2112 /* more is shown if menu goes down */
2113 m->cur.y = parent_item_bottom - m->container_y;
2117 /* menu is smaller than screen */
2118 if (((parent_item_bottom + m->cur.h - m->container_y) > m->zone->h) &&
2119 (parent_item_bottom > (m->zone->h / 2)))
2120 /* menu is partially out of screen and more is shown if menu goes up */
2121 m->cur.y = (parent_item_bottom - (m->container_h + 1)) + m->parent_item->h;
2123 m->cur.y = parent_item_bottom - m->container_y;
2126 /* FIXME: this will suck for big menus */
2127 tmp = _e_active_menus_copy_ref();
2129 EINA_LIST_FOREACH(m->items, l, mi)
2130 if ((mi->active) && (mi->submenu)) _e_menu_reposition(mi->submenu);
2132 _e_menu_list_free_unref(tmp);
2136 _e_menu_active_call(void)
2140 mi = _e_menu_item_active_get();
2144 e_menu_item_toggle_set(mi, !mi->toggle);
2145 if ((mi->radio) && (!e_menu_item_toggle_get(mi)))
2146 e_menu_item_toggle_set(mi, 1);
2148 mi->cb.func(mi->cb.data, mi->menu, mi);
2155 _e_menu_realize_call(E_Menu_Item *mi)
2159 if (mi->realize_cb.func)
2161 mi->realize_cb.func(mi->realize_cb.data, mi->menu, mi);
2169 _e_menu_item_activate_next(void)
2174 ll = _e_menu_list_item_active_get();
2175 mi = _e_menu_item_active_get();
2178 /* Look at the next item and then cycle until we're not on
2182 if (!eina_list_next(ll))
2183 ll = mi->menu->items;
2185 ll = eina_list_next(ll);
2186 mi = eina_list_data_get(ll);
2188 while (mi->separator || mi->disable);
2190 e_menu_item_active_set(mi, 1);
2191 _e_menu_item_ensure_onscreen(mi);
2195 _e_menu_activate_first();
2199 _e_menu_item_activate_previous(void)
2204 ll = _e_menu_list_item_active_get();
2205 mi = _e_menu_item_active_get();
2208 /* Look at the prev item and then cycle until we're not on
2212 if (!eina_list_prev(ll))
2213 ll = eina_list_last(ll);
2215 ll = eina_list_prev(ll);
2216 mi = eina_list_data_get(ll);
2218 while ((mi->separator) || (mi->disable));
2220 e_menu_item_active_set(mi, 1);
2221 _e_menu_item_ensure_onscreen(mi);
2225 _e_menu_activate_first();
2229 _e_menu_item_activate_first(void)
2235 m = _e_menu_active_get();
2239 mi = eina_list_data_get(ll);
2240 while ((mi->separator) && eina_list_next(ll))
2242 ll = eina_list_next(ll);
2243 mi = eina_list_data_get(ll);
2245 if (mi->separator) return;
2246 e_menu_item_active_set(mi, 1);
2247 _e_menu_item_ensure_onscreen(mi);
2250 _e_menu_activate_first();
2254 _e_menu_item_activate_last(void)
2260 m = _e_menu_active_get();
2263 ll = eina_list_last(m->items);
2264 mi = eina_list_data_get(ll);
2265 while ((mi->separator) && eina_list_prev(ll))
2267 ll = eina_list_prev(ll);
2268 mi = eina_list_data_get(ll);
2270 if (mi->separator) return;
2271 e_menu_item_active_set(mi, 1);
2272 _e_menu_item_ensure_onscreen(mi);
2275 _e_menu_activate_first();
2279 _e_menu_item_activate_nth(int n)
2286 mi = _e_menu_item_active_get();
2289 _e_menu_activate_first();
2290 mi = _e_menu_item_active_get();
2294 EINA_LIST_FOREACH(m->items, ll, mi)
2296 if (!mi->separator) i++;
2299 e_menu_item_active_set(mi, 1);
2300 _e_menu_item_ensure_onscreen(mi);
2304 _e_menu_item_activate_char(const char *key_compose)
2308 Eina_List *ll, *ll_orig;
2310 /* Ignore modifiers and such. */
2311 if (!key_compose) return;
2313 /* Check we've got a menu and it's active. */
2314 m = _e_menu_active_get();
2317 if (!_e_active_menus) return;
2318 m = eina_list_data_get(_e_active_menus);
2322 ll = _e_menu_list_item_active_get();
2323 /* If we don't have an active item, start from the top of the list. */
2327 mi = eina_list_data_get(ll);
2328 /* Only check the current item if it wasn't active before. */
2329 if (!mi->separator && mi->label && !strncasecmp(key_compose, mi->label, strlen(key_compose)))
2331 e_menu_item_active_set(mi, 1);
2332 _e_menu_item_ensure_onscreen(mi);
2339 mi = eina_list_data_get(ll);
2340 if (!eina_list_next(ll))
2341 ll = mi->menu->items;
2343 ll = eina_list_next(ll);
2344 mi = eina_list_data_get(ll);
2346 /* While we don't have a label OR we don't match AND we haven't
2348 while ((!mi->label || strncasecmp(key_compose, mi->label, strlen(key_compose)))
2353 if (!eina_list_next(ll))
2354 ll = mi->menu->items;
2356 ll = eina_list_next(ll);
2357 mi = eina_list_data_get(ll);
2359 while (mi->separator);
2362 e_menu_item_active_set(mi, 1);
2363 _e_menu_item_ensure_onscreen(mi);
2368 _e_menu_activate_next(void)
2372 mi = _e_menu_item_active_get();
2377 if (mi->submenu->items)
2380 EINA_LIST_FOREACH(mi->submenu->items, l, mi)
2383 e_menu_item_active_set(mi, 1);
2384 _e_menu_item_ensure_onscreen(mi);
2391 _e_menu_activate_first();
2395 _e_menu_activate_previous(void)
2399 mi = _e_menu_item_active_get();
2402 if (mi->menu->parent_item)
2404 mi = mi->menu->parent_item;
2405 e_menu_item_active_set(mi, 1);
2406 _e_menu_item_ensure_onscreen(mi);
2410 _e_menu_activate_last();
2414 _e_menu_activate_first(void)
2420 if (!_e_active_menus) return;
2421 m = eina_list_data_get(_e_active_menus);
2422 if (!m->items) return;
2424 mi = eina_list_data_get(ll);
2425 while ((mi->separator) && eina_list_next(ll))
2427 ll = eina_list_next(ll);
2428 mi = eina_list_data_get(ll);
2430 if (mi->separator) return;
2431 e_menu_item_active_set(mi, 1);
2432 _e_menu_item_ensure_onscreen(mi);
2436 _e_menu_activate_last(void)
2442 if (!_e_active_menus) return;
2443 m = eina_list_data_get(_e_active_menus);
2444 if (!m->items) return;
2445 ll = eina_list_last(m->items);
2446 mi = eina_list_data_get(ll);
2447 while ((mi->separator) && eina_list_prev(ll))
2449 ll = eina_list_prev(ll);
2450 mi = eina_list_data_get(ll);
2452 if (mi->separator) return;
2453 e_menu_item_active_set(mi, 1);
2454 _e_menu_item_ensure_onscreen(mi);
2459 _e_menu_activate_nth(int n)
2466 mi = _e_menu_item_active_get();
2469 _e_menu_activate_first();
2470 mi = _e_menu_item_active_get();
2474 EINA_LIST_FOREACH(m->items, ll, mi)
2476 if (!mi->separator) i++;
2479 e_menu_item_active_set(mi, 1);
2480 _e_menu_item_ensure_onscreen(mi);
2489 _e_menu_active_get(void)
2491 if (_e_active_menu_item) return _e_active_menu_item->menu;
2495 static E_Menu_Item *
2496 _e_menu_item_active_get(void)
2498 return _e_active_menu_item;
2502 _e_menu_list_item_active_get(void)
2504 if (_e_active_menu_item)
2505 return _e_active_menu_item->list_position;
2511 _e_menu_outside_bounds_get(int xdir, int ydir)
2521 EINA_LIST_FOREACH(_e_active_menus, l, m)
2523 if (m->cur.x < m->zone->x + e_config->menu_autoscroll_margin)
2525 i = m->zone->x - m->cur.x + e_config->menu_autoscroll_margin;
2526 if (i > outl) outl = i;
2528 if (m->cur.y < m->zone->y + e_config->menu_autoscroll_margin)
2530 i = m->zone->y - m->cur.y + e_config->menu_autoscroll_margin;
2531 if (i > outt) outt = i;
2533 if ((m->cur.x + m->cur.w) > (m->zone->w - e_config->menu_autoscroll_margin))
2535 i = m->cur.x + m->cur.w - (m->zone->x + m->zone->w - e_config->menu_autoscroll_margin);
2536 if (i > outr) outr = i;
2538 if ((m->cur.y + m->cur.h) > (m->zone->h - e_config->menu_autoscroll_margin))
2540 i = m->cur.y + m->cur.h - (m->zone->y + m->zone->h - e_config->menu_autoscroll_margin);
2541 if (i > outb) outb = i;
2546 if (outl) return outl;
2550 if (outr) return outr;
2552 else if (ydir == -1)
2554 if (outt) return outt;
2558 if (outb) return outb;
2564 _e_menu_scroll_by(int dx, int dy)
2569 EINA_LIST_FOREACH(_e_active_menus, l, m)
2577 _e_menu_mouse_autoscroll_check(void)
2579 int autoscroll_x = 0;
2580 int autoscroll_y = 0;
2582 if (_e_menu_x - e_config->menu_autoscroll_cursor_margin <= 0)
2584 if (_e_menu_outside_bounds_get(-1, 0)) autoscroll_x = -1;
2586 if (_e_menu_y - e_config->menu_autoscroll_cursor_margin <= 0)
2588 if (_e_menu_outside_bounds_get(0, -1)) autoscroll_y = -1;
2590 if ((!autoscroll_x) && (!autoscroll_y))
2592 if (_e_active_menus)
2596 m = eina_list_data_get(_e_active_menus);
2597 if (_e_menu_x + e_config->menu_autoscroll_cursor_margin >= (m->zone->w - 1))
2599 if (_e_menu_outside_bounds_get(1, 0)) autoscroll_x = 1;
2601 if (_e_menu_y + e_config->menu_autoscroll_cursor_margin >= (m->zone->h - 1))
2603 if (_e_menu_outside_bounds_get(0, 1)) autoscroll_y = 1;
2607 _e_menu_autoscroll_x = autoscroll_x;
2608 _e_menu_autoscroll_y = autoscroll_y;
2609 if ((!autoscroll_x) && (!autoscroll_y)) return;
2610 if (_e_menu_scroll_animator) return;
2611 _e_menu_scroll_animator = ecore_animator_add(_e_menu_cb_scroll_animator,
2613 _e_menu_scroll_start = ecore_loop_time_get();
2617 _e_menu_item_ensure_onscreen(E_Menu_Item *mi)
2619 int x = 0, y = 0, w = 0, h = 0;
2622 if (!mi->menu) return;
2623 if (!mi->menu->zone) return;
2624 x = mi->x + mi->menu->cur.x;
2625 y = mi->y + mi->menu->cur.y;
2628 if ((x + w) > (mi->menu->zone->x + mi->menu->zone->w))
2629 dx = (mi->menu->zone->x + mi->menu->zone->w) - (x + w);
2630 else if (x < mi->menu->zone->x)
2631 dx = mi->menu->zone->x - x;
2632 if ((y + h) > (mi->menu->zone->y + mi->menu->zone->h))
2633 dy = (mi->menu->zone->y + mi->menu->zone->h) - (y + h);
2634 else if (y < mi->menu->zone->y)
2635 dy = mi->menu->zone->y - y;
2636 if ((dx != 0) || (dy != 0))
2637 _e_menu_scroll_by(dx, dy);
2641 _e_menu_auto_place(E_Menu *m, int x, int y, int w, int h)
2654 * quadrants... which one
2656 if (w != m->zone->w)
2657 xr = (double)(x - m->zone->x) /
2658 (double)(m->zone->w - w);
2661 if (h != m->zone->h)
2662 yr = (double)(y - m->zone->y) /
2663 (double)(m->zone->h - h);
2666 if ((xr + yr) < 0.99) /* top or left */
2668 if (((1.0 - yr) + xr) <= 1.0)
2672 if (y < (m->zone->y + ((m->zone->h * 1) / 3)))
2674 else if (y < (m->zone->y + ((m->zone->h * 2) / 3)))
2675 m->cur.y = y + ((h - m->cur.h) / 2);
2677 m->cur.y = y + h - m->cur.h;
2684 if (x < (m->zone->x + ((m->zone->w * 1) / 3)))
2686 else if (x < (m->zone->x + ((m->zone->w * 2) / 3)))
2687 m->cur.x = x + ((w - m->cur.w) / 2);
2689 m->cur.x = x + w - m->cur.w;
2693 else /* bottom or right */
2695 if (((1.0 - yr) + xr) <= 1.01)
2698 m->cur.y = y - m->cur.h;
2699 if (x < (m->zone->x + ((m->zone->w * 1) / 3)))
2701 else if (x < (m->zone->x + ((m->zone->w * 2) / 3)))
2702 m->cur.x = x + ((w - m->cur.w) / 2);
2704 m->cur.x = x + w - m->cur.w;
2710 m->cur.x = x - m->cur.w;
2711 if (y < (m->zone->y + ((m->zone->h * 1) / 3)))
2713 else if (y < (m->zone->y + ((m->zone->h * 2) / 3)))
2714 m->cur.y = y + ((h - m->cur.h) / 2);
2716 m->cur.y = y + h - m->cur.h;
2724 _e_menu_cb_ecore_evas_resize(Ecore_Evas *ee)
2730 evas = ecore_evas_get(ee);
2731 evas_output_viewport_get(evas, NULL, NULL, &w, &h);
2732 o = evas_object_name_find(evas, "menu/background");
2733 evas_object_resize(o, w, h);
2737 _e_menu_cb_item_in(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2741 if (_e_menu_lock) return;
2743 e_menu_item_active_set(mi, 1);
2747 _e_menu_cb_item_out(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
2750 Evas_Event_Mouse_In *ev;
2754 e_menu_item_active_set(mi, 0);
2755 if (_e_menu_activate_maybe_drag)
2757 if (mi->drag_cb.func)
2759 /* User is dragging a draggable item elsewhere. */
2760 mi->drag.x = ev->output.x - (ev->output.x - mi->x);
2761 mi->drag.y = ev->output.y - (ev->output.y - mi->y);
2762 _e_menu_deactivate_all();
2763 mi->drag_cb.func(mi->drag_cb.data, mi->menu, mi);
2765 /* Either way, the maybe drag stops here. */
2766 _e_menu_activate_maybe_drag = 0;
2771 _e_menu_cb_key_down(void *data __UNUSED__, int type __UNUSED__, void *event)
2773 Ecore_Event_Key *ev;
2776 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2777 if ((!strcmp(ev->key, "Up")) || (!strcmp(ev->key, "KP_Up")))
2778 _e_menu_item_activate_previous();
2779 else if ((!strcmp(ev->key, "Down")) || (!strcmp(ev->key, "KP_Down")))
2780 _e_menu_item_activate_next();
2781 else if ((!strcmp(ev->key, "Left")) || (!strcmp(ev->key, "KP_Left")))
2782 _e_menu_activate_previous();
2783 else if ((!strcmp(ev->key, "Right")) || (!strcmp(ev->key, "KP_Right")))
2784 _e_menu_activate_next();
2785 else if ((!strcmp(ev->key, "Home")) || (!strcmp(ev->key, "KP_Home")))
2786 _e_menu_item_activate_first();
2787 else if ((!strcmp(ev->key, "End")) || (!strcmp(ev->key, "KP_End")))
2788 _e_menu_item_activate_last();
2789 else if (!strcmp(ev->key, "space"))
2790 _e_menu_active_call();
2791 else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
2793 _e_menu_active_call();
2794 _e_menu_deactivate_all();
2796 else if (!strcmp(ev->key, "Escape"))
2797 _e_menu_deactivate_all();
2798 else if ((!strcmp(ev->key, "1")) || (!strcmp(ev->key, "KP_1")))
2799 _e_menu_item_activate_first();
2800 else if ((!strcmp(ev->key, "2")) || (!strcmp(ev->key, "KP_2")))
2801 _e_menu_item_activate_nth(1);
2802 else if ((!strcmp(ev->key, "3")) || (!strcmp(ev->key, "KP_3")))
2803 _e_menu_item_activate_nth(2);
2804 else if ((!strcmp(ev->key, "4")) || (!strcmp(ev->key, "KP_4")))
2805 _e_menu_item_activate_nth(3);
2806 else if ((!strcmp(ev->key, "5")) || (!strcmp(ev->key, "KP_5")))
2807 _e_menu_item_activate_nth(4);
2808 else if ((!strcmp(ev->key, "6")) || (!strcmp(ev->key, "KP_6")))
2809 _e_menu_item_activate_nth(5);
2810 else if ((!strcmp(ev->key, "7")) || (!strcmp(ev->key, "KP_7")))
2811 _e_menu_item_activate_nth(6);
2812 else if ((!strcmp(ev->key, "8")) || (!strcmp(ev->key, "KP_8")))
2813 _e_menu_item_activate_nth(7);
2814 else if ((!strcmp(ev->key, "9")) || (!strcmp(ev->key, "KP_9")))
2815 _e_menu_item_activate_nth(8);
2816 else if ((!strcmp(ev->key, "0")) || (!strcmp(ev->key, "KP_0")))
2817 _e_menu_item_activate_last();
2818 else if (ev->compose)
2819 _e_menu_item_activate_char(ev->compose);
2820 return ECORE_CALLBACK_PASS_ON;
2824 _e_menu_cb_key_up(void *data __UNUSED__, int type __UNUSED__, void *event)
2826 Ecore_Event_Key *ev;
2829 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2830 return ECORE_CALLBACK_PASS_ON;
2833 /* we need all of these because menus are special and grab the mouse and
2834 * keyboard and thus the normal event mechanism doesn't work, so we feed
2835 * events directly to the canvases from our grab window
2839 _e_menu_cb_mouse_down(void *data __UNUSED__, int type __UNUSED__, void *event)
2841 Ecore_Event_Mouse_Button *ev;
2844 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2846 /* Only allow dragging from floating menus for now.
2847 * The reason for this is that for non floating menus,
2848 * the mouse is already down and dragging, so the decision
2849 * to start a drag is much more complex.
2851 if (_e_menu_activate_floating)
2852 _e_menu_activate_maybe_drag = 1;
2854 return ECORE_CALLBACK_PASS_ON;
2858 _e_menu_cb_mouse_up(void *data __UNUSED__, int type __UNUSED__, void *event)
2860 Ecore_Event_Mouse_Button *ev;
2865 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2867 t = ev->timestamp - _e_menu_activate_time;
2868 if ((_e_menu_activate_time != 0) &&
2869 (t < (e_config->menus_click_drag_timeout * 1000)))
2871 _e_menu_activate_floating = 1;
2872 return ECORE_CALLBACK_PASS_ON;
2875 if (_e_menu_activate_dragging)
2877 /* FIXME: This is a drop, which is not allowed for now.
2878 * Once dragging is working, this will be subject to some experimenattion.
2882 ret = _e_menu_active_call();
2883 _e_menu_activate_maybe_drag = 0;
2884 _e_menu_activate_dragging = 0;
2887 /* allow mouse to pop down menu if clicked elsewhere */
2888 /* if (_e_menu_activate_time != 0) */
2889 _e_menu_deactivate_all();
2892 _e_menu_deactivate_all();
2893 else if (!_e_menu_activate_floating)
2894 _e_menu_deactivate_all();
2895 return ECORE_CALLBACK_PASS_ON;
2899 _e_menu_cb_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event)
2901 Ecore_Event_Mouse_Move *ev;
2906 double fast_move_threshold;
2910 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2911 fast_move_threshold = e_config->menus_fast_mouse_move_threshhold;
2912 dx = ev->x - _e_menu_x;
2913 dy = ev->y - _e_menu_y;
2914 d = (dx * dx) + (dy * dy);
2915 dt = (double)(ev->timestamp - _e_menu_time) / 1000.0;
2917 if ((dt > 0.0) && ((d / dt) >= (fast_move_threshold * fast_move_threshold)))
2920 tmp = _e_active_menus_copy_ref();
2922 EINA_LIST_FOREACH(_e_active_menus, l, m)
2924 if ((m->realized) && (m->cur.visible))
2931 if (m->pending_new_submenu)
2935 mi = _e_menu_item_active_get();
2937 _e_menu_submenu_activate(mi);
2940 evas_event_feed_mouse_move(m->evas,
2941 ev->x - m->cur.x + m->zone->x,
2942 ev->y - m->cur.y + m->zone->y,
2943 ev->timestamp, NULL);
2947 _e_menu_list_free_unref(tmp);
2951 _e_menu_time = ev->timestamp;
2952 _e_menu_mouse_autoscroll_check();
2953 return ECORE_CALLBACK_PASS_ON;
2957 _e_menu_cb_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event)
2959 Ecore_Event_Mouse_Wheel *ev;
2962 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2963 if (ev->z < 0) /* up */
2967 for (i = ev->z; i < 0; i++)
2968 _e_menu_item_activate_previous();
2970 else if (ev->z > 0) /* down */
2974 for (i = ev->z; i > 0; i--)
2975 _e_menu_item_activate_next();
2977 return ECORE_CALLBACK_PASS_ON;
2981 _e_menu_cb_scroll_animator(void *data __UNUSED__)
2988 t = ecore_loop_time_get();
2989 spd = e_config->menus_scroll_speed;
2990 dt = t - _e_menu_scroll_start;
2991 _e_menu_scroll_start = t;
2994 if (_e_menu_autoscroll_x)
2996 out = _e_menu_outside_bounds_get(_e_menu_autoscroll_x, 0);
2997 dx = (-_e_menu_autoscroll_x) * spd * dt;
2998 if (_e_menu_autoscroll_x == -1)
3000 if (dx > out) dx = out;
3004 if (dx < -out) dx = -out;
3007 if (_e_menu_autoscroll_y)
3009 out = _e_menu_outside_bounds_get(0, _e_menu_autoscroll_y);
3010 dy = (-_e_menu_autoscroll_y) * spd * dt;
3011 if (_e_menu_autoscroll_y == -1)
3013 if (dy > out) dy = out;
3017 if (dy < -out) dy = -out;
3020 _e_menu_scroll_by(dx, dy);
3021 _e_menu_mouse_autoscroll_check();
3022 if ((_e_menu_autoscroll_x == 0) && (_e_menu_autoscroll_y == 0))
3024 _e_menu_scroll_animator = NULL;
3031 _e_menu_cb_window_shape(void *data __UNUSED__, int ev_type __UNUSED__, void *ev)
3034 Ecore_X_Event_Window_Shape *e;
3038 EINA_LIST_FOREACH(_e_active_menus, l, m)
3040 if (m->evas_win == e->win)
3041 m->need_shape_export = 1;
3043 return ECORE_CALLBACK_PASS_ON;
3047 _e_menu_cb_item_submenu_post_default(void *data __UNUSED__, E_Menu *m __UNUSED__, E_Menu_Item *mi)
3051 if (!mi->submenu) return;
3054 e_menu_item_submenu_set(mi, NULL);
3055 e_object_del(E_OBJECT(subm));
3059 _e_menu_categories_free_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
3061 E_Menu_Category_Callback *cb;
3062 E_Menu_Category *cat;
3064 cat = (E_Menu_Category *)data;
3065 EINA_LIST_FREE(cat->callbacks, cb)
3066 free(cb); /* free the callback struct */