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;
1496 m->ecore_evas = e_canvas_new(m->zone->container->win,
1497 m->cur.x, m->cur.y, m->cur.w, m->cur.h, 1, 1,
1499 e_canvas_add(m->ecore_evas);
1500 eina_hash_add(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1501 m->shape = e_container_shape_add(m->zone->container);
1502 e_container_shape_move(m->shape, m->cur.x, m->cur.y);
1503 e_container_shape_resize(m->shape, m->cur.w, m->cur.h);
1505 ecore_evas_callback_resize_set(m->ecore_evas, _e_menu_cb_ecore_evas_resize);
1506 m->evas = ecore_evas_get(m->ecore_evas);
1507 evas_event_freeze(m->evas);
1508 /* move cursor out to avoid event cycles during setup */
1509 evas_event_feed_mouse_in(m->evas, ecore_x_current_time_get(), NULL);
1510 evas_event_feed_mouse_move(m->evas, -1000000, -1000000,
1511 ecore_x_current_time_get(), NULL);
1512 ecore_x_window_shape_events_select(m->evas_win, 1);
1513 ecore_evas_name_class_set(m->ecore_evas, "E", "_e_menu_window");
1514 ecore_evas_title_set(m->ecore_evas, "E Menu");
1516 o = edje_object_add(m->evas);
1518 evas_object_name_set(o, "menu/background");
1519 evas_object_data_set(o, "e_menu", m);
1520 evas_object_move(o, 0, 0);
1521 evas_object_resize(o, m->cur.w, m->cur.h);
1522 ok = e_theme_edje_object_set(o, "base/theme/menus",
1523 "e/widgets/menu/default/background");
1526 const char *shape_option;
1528 shape_option = edje_object_data_get(o, "shaped");
1531 if (!strcmp(shape_option, "1")) m->shaped = 1;
1534 if (m->header.title)
1536 edje_object_part_text_set(o, "e.text.title", m->header.title);
1537 edje_object_signal_emit(o, "e,action,show,title", "e");
1538 edje_object_message_signal_process(o);
1540 evas_object_show(o);
1544 if (e_config->use_composite)
1546 ecore_evas_alpha_set(m->ecore_evas, m->shaped);
1548 eina_hash_del(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1549 m->evas_win = ecore_evas_software_x11_window_get(m->ecore_evas);
1550 eina_hash_add(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1553 ecore_evas_shaped_set(m->ecore_evas, m->shaped);
1556 ecore_x_netwm_window_type_set(m->evas_win, ECORE_X_WINDOW_TYPE_MENU);
1558 o = e_box_add(m->evas);
1559 m->container_object = o;
1560 evas_object_intercept_move_callback_add(o, _e_menu_cb_intercept_container_move, m);
1561 evas_object_intercept_resize_callback_add(o, _e_menu_cb_intercept_container_resize, m);
1563 evas_object_show(o);
1564 e_box_homogenous_set(o, 0);
1565 edje_object_part_swallow(m->bg_object, "e.swallow.content", m->container_object);
1567 EINA_LIST_FOREACH(m->items, l, mi)
1568 _e_menu_item_realize(mi);
1570 _e_menu_items_layout_update(m);
1571 e_box_thaw(m->container_object);
1572 evas_object_resize(m->bg_object, m->cur.w, m->cur.h);
1573 evas_event_thaw(m->evas);
1577 _e_menu_items_layout_update(E_Menu *m)
1581 Evas_Coord bw, bh, mw, mh;
1585 int submenus_on = 0;
1586 int min_icon_w = 0, min_icon_h = 0;
1587 int min_label_w = 0, min_label_h = 0;
1588 int min_submenu_w = 0, min_submenu_h = 0;
1589 int min_toggle_w = 0, min_toggle_h = 0;
1590 int min_w = 0, min_h = 0;
1592 e_box_freeze(m->container_object);
1593 EINA_LIST_FOREACH(m->items, l, mi)
1595 if (mi->icon) icons_on = 1;
1596 if (mi->icon_object) icons_on = 1;
1597 if (mi->label) labels_on = 1;
1598 if (mi->submenu) submenus_on = 1;
1599 if (mi->check) toggles_on = 1;
1600 if (mi->radio) toggles_on = 1;
1602 if (mi->icon_w > min_icon_w) min_icon_w = mi->icon_w;
1603 if (mi->icon_h > min_icon_h) min_icon_h = mi->icon_h;
1604 if (mi->label_w > min_label_w) min_label_w = mi->label_w;
1605 if (mi->label_h > min_label_h) min_label_h = mi->label_h;
1606 if (mi->submenu_w > min_submenu_w) min_submenu_w = mi->submenu_w;
1607 if (mi->submenu_h > min_submenu_h) min_submenu_h = mi->submenu_h;
1608 if (mi->toggle_w > min_toggle_w) min_toggle_w = mi->toggle_w;
1609 if (mi->toggle_h > min_toggle_h) min_toggle_h = mi->toggle_h;
1615 if (min_label_h < min_submenu_h)
1616 min_label_h = min_submenu_h;
1620 if (min_label_h < min_toggle_h)
1621 min_label_h = min_toggle_h;
1623 if ((icons_on) && (min_icon_h > 0))
1625 min_icon_w = (min_icon_w * min_label_h) / min_icon_h;
1626 min_icon_h = min_label_h;
1628 min_w = min_label_w + min_icon_w + min_submenu_w + min_toggle_w;
1629 min_h = min_label_h;
1635 if (min_icon_h < min_submenu_h)
1636 min_icon_h = min_submenu_h;
1640 if (min_icon_h < min_toggle_h)
1641 min_icon_h = min_toggle_h;
1643 min_w = min_icon_w + min_toggle_w + min_submenu_w;
1646 else if (toggles_on)
1650 if (min_toggle_h < min_submenu_h)
1651 min_toggle_h = min_submenu_h;
1653 min_w = min_toggle_w + min_submenu_w;
1654 min_h = min_toggle_h;
1656 EINA_LIST_FOREACH(m->items, l, mi)
1660 e_box_pack_options_set(mi->separator_object,
1663 0.5, 0.5, /* align */
1664 mi->separator_w, mi->separator_h, /* min */
1665 -1, mi->separator_h /* max */
1670 e_box_freeze(mi->container_object);
1672 e_box_pack_options_set(mi->toggle_object,
1675 0.5, 0.5, /* align */
1676 min_toggle_w, min_toggle_h, /* min */
1680 e_box_pack_options_set(mi->toggle_object,
1683 0.5, 0.5, /* align */
1689 if (mi->icon_bg_object)
1690 e_box_pack_options_set(mi->icon_bg_object,
1693 0.5, 0.5, /* align */
1694 min_icon_w, min_icon_h, /* min */
1698 e_box_pack_options_set(mi->icon_object,
1701 0.5, 0.5, /* align */
1702 min_icon_w, min_icon_h, /* min */
1707 e_box_pack_options_set(mi->icon_object,
1710 0.5, 0.5, /* align */
1715 e_box_pack_options_set(mi->label_object,
1718 0.5, 0.5, /* align */
1719 min_label_w, min_label_h, /* min */
1723 e_box_pack_options_set(mi->label_object,
1726 0.5, 0.5, /* align */
1731 e_box_pack_options_set(mi->submenu_object,
1734 0.5, 0.5, /* align */
1735 min_submenu_w, min_submenu_h, /* min */
1739 e_box_pack_options_set(mi->submenu_object,
1742 0.5, 0.5, /* align */
1746 edje_extern_object_min_size_set(mi->container_object,
1748 edje_object_part_swallow(mi->bg_object, "e.swallow.content",
1749 mi->container_object);
1750 edje_object_size_min_calc(mi->bg_object, &mw, &mh);
1751 e_box_pack_options_set(mi->bg_object,
1754 0.5, 0.5, /* align */
1758 e_box_thaw(mi->container_object);
1761 e_box_size_min_get(m->container_object, &bw, &bh);
1762 edje_extern_object_min_size_set(m->container_object, bw, bh);
1763 edje_extern_object_max_size_set(m->container_object, bw, bh);
1764 edje_object_part_swallow(m->bg_object, "e.swallow.content", m->container_object);
1765 edje_object_size_min_calc(m->bg_object, &mw, &mh);
1766 e_box_thaw(m->container_object);
1772 _e_menu_item_unrealize(E_Menu_Item *mi)
1774 if (mi->container_object) e_box_freeze(mi->container_object);
1775 if (mi->separator_object) evas_object_del(mi->separator_object);
1776 mi->separator_object = NULL;
1777 if (mi->bg_object) evas_object_del(mi->bg_object);
1778 mi->bg_object = NULL;
1779 if (mi->container_object) evas_object_del(mi->container_object);
1780 mi->container_object = NULL;
1781 if (mi->toggle_object) evas_object_del(mi->toggle_object);
1782 mi->toggle_object = NULL;
1783 if (mi->icon_bg_object) evas_object_del(mi->icon_bg_object);
1784 mi->icon_bg_object = NULL;
1785 if (mi->icon_object) evas_object_del(mi->icon_object);
1786 mi->icon_object = NULL;
1787 if (mi->label_object) evas_object_del(mi->label_object);
1788 mi->label_object = NULL;
1789 if (mi->submenu_object) evas_object_del(mi->submenu_object);
1790 mi->submenu_object = NULL;
1791 if (mi->event_object) evas_object_del(mi->event_object);
1792 mi->event_object = NULL;
1796 _e_menu_unrealize(E_Menu *m)
1801 if (!m->realized) return;
1802 evas_event_freeze(m->evas);
1803 e_container_shape_hide(m->shape);
1804 e_object_del(E_OBJECT(m->shape));
1806 e_box_freeze(m->container_object);
1807 EINA_LIST_FOREACH(m->items, l, mi)
1808 _e_menu_item_unrealize(mi);
1809 if (m->header.icon) evas_object_del(m->header.icon);
1810 m->header.icon = NULL;
1811 if (m->bg_object) evas_object_del(m->bg_object);
1812 m->bg_object = NULL;
1813 if (m->container_object) evas_object_del(m->container_object);
1814 m->container_object = NULL;
1816 m->prev.visible = 0;
1819 e_canvas_del(m->ecore_evas);
1820 ecore_evas_free(m->ecore_evas);
1821 m->ecore_evas = NULL;
1823 eina_hash_del(_e_menu_hash, e_util_winid_str_get(m->evas_win), m);
1828 _e_menu_activate_internal(E_Menu *m, E_Zone *zone)
1830 E_Menu_Category *cat = NULL;
1833 if (m->pre_activate_cb.func)
1834 m->pre_activate_cb.func(m->pre_activate_cb.data, m);
1836 m->pending_new_submenu = 0;
1839 _e_menu_win = ecore_x_window_input_new(zone->container->win,
1842 ecore_x_window_show(_e_menu_win);
1843 if (!e_grabinput_get(_e_menu_win, 1, _e_menu_win))
1845 ecore_x_window_free(_e_menu_win);
1850 if ((m->zone) && (m->zone->container != zone->container))
1852 printf("FIXME: cannot move menus between containers yet\n");
1858 /* this remove is in case the menu is marked as inactive but hasn't */
1859 /* been removed from the list yet */
1860 if (m->in_active_list)
1862 _e_active_menus = eina_list_remove(_e_active_menus, m);
1863 m->in_active_list = 0;
1864 e_object_unref(E_OBJECT(m));
1866 _e_active_menus = eina_list_append(_e_active_menus, m);
1867 m->in_active_list = 1;
1869 e_object_ref(E_OBJECT(m));
1871 /* the foreign menu items */
1874 cat = eina_hash_find(_e_menu_categories, m->category);
1877 E_Menu_Category_Callback *cb;
1878 EINA_LIST_FOREACH(cat->callbacks, l, cb)
1879 if (cb->create) cb->create(m, cat->data, cb->data);
1886 _e_menu_deactivate_all(void)
1891 tmp = _e_active_menus_copy_ref();
1893 EINA_LIST_FREE(tmp, m)
1895 e_menu_deactivate(m);
1896 m->parent_item = NULL;
1897 e_object_unref(E_OBJECT(m));
1899 _e_menu_activate_floating = 0;
1900 _e_menu_activate_maybe_drag = 0;
1901 _e_menu_activate_dragging = 0;
1905 _e_menu_deactivate_above(E_Menu *ma)
1911 tmp = _e_active_menus_copy_ref();
1913 EINA_LIST_FREE(tmp, m)
1917 e_menu_deactivate(m);
1918 m->parent_item = NULL;
1920 if (ma == m) above = 1;
1921 e_object_unref(E_OBJECT(m));
1926 _e_menu_submenu_activate(E_Menu_Item *mi)
1928 if (!mi->menu->active) return;
1929 if (mi->menu->fast_mouse)
1931 mi->menu->pending_new_submenu = 1;
1934 mi->menu->pending_new_submenu = 0;
1935 _e_menu_deactivate_above(mi->menu);
1936 if (mi->submenu_pre_cb.func)
1937 mi->submenu_pre_cb.func(mi->submenu_pre_cb.data, mi->menu, mi);
1943 e_object_ref(E_OBJECT(m));
1944 m->parent_item = mi;
1945 _e_menu_activate_internal(m, mi->menu->zone);
1946 _e_menu_reposition(m);
1947 e_object_unref(E_OBJECT(m));
1952 _e_menu_submenu_deactivate(E_Menu_Item *mi)
1954 if (!mi->menu->active) return;
1955 if (mi->submenu_post_cb.func)
1956 mi->submenu_post_cb.func(mi->submenu_post_cb.data, mi->menu, mi);
1960 _e_menu_reposition(E_Menu *m)
1964 int parent_item_bottom;
1966 if (!m->parent_item) return;
1967 m->cur.x = m->parent_item->menu->cur.x + m->parent_item->menu->cur.w;
1969 parent_item_bottom = m->parent_item->menu->cur.y + m->parent_item->y;
1970 if (m->cur.h > m->zone->h)
1972 /* menu is larger than screen */
1973 if (parent_item_bottom > (m->zone->h / 2))
1974 /* more is shown if menu goes up */
1975 m->cur.y = (parent_item_bottom - (m->container_h + 1));
1977 /* more is shown if menu goes down */
1978 m->cur.y = parent_item_bottom - m->container_y;
1982 /* menu is smaller than screen */
1983 if (((parent_item_bottom + m->cur.h - m->container_y) > m->zone->h) &&
1984 (parent_item_bottom > (m->zone->h / 2)))
1985 /* menu is partially out of screen and more is shown if menu goes up */
1986 m->cur.y = (parent_item_bottom - (m->container_h + 1)) + m->parent_item->h;
1988 m->cur.y = parent_item_bottom - m->container_y;
1991 /* FIXME: this will suck for big menus */
1992 tmp = _e_active_menus_copy_ref();
1994 EINA_LIST_FOREACH(m->items, l, mi)
1995 if ((mi->active) && (mi->submenu)) _e_menu_reposition(mi->submenu);
1997 _e_menu_list_free_unref(tmp);
2001 _e_menu_active_call(void)
2005 mi = _e_menu_item_active_get();
2008 if (mi->submenu) return 0;
2010 e_menu_item_toggle_set(mi, !mi->toggle);
2011 if ((mi->radio) && (!e_menu_item_toggle_get(mi)))
2012 e_menu_item_toggle_set(mi, 1);
2014 mi->cb.func(mi->cb.data, mi->menu, mi);
2021 _e_menu_realize_call(E_Menu_Item *mi)
2025 if (mi->realize_cb.func)
2027 mi->realize_cb.func(mi->realize_cb.data, mi->menu, mi);
2035 _e_menu_item_activate_next(void)
2040 ll = _e_menu_list_item_active_get();
2041 mi = _e_menu_item_active_get();
2044 /* Look at the next item and then cycle until we're not on
2048 if (!eina_list_next(ll))
2049 ll = mi->menu->items;
2051 ll = eina_list_next(ll);
2052 mi = eina_list_data_get(ll);
2054 while (mi->separator || mi->disable);
2056 e_menu_item_active_set(mi, 1);
2057 _e_menu_item_ensure_onscreen(mi);
2061 _e_menu_activate_first();
2065 _e_menu_item_activate_previous(void)
2070 ll = _e_menu_list_item_active_get();
2071 mi = _e_menu_item_active_get();
2074 /* Look at the prev item and then cycle until we're not on
2078 if (!eina_list_prev(ll))
2079 ll = eina_list_last(ll);
2081 ll = eina_list_prev(ll);
2082 mi = eina_list_data_get(ll);
2084 while ((mi->separator) || (mi->disable));
2086 e_menu_item_active_set(mi, 1);
2087 _e_menu_item_ensure_onscreen(mi);
2091 _e_menu_activate_first();
2095 _e_menu_item_activate_first(void)
2101 m = _e_menu_active_get();
2105 mi = eina_list_data_get(ll);
2106 while ((mi->separator) && eina_list_next(ll))
2108 ll = eina_list_next(ll);
2109 mi = eina_list_data_get(ll);
2111 if (mi->separator) return;
2112 e_menu_item_active_set(mi, 1);
2113 _e_menu_item_ensure_onscreen(mi);
2116 _e_menu_activate_first();
2120 _e_menu_item_activate_last(void)
2126 m = _e_menu_active_get();
2129 ll = eina_list_last(m->items);
2130 mi = eina_list_data_get(ll);
2131 while ((mi->separator) && eina_list_prev(ll))
2133 ll = eina_list_prev(ll);
2134 mi = eina_list_data_get(ll);
2136 if (mi->separator) return;
2137 e_menu_item_active_set(mi, 1);
2138 _e_menu_item_ensure_onscreen(mi);
2141 _e_menu_activate_first();
2145 _e_menu_item_activate_nth(int n)
2152 mi = _e_menu_item_active_get();
2155 _e_menu_activate_first();
2156 mi = _e_menu_item_active_get();
2160 EINA_LIST_FOREACH(m->items, ll, mi)
2162 if (!mi->separator) i++;
2165 e_menu_item_active_set(mi, 1);
2166 _e_menu_item_ensure_onscreen(mi);
2170 _e_menu_item_activate_char(const char * key_compose)
2174 Eina_List *ll, *ll_orig;
2176 /* Ignore modifiers and such. */
2177 if (!key_compose) return;
2179 /* Check we've got a menu and it's active. */
2180 m = _e_menu_active_get();
2183 if (!_e_active_menus) return;
2184 m = eina_list_data_get(_e_active_menus);
2188 ll = _e_menu_list_item_active_get();
2189 /* If we don't have an active item, start from the top of the list. */
2193 mi = eina_list_data_get(ll);
2194 /* Only check the current item if it wasn't active before. */
2195 if (!mi->separator && mi->label && !strncasecmp(key_compose, mi->label, strlen(key_compose)))
2197 e_menu_item_active_set(mi, 1);
2198 _e_menu_item_ensure_onscreen(mi);
2205 mi = eina_list_data_get(ll);
2206 if (!eina_list_next(ll))
2207 ll = mi->menu->items;
2209 ll = eina_list_next(ll);
2210 mi = eina_list_data_get(ll);
2212 /* While we don't have a label OR we don't match AND we haven't
2214 while ((!mi->label || strncasecmp(key_compose, mi->label, strlen(key_compose)))
2219 if (!eina_list_next(ll))
2220 ll = mi->menu->items;
2222 ll = eina_list_next(ll);
2223 mi = eina_list_data_get(ll);
2225 while (mi->separator);
2228 e_menu_item_active_set(mi, 1);
2229 _e_menu_item_ensure_onscreen(mi);
2234 _e_menu_activate_next(void)
2238 mi = _e_menu_item_active_get();
2243 if (mi->submenu->items)
2245 mi = eina_list_data_get(mi->submenu->items);
2246 e_menu_item_active_set(mi, 1);
2247 _e_menu_item_ensure_onscreen(mi);
2252 _e_menu_activate_first();
2256 _e_menu_activate_previous(void)
2260 mi = _e_menu_item_active_get();
2263 if (mi->menu->parent_item)
2265 mi = mi->menu->parent_item;
2266 e_menu_item_active_set(mi, 1);
2267 _e_menu_item_ensure_onscreen(mi);
2271 _e_menu_activate_last();
2275 _e_menu_activate_first(void)
2281 if (!_e_active_menus) return;
2282 m = eina_list_data_get(_e_active_menus);
2283 if (!m->items) return;
2285 mi = eina_list_data_get(ll);
2286 while ((mi->separator) && eina_list_next(ll))
2288 ll = eina_list_next(ll);
2289 mi = eina_list_data_get(ll);
2291 if (mi->separator) return;
2292 e_menu_item_active_set(mi, 1);
2293 _e_menu_item_ensure_onscreen(mi);
2297 _e_menu_activate_last(void)
2303 if (!_e_active_menus) return;
2304 m = eina_list_data_get(_e_active_menus);
2305 if (!m->items) return;
2306 ll = eina_list_last(m->items);
2307 mi = eina_list_data_get(ll);
2308 while ((mi->separator) && eina_list_prev(ll))
2310 ll = eina_list_prev(ll);
2311 mi = eina_list_data_get(ll);
2313 if (mi->separator) return;
2314 e_menu_item_active_set(mi, 1);
2315 _e_menu_item_ensure_onscreen(mi);
2320 _e_menu_activate_nth(int n)
2327 mi = _e_menu_item_active_get();
2330 _e_menu_activate_first();
2331 mi = _e_menu_item_active_get();
2335 EINA_LIST_FOREACH(m->items, ll, mi)
2337 if (!mi->separator) i++;
2340 e_menu_item_active_set(mi, 1);
2341 _e_menu_item_ensure_onscreen(mi);
2349 _e_menu_active_get(void)
2351 if (_e_active_menu_item) return _e_active_menu_item->menu;
2355 static E_Menu_Item *
2356 _e_menu_item_active_get(void)
2358 return _e_active_menu_item;
2362 _e_menu_list_item_active_get(void)
2364 if (_e_active_menu_item)
2365 return _e_active_menu_item->list_position;
2371 _e_menu_outside_bounds_get(int xdir, int ydir)
2381 EINA_LIST_FOREACH(_e_active_menus, l, m)
2383 if (m->cur.x < m->zone->x + e_config->menu_autoscroll_margin)
2385 i = m->zone->x - m->cur.x + e_config->menu_autoscroll_margin;
2386 if (i > outl) outl = i;
2388 if (m->cur.y < m->zone->y + e_config->menu_autoscroll_margin)
2390 i = m->zone->y - m->cur.y + e_config->menu_autoscroll_margin;
2391 if (i > outt) outt = i;
2393 if ((m->cur.x + m->cur.w) > (m->zone->w - e_config->menu_autoscroll_margin))
2395 i = m->cur.x + m->cur.w - (m->zone->x + m->zone->w - e_config->menu_autoscroll_margin);
2396 if (i > outr) outr = i;
2398 if ((m->cur.y + m->cur.h) > (m->zone->h - e_config->menu_autoscroll_margin))
2400 i = m->cur.y + m->cur.h - (m->zone->y + m->zone->h - e_config->menu_autoscroll_margin);
2401 if (i > outb) outb = i;
2406 if (outl) return outl;
2410 if (outr) return outr;
2412 else if (ydir == -1)
2414 if (outt) return outt;
2418 if (outb) return outb;
2424 _e_menu_scroll_by(int dx, int dy)
2429 EINA_LIST_FOREACH(_e_active_menus, l, m)
2437 _e_menu_mouse_autoscroll_check(void)
2439 int autoscroll_x = 0;
2440 int autoscroll_y = 0;
2442 if (_e_menu_x - e_config->menu_autoscroll_cursor_margin <= 0)
2444 if (_e_menu_outside_bounds_get(-1, 0)) autoscroll_x = -1;
2446 if (_e_menu_y - e_config->menu_autoscroll_cursor_margin <= 0)
2448 if (_e_menu_outside_bounds_get(0, -1)) autoscroll_y = -1;
2450 if ((!autoscroll_x) && (!autoscroll_y))
2452 if (_e_active_menus)
2456 m = eina_list_data_get(_e_active_menus);
2457 if (_e_menu_x + e_config->menu_autoscroll_cursor_margin >= (m->zone->w - 1))
2459 if (_e_menu_outside_bounds_get(1, 0)) autoscroll_x = 1;
2461 if (_e_menu_y + e_config->menu_autoscroll_cursor_margin >= (m->zone->h - 1))
2463 if (_e_menu_outside_bounds_get(0, 1)) autoscroll_y = 1;
2467 _e_menu_autoscroll_x = autoscroll_x;
2468 _e_menu_autoscroll_y = autoscroll_y;
2469 if ((!autoscroll_x) && (!autoscroll_y)) return;
2470 if (_e_menu_scroll_animator) return;
2471 _e_menu_scroll_animator = ecore_animator_add(_e_menu_cb_scroll_animator,
2473 _e_menu_scroll_start = ecore_loop_time_get();
2477 _e_menu_item_ensure_onscreen(E_Menu_Item *mi)
2479 int x = 0, y = 0, w = 0, h = 0;
2482 if (!mi->menu) return;
2483 if (!mi->menu->zone) return;
2484 x = mi->x + mi->menu->cur.x;
2485 y = mi->y + mi->menu->cur.y;
2488 if ((x + w) > (mi->menu->zone->x + mi->menu->zone->w))
2489 dx = (mi->menu->zone->x + mi->menu->zone->w) - (x + w);
2490 else if (x < mi->menu->zone->x)
2491 dx = mi->menu->zone->x - x;
2492 if ((y + h) > (mi->menu->zone->y + mi->menu->zone->h))
2493 dy = (mi->menu->zone->y + mi->menu->zone->h) - (y + h);
2494 else if (y < mi->menu->zone->y)
2495 dy = mi->menu->zone->y - y;
2496 if ((dx != 0) || (dy != 0))
2497 _e_menu_scroll_by(dx, dy);
2501 _e_menu_auto_place(E_Menu *m, int x, int y, int w, int h)
2514 * quadrants... which one
2516 if (w != m->zone->w)
2517 xr = (double)(x - m->zone->x) /
2518 (double)(m->zone->w - w);
2521 if (h != m->zone->h)
2522 yr = (double)(y - m->zone->y) /
2523 (double)(m->zone->h - h);
2526 if ((xr + yr) < 0.99) /* top or left */
2528 if (((1.0 - yr) + xr) <= 1.0)
2532 if (y < (m->zone->y + ((m->zone->h * 1) / 3)))
2534 else if (y < (m->zone->y + ((m->zone->h * 2) / 3)))
2535 m->cur.y = y + ((h - m->cur.h) / 2);
2537 m->cur.y = y + h - m->cur.h;
2544 if (x < (m->zone->x + ((m->zone->w * 1) / 3)))
2546 else if (x < (m->zone->x + ((m->zone->w * 2) / 3)))
2547 m->cur.x = x + ((w - m->cur.w) / 2);
2549 m->cur.x = x + w - m->cur.w;
2553 else /* bottom or right */
2555 if (((1.0 - yr) + xr) <= 1.01)
2558 m->cur.y = y - m->cur.h;
2559 if (x < (m->zone->x + ((m->zone->w * 1) / 3)))
2561 else if (x < (m->zone->x + ((m->zone->w * 2) / 3)))
2562 m->cur.x = x + ((w - m->cur.w) / 2);
2564 m->cur.x = x + w - m->cur.w;
2570 m->cur.x = x - m->cur.w;
2571 if (y < (m->zone->y + ((m->zone->h * 1) / 3)))
2573 else if (y < (m->zone->y + ((m->zone->h * 2) / 3)))
2574 m->cur.y = y + ((h - m->cur.h) / 2);
2576 m->cur.y = y + h - m->cur.h;
2584 _e_menu_cb_ecore_evas_resize(Ecore_Evas *ee)
2590 evas = ecore_evas_get(ee);
2591 evas_output_viewport_get(evas, NULL, NULL, &w, &h);
2592 o = evas_object_name_find(evas, "menu/background");
2593 evas_object_resize(o, w, h);
2597 _e_menu_cb_item_in(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
2602 e_menu_item_active_set(mi, 1);
2606 _e_menu_cb_item_out(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
2609 Evas_Event_Mouse_In *ev;
2613 e_menu_item_active_set(mi, 0);
2614 if (_e_menu_activate_maybe_drag)
2616 if (mi->drag_cb.func)
2618 /* User is dragging a draggable item elsewhere. */
2619 mi->drag.x = ev->output.x - (ev->output.x - mi->x);
2620 mi->drag.y = ev->output.y - (ev->output.y - mi->y);
2621 _e_menu_deactivate_all();
2622 mi->drag_cb.func(mi->drag_cb.data, mi->menu, mi);
2624 /* Either way, the maybe drag stops here. */
2625 _e_menu_activate_maybe_drag = 0;
2630 _e_menu_cb_key_down(void *data __UNUSED__, int type __UNUSED__, void *event)
2632 Ecore_Event_Key *ev;
2635 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2636 if ((!strcmp(ev->key, "Up")) || (!strcmp(ev->key, "KP_Up")))
2637 _e_menu_item_activate_previous();
2638 else if ((!strcmp(ev->key, "Down")) || (!strcmp(ev->key, "KP_Down")))
2639 _e_menu_item_activate_next();
2640 else if ((!strcmp(ev->key, "Left")) || (!strcmp(ev->key, "KP_Left")))
2641 _e_menu_activate_previous();
2642 else if ((!strcmp(ev->key, "Right")) || (!strcmp(ev->key, "KP_Right")))
2643 _e_menu_activate_next();
2644 else if ((!strcmp(ev->key, "Home")) || (!strcmp(ev->key, "KP_Home")))
2645 _e_menu_item_activate_first();
2646 else if ((!strcmp(ev->key, "End")) || (!strcmp(ev->key, "KP_End")))
2647 _e_menu_item_activate_last();
2648 else if (!strcmp(ev->key, "space"))
2649 _e_menu_active_call();
2650 else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
2652 _e_menu_active_call();
2653 _e_menu_deactivate_all();
2655 else if (!strcmp(ev->key, "Escape"))
2656 _e_menu_deactivate_all();
2657 else if ((!strcmp(ev->key, "1")) || (!strcmp(ev->key, "KP_1")))
2658 _e_menu_item_activate_first();
2659 else if ((!strcmp(ev->key, "2")) || (!strcmp(ev->key, "KP_2")))
2660 _e_menu_item_activate_nth(1);
2661 else if ((!strcmp(ev->key, "3")) || (!strcmp(ev->key, "KP_3")))
2662 _e_menu_item_activate_nth(2);
2663 else if ((!strcmp(ev->key, "4")) || (!strcmp(ev->key, "KP_4")))
2664 _e_menu_item_activate_nth(3);
2665 else if ((!strcmp(ev->key, "5")) || (!strcmp(ev->key, "KP_5")))
2666 _e_menu_item_activate_nth(4);
2667 else if ((!strcmp(ev->key, "6")) || (!strcmp(ev->key, "KP_6")))
2668 _e_menu_item_activate_nth(5);
2669 else if ((!strcmp(ev->key, "7")) || (!strcmp(ev->key, "KP_7")))
2670 _e_menu_item_activate_nth(6);
2671 else if ((!strcmp(ev->key, "8")) || (!strcmp(ev->key, "KP_8")))
2672 _e_menu_item_activate_nth(7);
2673 else if ((!strcmp(ev->key, "9")) || (!strcmp(ev->key, "KP_9")))
2674 _e_menu_item_activate_nth(8);
2675 else if ((!strcmp(ev->key, "0")) || (!strcmp(ev->key, "KP_0")))
2676 _e_menu_item_activate_last();
2677 else if (ev->compose)
2678 _e_menu_item_activate_char(ev->compose);
2679 return ECORE_CALLBACK_PASS_ON;
2683 _e_menu_cb_key_up(void *data __UNUSED__, int type __UNUSED__, void *event)
2685 Ecore_Event_Key *ev;
2688 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2689 return ECORE_CALLBACK_PASS_ON;
2692 /* we need all of these because menus are special and grab the mouse and
2693 * keyboard and thus the normal event mechanism doesn't work, so we feed
2694 * events directly to the canvases from our grab window
2698 _e_menu_cb_mouse_down(void *data __UNUSED__, int type __UNUSED__, void *event)
2700 Ecore_Event_Mouse_Button *ev;
2703 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2705 /* Only allow dragging from floating menus for now.
2706 * The reason for this is that for non floating menus,
2707 * the mouse is already down and dragging, so the decision
2708 * to start a drag is much more complex.
2710 if (_e_menu_activate_floating)
2711 _e_menu_activate_maybe_drag = 1;
2713 return ECORE_CALLBACK_PASS_ON;
2717 _e_menu_cb_mouse_up(void *data __UNUSED__, int type __UNUSED__, void *event)
2719 Ecore_Event_Mouse_Button *ev;
2724 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2726 t = ev->timestamp - _e_menu_activate_time;
2727 if ((_e_menu_activate_time != 0) &&
2728 (t < (e_config->menus_click_drag_timeout * 1000)))
2730 _e_menu_activate_floating = 1;
2731 return ECORE_CALLBACK_PASS_ON;
2734 if (_e_menu_activate_dragging)
2736 /* FIXME: This is a drop, which is not allowed for now.
2737 * Once dragging is working, this will be subject to some experimenattion.
2741 ret = _e_menu_active_call();
2742 _e_menu_activate_maybe_drag = 0;
2743 _e_menu_activate_dragging = 0;
2746 /* allow mouse to pop down menu if clicked elsewhere */
2747 /* if (_e_menu_activate_time != 0) */
2748 _e_menu_deactivate_all();
2751 _e_menu_deactivate_all();
2752 else if (!_e_menu_activate_floating)
2753 _e_menu_deactivate_all();
2754 return ECORE_CALLBACK_PASS_ON;
2758 _e_menu_cb_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event)
2760 Ecore_Event_Mouse_Move *ev;
2765 double fast_move_threshold;
2769 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2770 fast_move_threshold = e_config->menus_fast_mouse_move_threshhold;
2771 dx = ev->x - _e_menu_x;
2772 dy = ev->y - _e_menu_y;
2773 d = (dx * dx) + (dy * dy);
2774 dt = (double)(ev->timestamp - _e_menu_time) / 1000.0;
2776 if ((dt > 0.0) && ((d / dt) >= (fast_move_threshold * fast_move_threshold)))
2779 tmp = _e_active_menus_copy_ref();
2781 EINA_LIST_FOREACH(_e_active_menus, l, m)
2783 if ((m->realized) && (m->cur.visible))
2790 if (m->pending_new_submenu)
2794 mi = _e_menu_item_active_get();
2796 _e_menu_submenu_activate(mi);
2799 evas_event_feed_mouse_move(m->evas,
2800 ev->x - m->cur.x + m->zone->x,
2801 ev->y - m->cur.y + m->zone->y,
2802 ev->timestamp, NULL);
2806 _e_menu_list_free_unref(tmp);
2810 _e_menu_time = ev->timestamp;
2811 _e_menu_mouse_autoscroll_check();
2812 return ECORE_CALLBACK_PASS_ON;
2816 _e_menu_cb_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event)
2818 Ecore_Event_Mouse_Wheel *ev;
2821 if (ev->window != _e_menu_win) return ECORE_CALLBACK_PASS_ON;
2822 if (ev->z < 0) /* up */
2826 for (i = ev->z; i < 0; i++)
2827 _e_menu_item_activate_previous();
2829 else if (ev->z > 0) /* down */
2833 for (i = ev->z; i > 0; i--)
2834 _e_menu_item_activate_next();
2836 return ECORE_CALLBACK_PASS_ON;
2840 _e_menu_cb_scroll_animator(void *data __UNUSED__)
2847 t = ecore_loop_time_get();
2848 spd = e_config->menus_scroll_speed;
2849 dt = t - _e_menu_scroll_start;
2850 _e_menu_scroll_start = t;
2853 if (_e_menu_autoscroll_x)
2855 out = _e_menu_outside_bounds_get(_e_menu_autoscroll_x, 0);
2856 dx = (-_e_menu_autoscroll_x) * spd * dt;
2857 if (_e_menu_autoscroll_x == -1)
2859 if (dx > out) dx = out;
2863 if (dx < -out) dx = -out;
2866 if (_e_menu_autoscroll_y)
2868 out = _e_menu_outside_bounds_get(0, _e_menu_autoscroll_y);
2869 dy = (-_e_menu_autoscroll_y) * spd * dt;
2870 if (_e_menu_autoscroll_y == -1)
2872 if (dy > out) dy = out;
2876 if (dy < -out) dy = -out;
2879 _e_menu_scroll_by(dx, dy);
2880 _e_menu_mouse_autoscroll_check();
2881 if ((_e_menu_autoscroll_x == 0) && (_e_menu_autoscroll_y == 0))
2883 _e_menu_scroll_animator = NULL;
2890 _e_menu_cb_window_shape(void *data __UNUSED__, int ev_type __UNUSED__, void *ev)
2893 Ecore_X_Event_Window_Shape *e;
2897 EINA_LIST_FOREACH(_e_active_menus, l, m)
2899 if (m->evas_win == e->win)
2900 m->need_shape_export = 1;
2902 return ECORE_CALLBACK_PASS_ON;
2906 _e_menu_cb_item_submenu_post_default(void *data __UNUSED__, E_Menu *m __UNUSED__, E_Menu_Item *mi)
2910 if (!mi->submenu) return;
2913 e_menu_item_submenu_set(mi, NULL);
2914 e_object_del(E_OBJECT(subm));
2919 _e_menu_categories_free_cb(const Eina_Hash __UNUSED__ *hash, const void __UNUSED__ *key, void *data, void *fdata __UNUSED__)
2921 E_Menu_Category_Callback *cb;
2922 E_Menu_Category *cat;
2924 cat = (E_Menu_Category *) data;
2925 EINA_LIST_FREE(cat->callbacks, cb)
2926 free(cb); /* free the callback struct */