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 /* local subsystem globals */
88 static Ecore_X_Window _e_menu_win = 0;
89 static Eina_List *_e_active_menus = NULL;
90 static Eina_Hash *_e_menu_hash = NULL;
91 static E_Menu_Item *_e_active_menu_item = NULL;
92 /*static Eina_Hash *_e_menu_category_items = NULL;*/
93 static Eina_Hash *_e_menu_categories = NULL;
94 static Ecore_X_Time _e_menu_activate_time = 0;
95 static int _e_menu_activate_floating = 0;
96 static int _e_menu_activate_maybe_drag = 0;
97 static int _e_menu_activate_dragging = 0;
98 static Ecore_Animator *_e_menu_scroll_animator = NULL;
99 static double _e_menu_scroll_start = 0.0;
100 static int _e_menu_x = 0;
101 static int _e_menu_y = 0;
102 static Ecore_X_Time _e_menu_time = 0;
103 static int _e_menu_autoscroll_x = 0;
104 static int _e_menu_autoscroll_y = 0;
105 static Ecore_Event_Handler *_e_menu_key_down_handler = NULL;
106 static Ecore_Event_Handler *_e_menu_key_up_handler = NULL;
107 static Ecore_Event_Handler *_e_menu_mouse_down_handler = NULL;
108 static Ecore_Event_Handler *_e_menu_mouse_up_handler = NULL;
109 static Ecore_Event_Handler *_e_menu_mouse_move_handler = NULL;
110 static Ecore_Event_Handler *_e_menu_mouse_wheel_handler = NULL;
111 static Ecore_Event_Handler *_e_menu_window_shape_handler = NULL;
114 _e_active_menus_copy_ref(void)
117 Eina_List *l, *ret = NULL;
119 EINA_LIST_FOREACH(_e_active_menus, l, o)
121 ret = eina_list_append(ret, o);
128 _e_menu_list_free_unref(Eina_List *l)
137 /* externally accessible functions */
141 _e_menu_key_down_handler =
142 ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_menu_cb_key_down, NULL);
143 _e_menu_key_up_handler =
144 ecore_event_handler_add(ECORE_EVENT_KEY_UP, _e_menu_cb_key_up, NULL);
145 _e_menu_mouse_down_handler =
146 ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN,
147 _e_menu_cb_mouse_down, NULL);
148 _e_menu_mouse_up_handler =
149 ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP,
150 _e_menu_cb_mouse_up, NULL);
151 _e_menu_mouse_move_handler =
152 ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE,
153 _e_menu_cb_mouse_move, NULL);
154 _e_menu_mouse_wheel_handler =
155 ecore_event_handler_add(ECORE_EVENT_MOUSE_WHEEL,
156 _e_menu_cb_mouse_wheel, NULL);
157 _e_menu_window_shape_handler =
158 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHAPE,
159 _e_menu_cb_window_shape, NULL);
160 _e_menu_categories = eina_hash_string_superfast_new(NULL);
162 if (!_e_menu_hash) _e_menu_hash = eina_hash_string_superfast_new(NULL);
167 e_menu_shutdown(void)
171 E_FN_DEL(ecore_event_handler_del, _e_menu_key_down_handler);
172 E_FN_DEL(ecore_event_handler_del, _e_menu_key_up_handler);
173 E_FN_DEL(ecore_event_handler_del, _e_menu_mouse_down_handler);
174 E_FN_DEL(ecore_event_handler_del, _e_menu_mouse_up_handler);
175 E_FN_DEL(ecore_event_handler_del, _e_menu_mouse_move_handler);
176 E_FN_DEL(ecore_event_handler_del, _e_menu_mouse_wheel_handler);
177 E_FN_DEL(ecore_event_handler_del, _e_menu_window_shape_handler);
181 EINA_LIST_FREE(_e_active_menus, m)
184 _e_menu_unrealize(m);
185 m->in_active_list = 0;
186 e_object_unref(E_OBJECT(m));
189 _e_active_menus = NULL;
190 if (_e_menu_categories)
192 eina_hash_foreach(_e_menu_categories, _e_menu_categories_free_cb, NULL);
193 eina_hash_free(_e_menu_categories);
194 _e_menu_categories = NULL;
199 eina_hash_free(_e_menu_hash);
211 m = E_OBJECT_ALLOC(E_Menu, E_MENU_TYPE, _e_menu_free);
221 e_menu_activate_key(E_Menu *m, E_Zone *zone, int x, int y, int w, int h, int dir)
224 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
225 E_OBJECT_CHECK(zone);
226 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
227 _e_menu_activate_time = 0;
228 _e_menu_activate_floating = 0;
229 _e_menu_activate_internal(m, zone);
232 e_menu_deactivate(m);
237 case E_MENU_POP_DIRECTION_LEFT:
239 m->cur.x = x - m->cur.w;
241 if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
242 m->cur.y = y + h - m->cur.h;
243 _e_menu_activate_first();
245 case E_MENU_POP_DIRECTION_RIGHT:
248 _e_menu_activate_first();
250 case E_MENU_POP_DIRECTION_UP:
253 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
254 m->cur.x = x + w - m->cur.w;
255 m->cur.y = y - m->cur.h;
256 _e_menu_activate_last();
258 case E_MENU_POP_DIRECTION_DOWN:
261 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
262 m->cur.x = x + w - m->cur.w;
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();
268 case E_MENU_POP_DIRECTION_AUTO:
272 pos = _e_menu_auto_place(m, x, y, w, h);
274 _e_menu_activate_last();
276 _e_menu_activate_first();
282 _e_menu_activate_first();
288 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)
293 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
294 E_OBJECT_CHECK(zone);
295 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
296 _e_menu_activate_time = activate_time;
297 _e_menu_activate_floating = 0;
298 _e_menu_activate_internal(m, zone);
301 e_menu_deactivate(m);
306 case E_MENU_POP_DIRECTION_LEFT:
308 m->cur.x = x - m->cur.w;
310 if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
311 m->cur.y = y + h - m->cur.h;
313 case E_MENU_POP_DIRECTION_RIGHT:
318 case E_MENU_POP_DIRECTION_UP:
321 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
322 m->cur.x = x + w - m->cur.w;
323 m->cur.y = y - m->cur.h;
325 case E_MENU_POP_DIRECTION_DOWN:
328 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
329 m->cur.x = x + w - m->cur.w;
331 if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
332 m->cur.y = y + h - m->cur.h;
334 case E_MENU_POP_DIRECTION_AUTO:
335 _e_menu_auto_place(m, x, y, w, h);
342 pmi = _e_menu_item_active_get();
343 if (pmi) e_menu_item_active_set(pmi, 0);
347 e_menu_activate(E_Menu *m, E_Zone *zone, int x, int y, int w, int h, int dir)
352 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
353 E_OBJECT_CHECK(zone);
354 E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
355 _e_menu_activate_time = 0;
356 _e_menu_activate_floating = 0;
357 _e_menu_activate_internal(m, zone);
360 e_menu_deactivate(m);
365 case E_MENU_POP_DIRECTION_LEFT:
367 m->cur.x = x - m->cur.w;
369 if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
370 m->cur.y = y + h - m->cur.h;
371 _e_menu_activate_first();
373 case E_MENU_POP_DIRECTION_RIGHT:
377 _e_menu_activate_first();
379 case E_MENU_POP_DIRECTION_UP:
382 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
383 m->cur.x = x + w - m->cur.w;
384 m->cur.y = y - m->cur.h;
385 _e_menu_activate_last();
387 case E_MENU_POP_DIRECTION_DOWN:
390 if ((m->cur.x + m->cur.w) > (m->zone->x + m->zone->w))
391 m->cur.x = x + w - m->cur.w;
393 if ((m->cur.y + m->cur.h) > (m->zone->y + m->zone->h))
394 m->cur.y = y + h - m->cur.h;
395 _e_menu_activate_first();
397 case E_MENU_POP_DIRECTION_AUTO:
398 _e_menu_auto_place(m, x, y, w, h);
405 pmi = _e_menu_item_active_get();
406 if (pmi) e_menu_item_active_set(pmi, 0);
410 e_menu_deactivate(E_Menu *m)
413 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
416 if (m->post_deactivate_cb.func)
417 m->post_deactivate_cb.func(m->post_deactivate_cb.data, m);
421 e_menu_freeze(E_Menu *m)
423 E_OBJECT_CHECK_RETURN(m, 0);
424 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, 0);
430 e_menu_thaw(E_Menu *m)
432 E_OBJECT_CHECK_RETURN(m, 0);
433 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, 0);
435 if (m->frozen < 0) m->frozen = 0;
440 e_menu_title_set(E_Menu *m, char *title)
443 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
444 if ((m->header.title) && (title) && (!strcmp(m->header.title, title)))
448 eina_stringshare_del(m->header.title);
449 m->header.title = NULL;
451 if (title) m->header.title = eina_stringshare_add(title);
452 else m->header.title = NULL;
457 e_menu_icon_file_set(E_Menu *m __UNUSED__, char *icon __UNUSED__)
459 /* FIXME: support menu icons
461 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
466 e_menu_category_set(E_Menu *m, char *category)
469 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
472 eina_stringshare_del(m->category);
476 m->category = eina_stringshare_add(category);
483 e_menu_category_data_set(char *category, void *data)
485 E_Menu_Category *cat;
487 cat = eina_hash_find(_e_menu_categories, category);
490 else /* if it isn't found create the new hash */
492 cat = calloc(1, sizeof(E_Menu_Category));
494 eina_hash_add(_e_menu_categories, category, cat);
498 EAPI E_Menu_Category_Callback *
499 e_menu_category_callback_add(char *category, void (*create) (E_Menu *m, void *category_data, void *data), void (*free) (void *data), void *data)
501 E_Menu_Category *cat;
502 E_Menu_Category_Callback *cb = NULL;
504 cat = eina_hash_find(_e_menu_categories, category);
505 if (!cat) /* if it isn't found create the new hash */
507 cat = calloc(1, sizeof(E_Menu_Category));
508 eina_hash_add(_e_menu_categories, category, cat);
512 cb = calloc(1, sizeof(E_Menu_Category_Callback));
518 cb->category = eina_stringshare_add(category);
519 cat->callbacks = eina_list_append(cat->callbacks, cb);
526 e_menu_category_callback_del(E_Menu_Category_Callback *cb)
528 E_Menu_Category *cat;
532 cat = eina_hash_find(_e_menu_categories, cb->category);
534 cat->callbacks = eina_list_remove(cat->callbacks, cb);
535 eina_stringshare_del(cb->category);
541 e_menu_pre_activate_callback_set(E_Menu *m, void (*func) (void *data, E_Menu *m), void *data)
544 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
545 m->pre_activate_cb.func = func;
546 m->pre_activate_cb.data = data;
550 e_menu_post_deactivate_callback_set(E_Menu *m, void (*func) (void *data, E_Menu *m), void *data)
553 E_OBJECT_TYPE_CHECK(m, E_MENU_TYPE);
554 m->post_deactivate_cb.func = func;
555 m->post_deactivate_cb.data = data;
559 e_menu_root_get(E_Menu *m)
563 E_OBJECT_CHECK_RETURN(m, NULL);
564 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
566 while ((ret->parent_item) && (ret->parent_item->menu))
567 ret = ret->parent_item->menu;
573 e_menu_item_new(E_Menu *m)
577 E_OBJECT_CHECK_RETURN(m, NULL);
578 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
579 mi = E_OBJECT_ALLOC(E_Menu_Item, E_MENU_ITEM_TYPE, _e_menu_item_free);
581 mi->menu->items = eina_list_append(mi->menu->items, mi);
582 mi->list_position = eina_list_last(mi->menu->items);
587 e_menu_item_new_relative(E_Menu *m, E_Menu_Item *rel)
590 E_OBJECT_CHECK_RETURN(m, NULL);
591 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
594 E_OBJECT_CHECK_RETURN(rel, NULL);
595 E_OBJECT_TYPE_CHECK_RETURN(rel, E_MENU_ITEM_TYPE, NULL);
596 if (rel->menu != m) return NULL;
599 mi = E_OBJECT_ALLOC(E_Menu_Item, E_MENU_ITEM_TYPE, _e_menu_item_free);
606 l = eina_list_data_find_list(m->items, rel);
607 m->items = eina_list_append_relative_list(m->items, mi, l);
608 mi->list_position = eina_list_data_find_list(m->items, mi);
612 m->items = eina_list_prepend(m->items, mi);
613 mi->list_position = m->items;
620 e_menu_item_nth(E_Menu *m, int n)
622 E_OBJECT_CHECK_RETURN(m, NULL);
623 E_OBJECT_TYPE_CHECK_RETURN(m, E_MENU_TYPE, NULL);
624 return (E_Menu_Item *)eina_list_nth(m->items, n);
628 e_menu_item_num_get(const E_Menu_Item *mi)
631 const E_Menu_Item *mi2;
634 E_OBJECT_CHECK_RETURN(mi, -1);
635 E_OBJECT_CHECK_RETURN(mi->menu, -1);
636 E_OBJECT_TYPE_CHECK_RETURN(mi, E_MENU_TYPE, -1);
637 EINA_LIST_FOREACH(mi->menu->items, l, mi2)
639 if (mi2 == mi) return i;
646 e_menu_item_icon_file_set(E_Menu_Item *mi, const char *icon)
650 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
651 if (((mi->icon) && (icon) && (!strcmp(icon, mi->icon))) ||
652 ((!mi->icon) && (!icon)))
654 if (mi->icon) eina_stringshare_del(mi->icon);
655 if (mi->icon_key) eina_stringshare_del(mi->icon_key);
660 mi->icon = eina_stringshare_add(icon);
662 if ((len > 4) && (!strcasecmp(icon + len - 4, ".edj")))
663 mi->icon_key = eina_stringshare_add("icon");
666 mi->menu->changed = 1;
670 e_menu_item_icon_edje_set(E_Menu_Item *mi, const char *icon, const char *key)
673 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
674 if (((mi->icon) && (icon) && (!strcmp(icon, mi->icon))) ||
675 ((!mi->icon) && (!icon)) ||
676 ((key) && (mi->icon_key) && (!strcmp(key, mi->icon_key))))
678 if (mi->icon) eina_stringshare_del(mi->icon);
679 if (mi->icon_key) eina_stringshare_del(mi->icon_key);
682 if (icon) mi->icon = eina_stringshare_add(icon);
683 if (key) mi->icon_key = eina_stringshare_add(key);
685 mi->menu->changed = 1;
689 e_menu_item_label_set(E_Menu_Item *mi, const char *label)
692 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
693 if (((mi->label) && (label) && (!strcmp(label, mi->label))) ||
694 ((!mi->label) && (!label)))
696 if (mi->label) eina_stringshare_del(mi->label);
698 if (label) mi->label = eina_stringshare_add(label);
700 mi->menu->changed = 1;
704 e_menu_item_submenu_set(E_Menu_Item *mi, E_Menu *sub)
707 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
708 if (mi->submenu) e_object_unref(E_OBJECT(mi->submenu));
709 if (sub) e_object_ref(E_OBJECT(sub));
712 mi->menu->changed = 1;
716 e_menu_item_separator_set(E_Menu_Item *mi, int sep)
719 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
720 if (((mi->separator) && (sep)) || ((!mi->separator) && (!sep))) return;
723 mi->menu->changed = 1;
727 e_menu_item_check_set(E_Menu_Item *mi, int chk)
730 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
731 if (((mi->check) && (chk)) || ((!mi->check) && (!chk))) return;
734 mi->menu->changed = 1;
738 e_menu_item_radio_set(E_Menu_Item *mi, int rad)
741 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
742 if (((mi->radio) && (rad)) || ((!mi->radio) && (!rad))) return;
745 mi->menu->changed = 1;
749 e_menu_item_radio_group_set(E_Menu_Item *mi, int radg)
752 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
753 if (mi->radio_group == radg) return;
754 mi->radio_group = radg;
756 mi->menu->changed = 1;
760 e_menu_item_toggle_set(E_Menu_Item *mi, int tog)
763 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
764 if (mi->separator) return;
769 edje_object_signal_emit(mi->bg_object, "e,state,on", "e");
770 if (mi->icon_bg_object)
771 edje_object_signal_emit(mi->icon_bg_object, "e,state,on", "e");
772 if (mi->label_object)
773 edje_object_signal_emit(mi->label_object, "e,state,on", "e");
774 if (mi->submenu_object)
775 edje_object_signal_emit(mi->submenu_object, "e,state,on", "e");
776 if (mi->toggle_object)
777 edje_object_signal_emit(mi->toggle_object, "e,state,on", "e");
778 if (mi->menu->bg_object)
779 edje_object_signal_emit(mi->menu->bg_object, "e,state,on", "e");
785 edje_object_signal_emit(mi->bg_object, "e,state,off", "e");
786 if (mi->icon_bg_object)
787 edje_object_signal_emit(mi->icon_bg_object, "e,state,off", "e");
788 if (mi->label_object)
789 edje_object_signal_emit(mi->label_object, "e,state,off", "e");
790 if (mi->submenu_object)
791 edje_object_signal_emit(mi->submenu_object, "e,state,off", "e");
792 if (mi->toggle_object)
793 edje_object_signal_emit(mi->toggle_object, "e,state,off", "e");
794 if (mi->menu->bg_object)
795 edje_object_signal_emit(mi->menu->bg_object, "e,state,off", "e");
804 EINA_LIST_FOREACH(mi->menu->items, l, mi2)
806 if ((mi2 != mi) && (mi2->radio) &&
807 (mi2->radio_group == mi->radio_group))
808 e_menu_item_toggle_set(mi2, 0);
815 e_menu_item_toggle_get(E_Menu_Item *mi)
817 E_OBJECT_CHECK_RETURN(mi, 0);
818 E_OBJECT_TYPE_CHECK_RETURN(mi, E_MENU_ITEM_TYPE, 0);
823 e_menu_item_callback_set(E_Menu_Item *mi, void (*func) (void *data, E_Menu *m, E_Menu_Item *mi), void *data)
826 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
832 e_menu_item_realize_callback_set(E_Menu_Item *mi, void (*func) (void *data, E_Menu *m, E_Menu_Item *mi), void *data)
835 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
836 mi->realize_cb.func = func;
837 mi->realize_cb.data = data;
841 e_menu_item_submenu_pre_callback_set(E_Menu_Item *mi, void (*func) (void *data, E_Menu *m, E_Menu_Item *mi), void *data)
844 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
845 mi->submenu_pre_cb.func = func;
846 mi->submenu_pre_cb.data = data;
847 if (!mi->submenu_post_cb.func)
848 mi->submenu_post_cb.func = _e_menu_cb_item_submenu_post_default;
852 e_menu_item_submenu_post_callback_set(E_Menu_Item *mi, void (*func) (void *data, E_Menu *m, E_Menu_Item *mi), void *data)
855 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
856 mi->submenu_post_cb.func = func;
857 mi->submenu_post_cb.data = data;
861 e_menu_item_drag_callback_set(E_Menu_Item *mi, void (*func) (void *data, E_Menu *m, E_Menu_Item *mi), void *data)
864 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
865 mi->drag_cb.func = func;
866 mi->drag_cb.data = data;
870 e_menu_item_active_set(E_Menu_Item *mi, int active)
873 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
874 if (mi->separator) return;
875 if ((active) && (!mi->active))
879 if (mi->disable) return;
880 pmi = _e_menu_item_active_get();
881 if (mi == pmi) return;
882 if (pmi) e_menu_item_active_set(pmi, 0);
884 _e_active_menu_item = mi;
886 edje_object_signal_emit(mi->bg_object, "e,state,selected", "e");
887 if (mi->icon_bg_object)
888 edje_object_signal_emit(mi->icon_bg_object, "e,state,selected", "e");
889 if (mi->label_object)
890 edje_object_signal_emit(mi->label_object, "e,state,selected", "e");
891 if (mi->submenu_object)
892 edje_object_signal_emit(mi->submenu_object, "e,state,selected", "e");
893 if (mi->toggle_object)
894 edje_object_signal_emit(mi->toggle_object, "e,state,selected", "e");
899 if (strcmp(evas_object_type_get(mi->icon_object), "e_icon"))
900 edje_object_signal_emit(mi->icon_object, "e,state,selected", "e");
902 e_icon_selected_set(mi->icon_object, EINA_TRUE);
905 edje_object_signal_emit(mi->menu->bg_object, "e,state,selected", "e");
906 _e_menu_submenu_activate(mi);
908 else if ((!active) && (mi->active))
911 _e_active_menu_item = NULL;
913 edje_object_signal_emit(mi->bg_object, "e,state,unselected", "e");
914 if (mi->icon_bg_object)
915 edje_object_signal_emit(mi->icon_bg_object, "e,state,unselected", "e");
916 if (mi->label_object)
917 edje_object_signal_emit(mi->label_object, "e,state,unselected", "e");
918 if (mi->submenu_object)
919 edje_object_signal_emit(mi->submenu_object, "e,state,unselected", "e");
920 if (mi->toggle_object)
921 edje_object_signal_emit(mi->toggle_object, "e,state,unselected", "e");
926 if (strcmp(evas_object_type_get(mi->icon_object), "e_icon"))
927 edje_object_signal_emit(mi->icon_object, "e,state,unselected", "e");
929 e_icon_selected_set(mi->icon_object, EINA_FALSE);
932 edje_object_signal_emit(mi->menu->bg_object, "e,state,unselected", "e");
933 _e_menu_submenu_deactivate(mi);
938 e_menu_item_disabled_set(E_Menu_Item *mi, int disable)
941 E_OBJECT_TYPE_CHECK(mi, E_MENU_ITEM_TYPE);
942 if (mi->separator) return;
945 if (mi->active) e_menu_item_active_set(mi, 0);
947 if (mi->icon_bg_object)
948 edje_object_signal_emit(mi->icon_bg_object, "e,state,disable", "e");
949 if (mi->label_object)
950 edje_object_signal_emit(mi->label_object, "e,state,disable", "e");
951 if (mi->toggle_object)
952 edje_object_signal_emit(mi->toggle_object, "e,state,disable", "e");
957 if (mi->icon_bg_object)
958 edje_object_signal_emit(mi->icon_bg_object, "e,state,enable", "e");
959 if (mi->label_object)
960 edje_object_signal_emit(mi->label_object, "e,state,enable", "e");
961 if (mi->toggle_object)
962 edje_object_signal_emit(mi->toggle_object, "e,state,enable", "e");
968 e_menu_idler_before(void)
970 /* when e goes "idle" this gets called so leave all our hard work till */
971 /* idle time to avoid falling behind the user. just evaluate the high */
972 /* level state machine */
973 Eina_List *l, *removals = NULL, *tmp;
976 /* add refcount to all menus we will work with */
977 tmp = _e_active_menus_copy_ref();
978 /* phase 1. hide all the menus that want to be hidden */
979 EINA_LIST_FOREACH(_e_active_menus, l, m)
981 if ((!m->cur.visible) && (m->prev.visible))
983 m->prev.visible = m->cur.visible;
984 ecore_evas_hide(m->ecore_evas);
985 e_container_shape_hide(m->shape);
988 /* phase 2. move & reisze all the menus that want to moves/resized */
989 EINA_LIST_FOREACH(_e_active_menus, l, m)
991 if (!m->realized) _e_menu_realize(m);
994 if (((m->cur.w) != (m->prev.w)) ||
995 ((m->cur.h) != (m->prev.h)))
997 m->prev.w = m->cur.w;
998 m->prev.h = m->cur.h;
999 ecore_evas_resize(m->ecore_evas, m->cur.w, m->cur.h);
1000 e_container_shape_resize(m->shape, m->cur.w, m->cur.h);
1002 if (((m->cur.x) != (m->prev.x)) ||
1003 ((m->cur.y) != (m->prev.y)))
1005 m->prev.x = m->cur.x;
1006 m->prev.y = m->cur.y;
1007 ecore_evas_move(m->ecore_evas, m->cur.x, m->cur.y);
1008 e_container_shape_move(m->shape, m->cur.x, m->cur.y);
1012 /* phase 3. show all the menus that want to be shown */
1013 EINA_LIST_FOREACH(_e_active_menus, l, m)
1015 if ((m->cur.visible) && (!m->prev.visible))
1017 m->prev.visible = m->cur.visible;
1018 ecore_evas_raise(m->ecore_evas);
1019 ecore_evas_show(m->ecore_evas);
1020 if (!m->shaped) e_container_shape_show(m->shape);
1023 /* phase 4. de-activate... */
1024 EINA_LIST_FOREACH(_e_active_menus, l, m)
1028 _e_menu_unrealize(m);
1029 removals = eina_list_append(removals, m);
1032 EINA_LIST_FREE(removals, m)
1034 if (m->in_active_list)
1036 _e_active_menus = eina_list_remove(_e_active_menus, m);
1037 m->in_active_list = 0;
1038 e_object_unref(E_OBJECT(m));
1041 /* phase 5. shapes... */
1042 EINA_LIST_FOREACH(_e_active_menus, l, m)
1044 if (m->need_shape_export)
1046 Ecore_X_Rectangle *rects, *orects;
1049 rects = ecore_x_window_shape_rectangles_get(m->evas_win, &num);
1054 if ((num == m->shape_rects_num) && (m->shape_rects))
1058 orects = m->shape_rects;
1059 for (i = 0; i < num; i++)
1061 if ((orects[i].x != rects[i].x) ||
1062 (orects[i].y != rects[i].y) ||
1063 (orects[i].width != rects[i].width) ||
1064 (orects[i].height != rects[i].height))
1070 // TODO: This is meaningless
1075 E_FREE(m->shape_rects);
1076 m->shape_rects = rects;
1077 m->shape_rects_num = num;
1078 e_container_shape_rects_set(m->shape, rects, num);
1085 E_FREE(m->shape_rects);
1086 m->shape_rects = NULL;
1087 m->shape_rects_num = 0;
1088 e_container_shape_rects_set(m->shape, NULL, 0);
1090 m->need_shape_export = 0;
1091 if (m->cur.visible) e_container_shape_show(m->shape);
1094 /* del refcount to all menus we worked with */
1095 _e_menu_list_free_unref(tmp);
1097 if (!_e_active_menus)
1101 ecore_x_window_free(_e_menu_win);
1102 e_grabinput_release(_e_menu_win, _e_menu_win);
1109 e_menu_grab_window_get(void)
1115 e_menu_find_by_window(Ecore_X_Window win)
1119 m = eina_hash_find(_e_menu_hash, e_util_winid_str_get(win));
1120 if ((m) && (m->evas_win != win))
1126 /* local subsystem functions */
1128 _e_menu_free(E_Menu *m)
1130 Eina_List *l, *l_next;
1132 E_Menu_Category *cat = NULL;
1134 /* the foreign menu items */
1135 if (m->category) cat = eina_hash_find(_e_menu_categories, m->category);
1138 E_Menu_Category_Callback *cb;
1140 EINA_LIST_FOREACH(cat->callbacks, l, cb)
1142 if (cb->free) cb->free(cb->data);
1145 _e_menu_unrealize(m);
1146 E_FREE(m->shape_rects);
1147 m->shape_rects_num = 0;
1148 EINA_LIST_FOREACH_SAFE(m->items, l, l_next, mi)
1149 e_object_del(E_OBJECT(mi));
1150 if (m->in_active_list)
1152 _e_active_menus = eina_list_remove(_e_active_menus, m);
1153 m->in_active_list = 0;
1154 e_object_unref(E_OBJECT(m));
1156 if (m->header.title) eina_stringshare_del(m->header.title);
1157 if (m->header.icon_file) eina_stringshare_del(m->header.icon_file);
1162 _e_menu_item_free(E_Menu_Item *mi)
1164 if (mi == _e_active_menu_item) _e_active_menu_item = NULL;
1167 mi->submenu->parent_item = NULL;
1168 e_object_unref(E_OBJECT(mi->submenu)); /* added on submenu_set() */
1169 /* e_object_del(E_OBJECT(mi->submenu)); */
1171 if (mi->menu->realized) _e_menu_item_unrealize(mi);
1172 mi->menu->items = eina_list_remove(mi->menu->items, mi);
1173 if (mi->icon) eina_stringshare_del(mi->icon);
1174 if (mi->icon_key) eina_stringshare_del(mi->icon_key);
1175 if (mi->label) eina_stringshare_del(mi->label);
1180 _e_menu_cb_intercept_item_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y)
1187 evas_object_move(mi->event_object, x, y);
1188 evas_object_move(o, x, y);
1189 if ((mi->submenu) && (mi->submenu->parent_item))
1190 _e_menu_reposition(mi->submenu);
1194 _e_menu_cb_intercept_item_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h)
1201 evas_object_resize(mi->event_object, w, h);
1202 evas_object_resize(o, w, h);
1203 if ((mi->submenu) && (mi->submenu->parent_item))
1204 _e_menu_reposition(mi->submenu);
1208 _e_menu_cb_intercept_container_move(void *data, Evas_Object *o, Evas_Coord x, Evas_Coord y)
1215 if (m->parent_item) _e_menu_reposition(m);
1216 evas_object_move(o, x, y);
1220 _e_menu_cb_intercept_container_resize(void *data, Evas_Object *o, Evas_Coord w, Evas_Coord h)
1227 if (m->parent_item) _e_menu_reposition(m);
1228 evas_object_resize(o, w, h);
1232 _e_menu_item_realize(E_Menu_Item *mi)
1237 /* and set up initial item state */
1240 o = edje_object_add(mi->menu->evas);
1241 mi->separator_object = o;
1242 e_theme_edje_object_set(o, "base/theme/menus",
1243 "e/widgets/menu/default/separator");
1244 evas_object_show(o);
1245 edje_object_size_min_calc(mi->separator_object, &ww, &hh);
1246 mi->separator_w = ww;
1247 mi->separator_h = hh;
1248 e_box_pack_end(mi->menu->container_object, mi->separator_object);
1252 o = edje_object_add(mi->menu->evas);
1254 evas_object_intercept_move_callback_add (o, _e_menu_cb_intercept_item_move, mi);
1255 evas_object_intercept_resize_callback_add(o, _e_menu_cb_intercept_item_resize, mi);
1257 if ((mi->submenu) || (mi->submenu_pre_cb.func))
1259 if (!e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
1260 "e/widgets/menu/default/submenu_bg"))
1261 goto no_submenu_item;
1266 e_theme_edje_object_set(mi->bg_object, "base/theme/menus",
1267 "e/widgets/menu/default/item_bg");
1269 evas_object_show(o);
1271 o = e_box_add(mi->menu->evas);
1272 e_box_homogenous_set(o, 0);
1273 mi->container_object = o;
1274 e_box_orientation_set(o, 1);
1275 evas_object_show(o);
1277 e_box_freeze(mi->container_object);
1281 o = edje_object_add(mi->menu->evas);
1282 mi->toggle_object = o;
1283 e_theme_edje_object_set(o, "base/theme/menus",
1284 "e/widgets/menu/default/check");
1285 evas_object_pass_events_set(o, 1);
1286 evas_object_show(o);
1287 e_box_pack_end(mi->container_object, o);
1288 edje_object_size_min_calc(mi->toggle_object, &ww, &hh);
1294 o = edje_object_add(mi->menu->evas);
1295 mi->toggle_object = o;
1296 e_theme_edje_object_set(o, "base/theme/menus",
1297 "e/widgets/menu/default/radio");
1298 evas_object_pass_events_set(o, 1);
1299 evas_object_show(o);
1300 e_box_pack_end(mi->container_object, o);
1301 edje_object_size_min_calc(mi->toggle_object, &ww, &hh);
1307 o = evas_object_rectangle_add(mi->menu->evas);
1308 mi->toggle_object = o;
1309 evas_object_color_set(o, 0, 0, 0, 0);
1310 evas_object_pass_events_set(o, 1);
1311 e_box_pack_end(mi->container_object, o);
1313 if ((mi->icon) || (mi->realize_cb.func))
1315 int icon_w = 0, icon_h = 0;
1317 o = edje_object_add(mi->menu->evas);
1318 if (e_theme_edje_object_set(o, "base/theme/menus",
1319 "e/widgets/menu/default/icon"))
1321 mi->icon_bg_object = o;
1322 evas_object_show(o);
1330 /* FIXME: Not sure why there are two different tries to get the icon size, surely only the last one si needed. */
1331 /* 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.
1334 o = e_app_icon_add(mi->menu->evas, mi->app);
1335 mi->icon_object = o;
1336 e_icon_size_get(mi->icon_object, &icon_w, &icon_h);
1342 /* This is done this way to match up with how e_app_icon_add does it. */
1345 Evas_Coord iww, ihh;
1347 o = edje_object_add(mi->menu->evas);
1348 if (edje_object_file_set(o, mi->icon, mi->icon_key))
1350 mi->icon_object = o;
1351 edje_object_size_max_get(o, &iww, &ihh);
1361 if (!mi->icon_object)
1363 o = e_icon_add(mi->menu->evas);
1364 mi->icon_object = o;
1365 e_icon_scale_size_set(o, e_util_icon_size_normalize(24 * e_scale));
1366 e_icon_preload_set(mi->icon_object, 1);
1367 e_icon_file_set(o, mi->icon);
1368 e_icon_fill_inside_set(mi->icon_object, 1);
1369 e_icon_size_get(mi->icon_object, &icon_w, &icon_h);
1372 if (_e_menu_realize_call(mi))
1374 o = mi->icon_object;
1375 e_icon_fill_inside_set(o, 1);
1376 e_icon_size_get(o, &icon_w, &icon_h);
1379 evas_object_pass_events_set(o, 1);
1380 evas_object_show(o);
1382 if (mi->icon_bg_object)
1384 edje_extern_object_min_size_set(mi->icon_object,
1386 edje_object_part_swallow(mi->icon_bg_object,
1387 "e.swallow.content",
1389 edje_object_size_min_calc(mi->icon_bg_object, &ww, &hh);
1393 edje_extern_object_min_size_set(mi->icon_object, 0, 0);
1394 edje_object_part_swallow(mi->icon_bg_object,
1395 "e.swallow.content",
1397 e_box_pack_end(mi->container_object, mi->icon_bg_object);
1401 int icon_w = 0, icon_h = 0;
1403 o = edje_object_add(mi->menu->evas);
1404 e_icon_size_get(mi->icon_object, &icon_w, &icon_h);
1405 mi->icon_w = icon_w;
1406 mi->icon_h = icon_h;
1407 e_box_pack_end(mi->container_object, o);
1412 o = evas_object_rectangle_add(mi->menu->evas);
1413 mi->icon_object = o;
1414 evas_object_color_set(o, 0, 0, 0, 0);
1415 evas_object_pass_events_set(o, 1);
1416 e_box_pack_end(mi->container_object, o);
1421 o = edje_object_add(mi->menu->evas);
1422 mi->label_object = o;
1423 e_theme_edje_object_set(o, "base/theme/menus",
1424 "e/widgets/menu/default/label");
1426 edje_object_part_text_set(o, "e.text.label", mi->label);
1427 evas_object_pass_events_set(o, 1);
1428 evas_object_show(o);
1429 e_box_pack_end(mi->container_object, o);
1430 edje_object_size_min_calc(mi->label_object, &ww, &hh);
1436 o = evas_object_rectangle_add(mi->menu->evas);
1437 mi->label_object = o;
1438 evas_object_color_set(o, 0, 0, 0, 0);
1439 evas_object_pass_events_set(o, 1);
1440 e_box_pack_end(mi->container_object, o);
1442 if ((mi->submenu) || (mi->submenu_pre_cb.func))
1444 o = edje_object_add(mi->menu->evas);
1445 mi->submenu_object = o;
1446 e_theme_edje_object_set(o, "base/theme/menus",
1447 "e/widgets/menu/default/submenu");
1448 evas_object_pass_events_set(o, 1);
1449 evas_object_show(o);
1450 e_box_pack_end(mi->container_object, o);
1451 edje_object_size_min_calc(mi->submenu_object, &ww, &hh);
1457 o = evas_object_rectangle_add(mi->menu->evas);
1458 mi->submenu_object = o;
1459 evas_object_color_set(o, 0, 0, 0, 0);
1460 evas_object_pass_events_set(o, 1);
1461 e_box_pack_end(mi->container_object, o);
1464 edje_object_part_swallow(mi->bg_object, "e.swallow.content",
1465 mi->container_object);
1467 o = evas_object_rectangle_add(mi->menu->evas);
1468 evas_object_color_set(o, 0, 0, 0, 0);
1469 evas_object_layer_set(o, 1);
1470 evas_object_repeat_events_set(o, 1);
1471 evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_IN,
1472 _e_menu_cb_item_in, mi);
1473 evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_OUT,
1474 _e_menu_cb_item_out, mi);
1475 evas_object_show(o);
1476 mi->event_object = o;
1478 e_box_thaw(mi->container_object);
1479 e_box_pack_end(mi->menu->container_object, mi->bg_object);
1481 if (mi->active) e_menu_item_active_set(mi, 1);
1482 if (mi->toggle) e_menu_item_toggle_set(mi, 1);
1483 if (mi->disable) e_menu_item_disabled_set(mi, 1);
1487 _e_menu_realize(E_Menu *m)
1494 if (m->realized) return;
1497 e_canvas_new(e_config->evas_engine_menus, m->zone->container->win,
1498 m->cur.x, m->cur.y, m->cur.w, m->cur.h, 1, 1,
1500 e_canvas_add(m->ecore_evas);
1501 eina_hash_add(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1502 m->shape = e_container_shape_add(m->zone->container);
1503 e_container_shape_move(m->shape, m->cur.x, m->cur.y);
1504 e_container_shape_resize(m->shape, m->cur.w, m->cur.h);
1506 ecore_evas_callback_resize_set(m->ecore_evas, _e_menu_cb_ecore_evas_resize);
1507 m->evas = ecore_evas_get(m->ecore_evas);
1508 evas_event_freeze(m->evas);
1509 /* move cursor out to avoid event cycles during setup */
1510 evas_event_feed_mouse_in(m->evas, ecore_x_current_time_get(), NULL);
1511 evas_event_feed_mouse_move(m->evas, -1000000, -1000000,
1512 ecore_x_current_time_get(), NULL);
1513 ecore_x_window_shape_events_select(m->evas_win, 1);
1514 ecore_evas_name_class_set(m->ecore_evas, "E", "_e_menu_window");
1515 ecore_evas_title_set(m->ecore_evas, "E Menu");
1517 o = edje_object_add(m->evas);
1519 evas_object_name_set(o, "menu/background");
1520 evas_object_data_set(o, "e_menu", m);
1521 evas_object_move(o, 0, 0);
1522 evas_object_resize(o, m->cur.w, m->cur.h);
1523 ok = e_theme_edje_object_set(o, "base/theme/menus",
1524 "e/widgets/menu/default/background");
1527 const char *shape_option;
1529 shape_option = edje_object_data_get(o, "shaped");
1532 if (!strcmp(shape_option, "1")) m->shaped = 1;
1535 if (m->header.title)
1537 edje_object_part_text_set(o, "e.text.title", m->header.title);
1538 edje_object_signal_emit(o, "e,action,show,title", "e");
1539 edje_object_message_signal_process(o);
1541 evas_object_show(o);
1545 if (e_config->use_composite)
1547 ecore_evas_alpha_set(m->ecore_evas, m->shaped);
1549 eina_hash_del(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1550 m->evas_win = ecore_evas_software_x11_window_get(m->ecore_evas);
1551 eina_hash_add(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1554 ecore_evas_shaped_set(m->ecore_evas, m->shaped);
1557 ecore_x_netwm_window_type_set(m->evas_win, ECORE_X_WINDOW_TYPE_MENU);
1559 o = e_box_add(m->evas);
1560 m->container_object = o;
1561 evas_object_intercept_move_callback_add(o, _e_menu_cb_intercept_container_move, m);
1562 evas_object_intercept_resize_callback_add(o, _e_menu_cb_intercept_container_resize, m);
1564 evas_object_show(o);
1565 e_box_homogenous_set(o, 0);
1566 edje_object_part_swallow(m->bg_object, "e.swallow.content", m->container_object);
1568 EINA_LIST_FOREACH(m->items, l, mi)
1569 _e_menu_item_realize(mi);
1571 _e_menu_items_layout_update(m);
1572 e_box_thaw(m->container_object);
1573 evas_object_resize(m->bg_object, m->cur.w, m->cur.h);
1574 evas_event_thaw(m->evas);
1578 _e_menu_items_layout_update(E_Menu *m)
1582 Evas_Coord bw, bh, mw, mh;
1586 int submenus_on = 0;
1587 int min_icon_w = 0, min_icon_h = 0;
1588 int min_label_w = 0, min_label_h = 0;
1589 int min_submenu_w = 0, min_submenu_h = 0;
1590 int min_toggle_w = 0, min_toggle_h = 0;
1591 int min_w = 0, min_h = 0;
1593 e_box_freeze(m->container_object);
1594 EINA_LIST_FOREACH(m->items, l, mi)
1596 if (mi->icon) icons_on = 1;
1597 if (mi->icon_object) icons_on = 1;
1598 if (mi->label) labels_on = 1;
1599 if (mi->submenu) submenus_on = 1;
1600 if (mi->check) toggles_on = 1;
1601 if (mi->radio) toggles_on = 1;
1603 if (mi->icon_w > min_icon_w) min_icon_w = mi->icon_w;
1604 if (mi->icon_h > min_icon_h) min_icon_h = mi->icon_h;
1605 if (mi->label_w > min_label_w) min_label_w = mi->label_w;
1606 if (mi->label_h > min_label_h) min_label_h = mi->label_h;
1607 if (mi->submenu_w > min_submenu_w) min_submenu_w = mi->submenu_w;
1608 if (mi->submenu_h > min_submenu_h) min_submenu_h = mi->submenu_h;
1609 if (mi->toggle_w > min_toggle_w) min_toggle_w = mi->toggle_w;
1610 if (mi->toggle_h > min_toggle_h) min_toggle_h = mi->toggle_h;
1616 if (min_label_h < min_submenu_h)
1617 min_label_h = min_submenu_h;
1621 if (min_label_h < min_toggle_h)
1622 min_label_h = min_toggle_h;
1624 if ((icons_on) && (min_icon_h > 0))
1626 min_icon_w = (min_icon_w * min_label_h) / min_icon_h;
1627 min_icon_h = min_label_h;
1629 min_w = min_label_w + min_icon_w + min_submenu_w + min_toggle_w;
1630 min_h = min_label_h;
1636 if (min_icon_h < min_submenu_h)
1637 min_icon_h = min_submenu_h;
1641 if (min_icon_h < min_toggle_h)
1642 min_icon_h = min_toggle_h;
1644 min_w = min_icon_w + min_toggle_w + min_submenu_w;
1647 else if (toggles_on)
1651 if (min_toggle_h < min_submenu_h)
1652 min_toggle_h = min_submenu_h;
1654 min_w = min_toggle_w + min_submenu_w;
1655 min_h = min_toggle_h;
1657 EINA_LIST_FOREACH(m->items, l, mi)
1661 e_box_pack_options_set(mi->separator_object,
1664 0.5, 0.5, /* align */
1665 mi->separator_w, mi->separator_h, /* min */
1666 -1, mi->separator_h /* max */
1671 e_box_freeze(mi->container_object);
1673 e_box_pack_options_set(mi->toggle_object,
1676 0.5, 0.5, /* align */
1677 min_toggle_w, min_toggle_h, /* min */
1681 e_box_pack_options_set(mi->toggle_object,
1684 0.5, 0.5, /* align */
1690 if (mi->icon_bg_object)
1691 e_box_pack_options_set(mi->icon_bg_object,
1694 0.5, 0.5, /* align */
1695 min_icon_w, min_icon_h, /* min */
1699 e_box_pack_options_set(mi->icon_object,
1702 0.5, 0.5, /* align */
1703 min_icon_w, min_icon_h, /* min */
1708 e_box_pack_options_set(mi->icon_object,
1711 0.5, 0.5, /* align */
1716 e_box_pack_options_set(mi->label_object,
1719 0.5, 0.5, /* align */
1720 min_label_w, min_label_h, /* min */
1724 e_box_pack_options_set(mi->label_object,
1727 0.5, 0.5, /* align */
1732 e_box_pack_options_set(mi->submenu_object,
1735 0.5, 0.5, /* align */
1736 min_submenu_w, min_submenu_h, /* min */
1740 e_box_pack_options_set(mi->submenu_object,
1743 0.5, 0.5, /* align */
1747 edje_extern_object_min_size_set(mi->container_object,
1749 edje_object_part_swallow(mi->bg_object, "e.swallow.content",
1750 mi->container_object);
1751 edje_object_size_min_calc(mi->bg_object, &mw, &mh);
1752 e_box_pack_options_set(mi->bg_object,
1755 0.5, 0.5, /* align */
1759 e_box_thaw(mi->container_object);
1762 e_box_size_min_get(m->container_object, &bw, &bh);
1763 edje_extern_object_min_size_set(m->container_object, bw, bh);
1764 edje_extern_object_max_size_set(m->container_object, bw, bh);
1765 edje_object_part_swallow(m->bg_object, "e.swallow.content", m->container_object);
1766 edje_object_size_min_calc(m->bg_object, &mw, &mh);
1767 e_box_thaw(m->container_object);
1773 _e_menu_item_unrealize(E_Menu_Item *mi)
1775 if (mi->container_object) e_box_freeze(mi->container_object);
1776 if (mi->separator_object) evas_object_del(mi->separator_object);
1777 mi->separator_object = NULL;
1778 if (mi->bg_object) evas_object_del(mi->bg_object);
1779 mi->bg_object = NULL;
1780 if (mi->container_object) evas_object_del(mi->container_object);
1781 mi->container_object = NULL;
1782 if (mi->toggle_object) evas_object_del(mi->toggle_object);
1783 mi->toggle_object = NULL;
1784 if (mi->icon_bg_object) evas_object_del(mi->icon_bg_object);
1785 mi->icon_bg_object = NULL;
1786 if (mi->icon_object) evas_object_del(mi->icon_object);
1787 mi->icon_object = NULL;
1788 if (mi->label_object) evas_object_del(mi->label_object);
1789 mi->label_object = NULL;
1790 if (mi->submenu_object) evas_object_del(mi->submenu_object);
1791 mi->submenu_object = NULL;
1792 if (mi->event_object) evas_object_del(mi->event_object);
1793 mi->event_object = NULL;
1797 _e_menu_unrealize(E_Menu *m)
1802 if (!m->realized) return;
1803 evas_event_freeze(m->evas);
1804 e_container_shape_hide(m->shape);
1805 e_object_del(E_OBJECT(m->shape));
1807 e_box_freeze(m->container_object);
1808 EINA_LIST_FOREACH(m->items, l, mi)
1809 _e_menu_item_unrealize(mi);
1810 if (m->header.icon) evas_object_del(m->header.icon);
1811 m->header.icon = NULL;
1812 if (m->bg_object) evas_object_del(m->bg_object);
1813 m->bg_object = NULL;
1814 if (m->container_object) evas_object_del(m->container_object);
1815 m->container_object = NULL;
1817 m->prev.visible = 0;
1820 e_canvas_del(m->ecore_evas);
1821 ecore_evas_free(m->ecore_evas);
1822 m->ecore_evas = NULL;
1824 eina_hash_del(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1829 _e_menu_activate_internal(E_Menu *m, E_Zone *zone)
1831 E_Menu_Category *cat = NULL;
1834 if (m->pre_activate_cb.func)
1835 m->pre_activate_cb.func(m->pre_activate_cb.data, m);
1837 m->pending_new_submenu = 0;
1840 _e_menu_win = ecore_x_window_input_new(zone->container->win,
1843 ecore_x_window_show(_e_menu_win);
1844 if (!e_grabinput_get(_e_menu_win, 1, _e_menu_win))
1846 ecore_x_window_free(_e_menu_win);
1851 if ((m->zone) && (m->zone->container != zone->container))
1853 printf("FIXME: cannot move menus between containers yet\n");
1859 /* this remove is in case the menu is marked as inactive but hasn't */
1860 /* been removed from the list yet */
1861 if (m->in_active_list)
1863 _e_active_menus = eina_list_remove(_e_active_menus, m);
1864 m->in_active_list = 0;
1865 e_object_unref(E_OBJECT(m));
1867 _e_active_menus = eina_list_append(_e_active_menus, m);
1868 m->in_active_list = 1;
1870 e_object_ref(E_OBJECT(m));
1872 /* the foreign menu items */
1875 cat = eina_hash_find(_e_menu_categories, m->category);
1878 E_Menu_Category_Callback *cb;
1879 EINA_LIST_FOREACH(cat->callbacks, l, cb)
1880 if (cb->create) cb->create(m, cat->data, cb->data);
1887 _e_menu_deactivate_all(void)
1892 tmp = _e_active_menus_copy_ref();
1894 EINA_LIST_FREE(tmp, m)
1896 e_menu_deactivate(m);
1897 m->parent_item = NULL;
1898 e_object_unref(E_OBJECT(m));
1900 _e_menu_activate_floating = 0;
1901 _e_menu_activate_maybe_drag = 0;
1902 _e_menu_activate_dragging = 0;
1906 _e_menu_deactivate_above(E_Menu *ma)
1912 tmp = _e_active_menus_copy_ref();
1914 EINA_LIST_FREE(tmp, m)
1918 e_menu_deactivate(m);
1919 m->parent_item = NULL;
1921 if (ma == m) above = 1;
1922 e_object_unref(E_OBJECT(m));
1927 _e_menu_submenu_activate(E_Menu_Item *mi)
1929 if (!mi->menu->active) return;
1930 if (mi->menu->fast_mouse)
1932 mi->menu->pending_new_submenu = 1;
1935 mi->menu->pending_new_submenu = 0;
1936 _e_menu_deactivate_above(mi->menu);
1937 if (mi->submenu_pre_cb.func)
1938 mi->submenu_pre_cb.func(mi->submenu_pre_cb.data, mi->menu, mi);
1944 e_object_ref(E_OBJECT(m));
1945 m->parent_item = mi;
1946 _e_menu_activate_internal(m, mi->menu->zone);
1947 _e_menu_reposition(m);
1948 e_object_unref(E_OBJECT(m));
1953 _e_menu_submenu_deactivate(E_Menu_Item *mi)
1955 if (!mi->menu->active) return;
1956 if (mi->submenu_post_cb.func)
1957 mi->submenu_post_cb.func(mi->submenu_post_cb.data, mi->menu, mi);
1961 _e_menu_reposition(E_Menu *m)
1965 int parent_item_bottom;
1967 if (!m->parent_item) return;
1968 m->cur.x = m->parent_item->menu->cur.x + m->parent_item->menu->cur.w;
1970 parent_item_bottom = m->parent_item->menu->cur.y + m->parent_item->y;
1971 if (m->cur.h > m->zone->h)
1973 /* menu is larger than screen */
1974 if (parent_item_bottom > (m->zone->h / 2))
1975 /* more is shown if menu goes up */
1976 m->cur.y = (parent_item_bottom - (m->container_h + 1));
1978 /* more is shown if menu goes down */
1979 m->cur.y = parent_item_bottom - m->container_y;
1983 /* menu is smaller than screen */
1984 if (((parent_item_bottom + m->cur.h - m->container_y) > m->zone->h) &&
1985 (parent_item_bottom > (m->zone->h / 2)))
1986 /* menu is partially out of screen and more is shown if menu goes up */
1987 m->cur.y = (parent_item_bottom - (m->container_h + 1)) + m->parent_item->h;
1989 m->cur.y = parent_item_bottom - m->container_y;
1992 /* FIXME: this will suck for big menus */
1993 tmp = _e_active_menus_copy_ref();
1995 EINA_LIST_FOREACH(m->items, l, mi)
1996 if ((mi->active) && (mi->submenu)) _e_menu_reposition(mi->submenu);
1998 _e_menu_list_free_unref(tmp);
2002 _e_menu_active_call(void)
2006 mi = _e_menu_item_active_get();
2009 if (mi->submenu) return 0;
2011 e_menu_item_toggle_set(mi, !mi->toggle);
2012 if ((mi->radio) && (!e_menu_item_toggle_get(mi)))
2013 e_menu_item_toggle_set(mi, 1);
2015 mi->cb.func(mi->cb.data, mi->menu, mi);
2022 _e_menu_realize_call(E_Menu_Item *mi)
2026 if (mi->realize_cb.func)
2028 mi->realize_cb.func(mi->realize_cb.data, mi->menu, mi);
2036 _e_menu_item_activate_next(void)
2041 ll = _e_menu_list_item_active_get();
2042 mi = _e_menu_item_active_get();
2045 /* Look at the next item and then cycle until we're not on
2049 if (!eina_list_next(ll))
2050 ll = mi->menu->items;
2052 ll = eina_list_next(ll);
2053 mi = eina_list_data_get(ll);
2055 while (mi->separator || mi->disable);
2057 e_menu_item_active_set(mi, 1);
2058 _e_menu_item_ensure_onscreen(mi);
2062 _e_menu_activate_first();
2066 _e_menu_item_activate_previous(void)
2071 ll = _e_menu_list_item_active_get();
2072 mi = _e_menu_item_active_get();
2075 /* Look at the prev item and then cycle until we're not on
2079 if (!eina_list_prev(ll))
2080 ll = eina_list_last(ll);
2082 ll = eina_list_prev(ll);
2083 mi = eina_list_data_get(ll);
2085 while ((mi->separator) || (mi->disable));
2087 e_menu_item_active_set(mi, 1);
2088 _e_menu_item_ensure_onscreen(mi);
2092 _e_menu_activate_first();
2096 _e_menu_item_activate_first(void)
2102 m = _e_menu_active_get();
2106 mi = eina_list_data_get(ll);
2107 while ((mi->separator) && eina_list_next(ll))
2109 ll = eina_list_next(ll);
2110 mi = eina_list_data_get(ll);
2112 if (mi->separator) return;
2113 e_menu_item_active_set(mi, 1);
2114 _e_menu_item_ensure_onscreen(mi);
2117 _e_menu_activate_first();
2121 _e_menu_item_activate_last(void)
2127 m = _e_menu_active_get();
2130 ll = eina_list_last(m->items);
2131 mi = eina_list_data_get(ll);
2132 while ((mi->separator) && eina_list_prev(ll))
2134 ll = eina_list_prev(ll);
2135 mi = eina_list_data_get(ll);
2137 if (mi->separator) return;
2138 e_menu_item_active_set(mi, 1);
2139 _e_menu_item_ensure_onscreen(mi);
2142 _e_menu_activate_first();
2146 _e_menu_item_activate_nth(int n)
2153 mi = _e_menu_item_active_get();
2156 _e_menu_activate_first();
2157 mi = _e_menu_item_active_get();
2161 EINA_LIST_FOREACH(m->items, ll, mi)
2163 if (!mi->separator) i++;
2166 e_menu_item_active_set(mi, 1);
2167 _e_menu_item_ensure_onscreen(mi);
2171 _e_menu_item_activate_char(const char * key_compose)
2175 Eina_List *ll, *ll_orig;
2177 /* Ignore modifiers and such. */
2178 if (!key_compose) return;
2180 /* Check we've got a menu and it's active. */
2181 m = _e_menu_active_get();
2184 if (!_e_active_menus) return;
2185 m = eina_list_data_get(_e_active_menus);
2189 ll = _e_menu_list_item_active_get();
2190 /* If we don't have an active item, start from the top of the list. */
2194 mi = eina_list_data_get(ll);
2195 /* Only check the current item if it wasn't active before. */
2196 if (!mi->separator && mi->label && !strncasecmp(key_compose, mi->label, strlen(key_compose)))
2198 e_menu_item_active_set(mi, 1);
2199 _e_menu_item_ensure_onscreen(mi);
2206 mi = eina_list_data_get(ll);
2207 if (!eina_list_next(ll))
2208 ll = mi->menu->items;
2210 ll = eina_list_next(ll);
2211 mi = eina_list_data_get(ll);
2213 /* While we don't have a label OR we don't match AND we haven't
2215 while ((!mi->label || strncasecmp(key_compose, mi->label, strlen(key_compose)))
2220 if (!eina_list_next(ll))
2221 ll = mi->menu->items;
2223 ll = eina_list_next(ll);
2224 mi = eina_list_data_get(ll);
2226 while (mi->separator);
2229 e_menu_item_active_set(mi, 1);
2230 _e_menu_item_ensure_onscreen(mi);
2235 _e_menu_activate_next(void)
2239 mi = _e_menu_item_active_get();
2244 if (mi->submenu->items)
2246 mi = eina_list_data_get(mi->submenu->items);
2247 e_menu_item_active_set(mi, 1);
2248 _e_menu_item_ensure_onscreen(mi);
2253 _e_menu_activate_first();
2257 _e_menu_activate_previous(void)
2261 mi = _e_menu_item_active_get();
2264 if (mi->menu->parent_item)
2266 mi = mi->menu->parent_item;
2267 e_menu_item_active_set(mi, 1);
2268 _e_menu_item_ensure_onscreen(mi);
2272 _e_menu_activate_last();
2276 _e_menu_activate_first(void)
2282 if (!_e_active_menus) return;
2283 m = eina_list_data_get(_e_active_menus);
2284 if (!m->items) return;
2286 mi = eina_list_data_get(ll);
2287 while ((mi->separator) && eina_list_next(ll))
2289 ll = eina_list_next(ll);
2290 mi = eina_list_data_get(ll);
2292 if (mi->separator) return;
2293 e_menu_item_active_set(mi, 1);
2294 _e_menu_item_ensure_onscreen(mi);
2298 _e_menu_activate_last(void)
2304 if (!_e_active_menus) return;
2305 m = eina_list_data_get(_e_active_menus);
2306 if (!m->items) return;
2307 ll = eina_list_last(m->items);
2308 mi = eina_list_data_get(ll);
2309 while ((mi->separator) && eina_list_prev(ll))
2311 ll = eina_list_prev(ll);
2312 mi = eina_list_data_get(ll);
2314 if (mi->separator) return;
2315 e_menu_item_active_set(mi, 1);
2316 _e_menu_item_ensure_onscreen(mi);
2321 _e_menu_activate_nth(int n)
2328 mi = _e_menu_item_active_get();
2331 _e_menu_activate_first();
2332 mi = _e_menu_item_active_get();
2336 EINA_LIST_FOREACH(m->items, ll, mi)
2338 if (!mi->separator) i++;
2341 e_menu_item_active_set(mi, 1);
2342 _e_menu_item_ensure_onscreen(mi);
2350 _e_menu_active_get(void)
2352 if (_e_active_menu_item) return _e_active_menu_item->menu;
2356 static E_Menu_Item *
2357 _e_menu_item_active_get(void)
2359 return _e_active_menu_item;
2363 _e_menu_list_item_active_get(void)
2365 if (_e_active_menu_item)
2366 return _e_active_menu_item->list_position;
2372 _e_menu_outside_bounds_get(int xdir, int ydir)
2382 EINA_LIST_FOREACH(_e_active_menus, l, m)
2384 if (m->cur.x < m->zone->x + e_config->menu_autoscroll_margin)
2386 i = m->zone->x - m->cur.x + e_config->menu_autoscroll_margin;
2387 if (i > outl) outl = i;
2389 if (m->cur.y < m->zone->y + e_config->menu_autoscroll_margin)
2391 i = m->zone->y - m->cur.y + e_config->menu_autoscroll_margin;
2392 if (i > outt) outt = i;
2394 if ((m->cur.x + m->cur.w) > (m->zone->w - e_config->menu_autoscroll_margin))
2396 i = m->cur.x + m->cur.w - (m->zone->x + m->zone->w - e_config->menu_autoscroll_margin);
2397 if (i > outr) outr = i;
2399 if ((m->cur.y + m->cur.h) > (m->zone->h - e_config->menu_autoscroll_margin))
2401 i = m->cur.y + m->cur.h - (m->zone->y + m->zone->h - e_config->menu_autoscroll_margin);
2402 if (i > outb) outb = i;
2407 if (outl) return outl;
2411 if (outr) return outr;
2413 else if (ydir == -1)
2415 if (outt) return outt;
2419 if (outb) return outb;
2425 _e_menu_scroll_by(int dx, int dy)
2430 EINA_LIST_FOREACH(_e_active_menus, l, m)
2438 _e_menu_mouse_autoscroll_check(void)
2440 int autoscroll_x = 0;
2441 int autoscroll_y = 0;
2443 if (_e_menu_x - e_config->menu_autoscroll_cursor_margin <= 0)
2445 if (_e_menu_outside_bounds_get(-1, 0)) autoscroll_x = -1;
2447 if (_e_menu_y - e_config->menu_autoscroll_cursor_margin <= 0)
2449 if (_e_menu_outside_bounds_get(0, -1)) autoscroll_y = -1;
2451 if ((!autoscroll_x) && (!autoscroll_y))
2453 if (_e_active_menus)
2457 m = eina_list_data_get(_e_active_menus);
2458 if (_e_menu_x + e_config->menu_autoscroll_cursor_margin >= (m->zone->w - 1))
2460 if (_e_menu_outside_bounds_get(1, 0)) autoscroll_x = 1;
2462 if (_e_menu_y + e_config->menu_autoscroll_cursor_margin >= (m->zone->h - 1))
2464 if (_e_menu_outside_bounds_get(0, 1)) autoscroll_y = 1;
2468 _e_menu_autoscroll_x = autoscroll_x;
2469 _e_menu_autoscroll_y = autoscroll_y;
2470 if ((!autoscroll_x) && (!autoscroll_y)) return;
2471 if (_e_menu_scroll_animator) return;
2472 _e_menu_scroll_animator = ecore_animator_add(_e_menu_cb_scroll_animator,
2474 _e_menu_scroll_start = ecore_loop_time_get();
2478 _e_menu_item_ensure_onscreen(E_Menu_Item *mi)
2480 int x = 0, y = 0, w = 0, h = 0;
2483 if (!mi->menu) return;
2484 if (!mi->menu->zone) return;
2485 x = mi->x + mi->menu->cur.x;
2486 y = mi->y + mi->menu->cur.y;
2489 if ((x + w) > (mi->menu->zone->x + mi->menu->zone->w))
2490 dx = (mi->menu->zone->x + mi->menu->zone->w) - (x + w);
2491 else if (x < mi->menu->zone->x)
2492 dx = mi->menu->zone->x - x;
2493 if ((y + h) > (mi->menu->zone->y + mi->menu->zone->h))
2494 dy = (mi->menu->zone->y + mi->menu->zone->h) - (y + h);
2495 else if (y < mi->menu->zone->y)
2496 dy = mi->menu->zone->y - y;
2497 if ((dx != 0) || (dy != 0))
2498 _e_menu_scroll_by(dx, dy);
2502 _e_menu_auto_place(E_Menu *m, int x, int y, int w, int h)
2515 * quadrants... which one
2517 if (w != m->zone->w)
2518 xr = (double)(x - m->zone->x) /
2519 (double)(m->zone->w - w);
2522 if (h != m->zone->h)
2523 yr = (double)(y - m->zone->y) /
2524 (double)(m->zone->h - h);
2527 if ((xr + yr) < 0.99) /* top or left */
2529 if (((1.0 - yr) + xr) <= 1.0)
2533 if (y < (m->zone->y + ((m->zone->h * 1) / 3)))
2535 else if (y < (m->zone->y + ((m->zone->h * 2) / 3)))
2536 m->cur.y = y + ((h - m->cur.h) / 2);
2538 m->cur.y = y + h - m->cur.h;
2545 if (x < (m->zone->x + ((m->zone->w * 1) / 3)))
2547 else if (x < (m->zone->x + ((m->zone->w * 2) / 3)))
2548 m->cur.x = x + ((w - m->cur.w) / 2);
2550 m->cur.x = x + w - m->cur.w;
2554 else /* bottom or right */
2556 if (((1.0 - yr) + xr) <= 1.01)
2559 m->cur.y = y - m->cur.h;
2560 if (x < (m->zone->x + ((m->zone->w * 1) / 3)))
2562 else if (x < (m->zone->x + ((m->zone->w * 2) / 3)))
2563 m->cur.x = x + ((w - m->cur.w) / 2);
2565 m->cur.x = x + w - m->cur.w;
2571 m->cur.x = x - m->cur.w;
2572 if (y < (m->zone->y + ((m->zone->h * 1) / 3)))
2574 else if (y < (m->zone->y + ((m->zone->h * 2) / 3)))
2575 m->cur.y = y + ((h - m->cur.h) / 2);
2577 m->cur.y = y + h - m->cur.h;
2585 _e_menu_cb_ecore_evas_resize(Ecore_Evas *ee)
2591 evas = ecore_evas_get(ee);
2592 evas_output_viewport_get(evas, NULL, NULL, &w, &h);
2593 o = evas_object_name_find(evas, "menu/background");
2594 evas_object_resize(o, w, h);
2598 _e_menu_cb_item_in(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2603 e_menu_item_active_set(mi, 1);
2607 _e_menu_cb_item_out(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
2610 Evas_Event_Mouse_In *ev;
2614 e_menu_item_active_set(mi, 0);
2615 if (_e_menu_activate_maybe_drag)
2617 if (mi->drag_cb.func)
2619 /* User is dragging a draggable item elsewhere. */
2620 mi->drag.x = ev->output.x - (ev->output.x - mi->x);
2621 mi->drag.y = ev->output.y - (ev->output.y - mi->y);
2622 _e_menu_deactivate_all();
2623 mi->drag_cb.func(mi->drag_cb.data, mi->menu, mi);
2625 /* Either way, the maybe drag stops here. */
2626 _e_menu_activate_maybe_drag = 0;
2631 _e_menu_cb_key_down(void *data __UNUSED__, int type __UNUSED__, void *event)
2633 Ecore_Event_Key *ev;
2636 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2637 if ((!strcmp(ev->key, "Up")) || (!strcmp(ev->key, "KP_Up")))
2638 _e_menu_item_activate_previous();
2639 else if ((!strcmp(ev->key, "Down")) || (!strcmp(ev->key, "KP_Down")))
2640 _e_menu_item_activate_next();
2641 else if ((!strcmp(ev->key, "Left")) || (!strcmp(ev->key, "KP_Left")))
2642 _e_menu_activate_previous();
2643 else if ((!strcmp(ev->key, "Right")) || (!strcmp(ev->key, "KP_Right")))
2644 _e_menu_activate_next();
2645 else if ((!strcmp(ev->key, "Home")) || (!strcmp(ev->key, "KP_Home")))
2646 _e_menu_item_activate_first();
2647 else if ((!strcmp(ev->key, "End")) || (!strcmp(ev->key, "KP_End")))
2648 _e_menu_item_activate_last();
2649 else if (!strcmp(ev->key, "space"))
2650 _e_menu_active_call();
2651 else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
2653 _e_menu_active_call();
2654 _e_menu_deactivate_all();
2656 else if (!strcmp(ev->key, "Escape"))
2657 _e_menu_deactivate_all();
2658 else if ((!strcmp(ev->key, "1")) || (!strcmp(ev->key, "KP_1")))
2659 _e_menu_item_activate_first();
2660 else if ((!strcmp(ev->key, "2")) || (!strcmp(ev->key, "KP_2")))
2661 _e_menu_item_activate_nth(1);
2662 else if ((!strcmp(ev->key, "3")) || (!strcmp(ev->key, "KP_3")))
2663 _e_menu_item_activate_nth(2);
2664 else if ((!strcmp(ev->key, "4")) || (!strcmp(ev->key, "KP_4")))
2665 _e_menu_item_activate_nth(3);
2666 else if ((!strcmp(ev->key, "5")) || (!strcmp(ev->key, "KP_5")))
2667 _e_menu_item_activate_nth(4);
2668 else if ((!strcmp(ev->key, "6")) || (!strcmp(ev->key, "KP_6")))
2669 _e_menu_item_activate_nth(5);
2670 else if ((!strcmp(ev->key, "7")) || (!strcmp(ev->key, "KP_7")))
2671 _e_menu_item_activate_nth(6);
2672 else if ((!strcmp(ev->key, "8")) || (!strcmp(ev->key, "KP_8")))
2673 _e_menu_item_activate_nth(7);
2674 else if ((!strcmp(ev->key, "9")) || (!strcmp(ev->key, "KP_9")))
2675 _e_menu_item_activate_nth(8);
2676 else if ((!strcmp(ev->key, "0")) || (!strcmp(ev->key, "KP_0")))
2677 _e_menu_item_activate_last();
2678 else if (ev->compose)
2679 _e_menu_item_activate_char(ev->compose);
2680 return ECORE_CALLBACK_PASS_ON;
2684 _e_menu_cb_key_up(void *data __UNUSED__, int type __UNUSED__, void *event)
2686 Ecore_Event_Key *ev;
2689 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2690 return ECORE_CALLBACK_PASS_ON;
2693 /* we need all of these because menus are special and grab the mouse and
2694 * keyboard and thus the normal event mechanism doesn't work, so we feed
2695 * events directly to the canvases from our grab window
2699 _e_menu_cb_mouse_down(void *data __UNUSED__, int type __UNUSED__, void *event)
2701 Ecore_Event_Mouse_Button *ev;
2704 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2706 /* Only allow dragging from floating menus for now.
2707 * The reason for this is that for non floating menus,
2708 * the mouse is already down and dragging, so the decision
2709 * to start a drag is much more complex.
2711 if (_e_menu_activate_floating)
2712 _e_menu_activate_maybe_drag = 1;
2714 return ECORE_CALLBACK_PASS_ON;
2718 _e_menu_cb_mouse_up(void *data __UNUSED__, int type __UNUSED__, void *event)
2720 Ecore_Event_Mouse_Button *ev;
2725 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2727 t = ev->timestamp - _e_menu_activate_time;
2728 if ((_e_menu_activate_time != 0) &&
2729 (t < (e_config->menus_click_drag_timeout * 1000)))
2731 _e_menu_activate_floating = 1;
2732 return ECORE_CALLBACK_PASS_ON;
2735 if (_e_menu_activate_dragging)
2737 /* FIXME: This is a drop, which is not allowed for now.
2738 * Once dragging is working, this will be subject to some experimenattion.
2742 ret = _e_menu_active_call();
2743 _e_menu_activate_maybe_drag = 0;
2744 _e_menu_activate_dragging = 0;
2747 /* allow mouse to pop down menu if clicked elsewhere */
2748 /* if (_e_menu_activate_time != 0) */
2749 _e_menu_deactivate_all();
2752 _e_menu_deactivate_all();
2753 else if (!_e_menu_activate_floating)
2754 _e_menu_deactivate_all();
2755 return ECORE_CALLBACK_PASS_ON;
2759 _e_menu_cb_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event)
2761 Ecore_Event_Mouse_Move *ev;
2766 double fast_move_threshold;
2770 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2771 fast_move_threshold = e_config->menus_fast_mouse_move_threshhold;
2772 dx = ev->x - _e_menu_x;
2773 dy = ev->y - _e_menu_y;
2774 d = (dx * dx) + (dy * dy);
2775 dt = (double)(ev->timestamp - _e_menu_time) / 1000.0;
2777 if ((dt > 0.0) && ((d / dt) >= (fast_move_threshold * fast_move_threshold)))
2780 tmp = _e_active_menus_copy_ref();
2782 EINA_LIST_FOREACH(_e_active_menus, l, m)
2784 if ((m->realized) && (m->cur.visible))
2791 if (m->pending_new_submenu)
2795 mi = _e_menu_item_active_get();
2797 _e_menu_submenu_activate(mi);
2800 evas_event_feed_mouse_move(m->evas,
2801 ev->x - m->cur.x + m->zone->x,
2802 ev->y - m->cur.y + m->zone->y,
2803 ev->timestamp, NULL);
2807 _e_menu_list_free_unref(tmp);
2811 _e_menu_time = ev->timestamp;
2812 _e_menu_mouse_autoscroll_check();
2813 return ECORE_CALLBACK_PASS_ON;
2817 _e_menu_cb_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event)
2819 Ecore_Event_Mouse_Wheel *ev;
2822 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2823 if (ev->z < 0) /* up */
2827 for (i = ev->z; i < 0; i++)
2828 _e_menu_item_activate_previous();
2830 else if (ev->z > 0) /* down */
2834 for (i = ev->z; i > 0; i--)
2835 _e_menu_item_activate_next();
2837 return ECORE_CALLBACK_PASS_ON;
2841 _e_menu_cb_scroll_animator(void *data __UNUSED__)
2848 t = ecore_loop_time_get();
2849 spd = e_config->menus_scroll_speed;
2850 dt = t - _e_menu_scroll_start;
2851 _e_menu_scroll_start = t;
2854 if (_e_menu_autoscroll_x)
2856 out = _e_menu_outside_bounds_get(_e_menu_autoscroll_x, 0);
2857 dx = (-_e_menu_autoscroll_x) * spd * dt;
2858 if (_e_menu_autoscroll_x == -1)
2860 if (dx > out) dx = out;
2864 if (dx < -out) dx = -out;
2867 if (_e_menu_autoscroll_y)
2869 out = _e_menu_outside_bounds_get(0, _e_menu_autoscroll_y);
2870 dy = (-_e_menu_autoscroll_y) * spd * dt;
2871 if (_e_menu_autoscroll_y == -1)
2873 if (dy > out) dy = out;
2877 if (dy < -out) dy = -out;
2880 _e_menu_scroll_by(dx, dy);
2881 _e_menu_mouse_autoscroll_check();
2882 if ((_e_menu_autoscroll_x == 0) && (_e_menu_autoscroll_y == 0))
2884 _e_menu_scroll_animator = NULL;
2891 _e_menu_cb_window_shape(void *data __UNUSED__, int ev_type __UNUSED__, void *ev)
2894 Ecore_X_Event_Window_Shape *e;
2898 EINA_LIST_FOREACH(_e_active_menus, l, m)
2900 if (m->evas_win == e->win)
2901 m->need_shape_export = 1;
2903 return ECORE_CALLBACK_PASS_ON;
2907 _e_menu_cb_item_submenu_post_default(void *data __UNUSED__, E_Menu *m __UNUSED__, E_Menu_Item *mi)
2911 if (!mi->submenu) return;
2914 e_menu_item_submenu_set(mi, NULL);
2915 e_object_del(E_OBJECT(subm));
2920 _e_menu_categories_free_cb(const Eina_Hash __UNUSED__ *hash, const void __UNUSED__ *key, void *data, void *fdata __UNUSED__)
2922 E_Menu_Category_Callback *cb;
2923 E_Menu_Category *cat;
2925 cat = (E_Menu_Category *) data;
2926 EINA_LIST_FREE(cat->callbacks, cb)
2927 free(cb); /* free the callback struct */