From fa7744b4de1a694630b703e32295598c963a1572 Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Fri, 26 Jul 2013 14:42:48 +0100 Subject: [PATCH] fix ibar client menu to track multiple windows per exe --- src/bin/e_border.c | 51 +++++----- src/bin/e_exec.c | 21 +++-- src/bin/e_exec.h | 4 +- src/modules/ibar/e_mod_main.c | 170 ++++++++++++++++++++++++---------- 4 files changed, 169 insertions(+), 77 deletions(-) diff --git a/src/bin/e_border.c b/src/bin/e_border.c index a22962ab0..ae0802d3d 100644 --- a/src/bin/e_border.c +++ b/src/bin/e_border.c @@ -4899,10 +4899,10 @@ _e_border_del(E_Border *bd) if (bd->exe_inst) { - if (bd->exe_inst->phony) + if (bd->exe_inst->phony && (eina_list_count(bd->exe_inst->borders) == 1)) e_exec_phony_del(bd->exe_inst); else - bd->exe_inst->bd = NULL; + bd->exe_inst->borders = eina_list_remove(bd->exe_inst->borders, bd); bd->exe_inst = NULL; } @@ -7999,30 +7999,35 @@ _e_border_eval0(E_Border *bd) { inst = e_exec_startup_id_pid_instance_find(bd->client.netwm.startup_id, bd->client.netwm.pid); - if ((inst) && (inst->used == 0)) + if (inst) { - E_Zone *zone; - E_Desk *desk; - - inst->used++; - zone = e_container_zone_number_get(bd->zone->container, - inst->screen); - if (zone) e_border_zone_set(bd, zone); - desk = e_desk_at_xy_get(bd->zone, inst->desk_x, - inst->desk_y); - if (desk) e_border_desk_set(bd, desk); - if (bd->client.netwm.pid != ecore_exe_pid_get(inst->exe)) + Eina_Bool found; + if (inst->used == 0) { - /* most likely what has happened here is that the .desktop launcher - * has spawned a process which then created this border, meaning the - * E_Exec instance will be deleted in a moment, and we will be unable to track it. - * to prevent this, we convert our instance to a phony - */ - inst->phony = 1; + E_Zone *zone; + E_Desk *desk; + + inst->used++; + zone = e_container_zone_number_get(bd->zone->container, + inst->screen); + if (zone) e_border_zone_set(bd, zone); + desk = e_desk_at_xy_get(bd->zone, inst->desk_x, + inst->desk_y); + if (desk) e_border_desk_set(bd, desk); + if (bd->client.netwm.pid != ecore_exe_pid_get(inst->exe)) + { + /* most likely what has happened here is that the .desktop launcher + * has spawned a process which then created this border, meaning the + * E_Exec instance will be deleted in a moment, and we will be unable to track it. + * to prevent this, we convert our instance to a phony + */ + inst->phony = 1; + } } - inst->bd = bd; - bd->exe_inst = inst; - e_exec_instance_found(inst); + found = !!inst->borders; + e_exec_instance_client_add(inst, bd); + if (!found) + e_exec_instance_found(inst); } else if (!inst) e_exec_phony(bd); diff --git a/src/bin/e_exec.c b/src/bin/e_exec.c index 25f9eab65..5ea76f1c5 100644 --- a/src/bin/e_exec.c +++ b/src/bin/e_exec.c @@ -77,6 +77,7 @@ static E_Exec_Instance *(*_e_exec_executor_func)(void *data, E_Zone * zone, Efre static void *_e_exec_executor_data = NULL; EAPI int E_EVENT_EXEC_NEW = -1; +EAPI int E_EVENT_EXEC_NEW_CLIENT = -1; EAPI int E_EVENT_EXEC_DEL = -1; /* externally accessible functions */ @@ -93,6 +94,7 @@ e_exec_init(void) #endif E_EVENT_EXEC_NEW = ecore_event_type_new(); + E_EVENT_EXEC_NEW_CLIENT = ecore_event_type_new(); E_EVENT_EXEC_DEL = ecore_event_type_new(); return 1; } @@ -257,7 +259,7 @@ e_exec_phony(E_Border *bd) } inst->used = 1; bd->exe_inst = inst; - inst->bd = bd; + inst->borders = eina_list_append(inst->borders, bd); if (bd->zone) inst->screen = bd->zone->num; if (bd->desk) { @@ -341,6 +343,15 @@ e_exec_instance_found(E_Exec_Instance *inst) _e_exe_instance_watchers_call(inst, E_EXEC_WATCH_STARTED); } +EAPI void +e_exec_instance_client_add(E_Exec_Instance *inst, E_Border *bd) +{ + inst->borders = eina_list_append(inst->borders, bd); + bd->exe_inst = inst; + inst->ref++; + ecore_event_add(E_EVENT_EXEC_NEW_CLIENT, inst, _e_exec_cb_exec_new_free, inst); +} + EAPI void e_exec_instance_watcher_add(E_Exec_Instance *inst, void (*func)(void *data, E_Exec_Instance *inst, E_Exec_Watch_Type type), const void *data) { @@ -618,6 +629,7 @@ static void _e_exec_instance_free(E_Exec_Instance *inst) { Eina_List *instances; + E_Border *bd; if (inst->ref) return; E_FREE_LIST(inst->watchers, free); @@ -644,11 +656,8 @@ _e_exec_instance_free(E_Exec_Instance *inst) e_exec_start_pending = eina_list_remove(e_exec_start_pending, inst->desktop); if (inst->expire_timer) ecore_timer_del(inst->expire_timer); - if (inst->bd) - { - inst->bd->exe_inst = NULL; - inst->bd = NULL; - } + EINA_LIST_FREE(inst->borders, bd) + bd->exe_inst = NULL; if (inst->desktop) efreet_desktop_free(inst->desktop); free(inst); } diff --git a/src/bin/e_exec.h b/src/bin/e_exec.h index 9cc39662c..86090b80b 100644 --- a/src/bin/e_exec.h +++ b/src/bin/e_exec.h @@ -9,7 +9,7 @@ typedef struct _E_Exec_Instance E_Exec_Instance; struct _E_Exec_Instance { Efreet_Desktop *desktop; - E_Border *bd; + Eina_List *borders; const char *key; Ecore_Exe *exe; int startup_id; @@ -46,9 +46,11 @@ EAPI void e_exec_instance_watcher_del(E_Exec_Instance *inst, void (*func) (void EAPI const Eina_List *e_exec_desktop_instances_find(const Efreet_Desktop *desktop); EAPI const Eina_Hash *e_exec_instances_get(void); +EAPI void e_exec_instance_client_add(E_Exec_Instance *inst, E_Border *bd); /* sends E_Exec_Instance */ EAPI extern int E_EVENT_EXEC_NEW; +EAPI extern int E_EVENT_EXEC_NEW_CLIENT; EAPI extern int E_EVENT_EXEC_DEL; #endif diff --git a/src/modules/ibar/e_mod_main.c b/src/modules/ibar/e_mod_main.c index 7c70d7c3a..5cf91c5c0 100644 --- a/src/modules/ibar/e_mod_main.c +++ b/src/modules/ibar/e_mod_main.c @@ -524,8 +524,18 @@ _ibar_fill(IBar *b) { EINA_LIST_FOREACH(l, ll, exe) { + E_Border *bd; + Eina_List *lll; + Eina_Bool skip = EINA_TRUE; + if (!exe->desktop) continue; - if (exe->bd && exe->bd->client.netwm.state.skip_taskbar) continue; + EINA_LIST_FOREACH(exe->borders, lll, bd) + if (!bd->client.netwm.state.skip_taskbar) + { + skip = EINA_FALSE; + break; + } + if (skip) continue; ic = eina_hash_find(b->icon_hash, _desktop_name_get(exe->desktop)); if (ic) { @@ -1025,6 +1035,7 @@ _ibar_cb_icon_menu_img_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EIN IBar_Icon *ic = evas_object_data_del(data, "ibar_icon"); if (!ic) return; //menu is closing + if (!ic->menu) return; //who knows edje_object_part_box_remove(ic->menu->o_bg, "e.box", data); evas_object_del(data); if (eina_list_count(ic->exes) < 2) @@ -1071,33 +1082,37 @@ _ibar_icon_menu(IBar_Icon *ic) { Evas_Object *img; const char *txt; + Eina_List *ll; + E_Border *bd; - if (!exe->bd) continue; //WTF - it = edje_object_add(e); - e_popup_object_add(ic->menu->win, it); - e_theme_edje_object_set(it, "base/theme/modules/ibar", - "e/modules/ibar/menu/item"); - img = e_comp_win_image_mirror_add(exe->bd->cw); - evas_object_event_callback_add(img, EVAS_CALLBACK_DEL, - _ibar_cb_icon_menu_img_del, it); - txt = exe->bd->client.netwm.name ?: - (exe->bd->client.icccm.title ?: exe->bd->client.icccm.name); - w = exe->bd->cw->pw; - h = exe->bd->cw->ph; - e_popup_object_add(ic->menu->win, img); - evas_object_show(img); - edje_extern_object_aspect_set(img, EDJE_ASPECT_CONTROL_BOTH, w, h); - edje_object_part_swallow(it, "e.swallow.icon", img); - edje_object_part_text_set(it, "e.text.title", txt); - edje_object_calc_force(it); - edje_object_size_min_calc(it, &w, &h); - edje_extern_object_min_size_set(it, w, h); - evas_object_size_hint_min_set(it, w, h); - evas_object_show(it); - evas_object_event_callback_add(it, EVAS_CALLBACK_MOUSE_UP, - _ibar_cb_icon_menu_mouse_up, exe->bd); - evas_object_data_set(it, "ibar_icon", ic); - edje_object_part_box_append(o, "e.box", it); + EINA_LIST_FOREACH(exe->borders, ll, bd) + { + if (bd->client.netwm.state.skip_taskbar) continue; + it = edje_object_add(e); + e_popup_object_add(ic->menu->win, it); + e_theme_edje_object_set(it, "base/theme/modules/ibar", + "e/modules/ibar/menu/item"); + img = e_comp_win_image_mirror_add(bd->cw); + evas_object_event_callback_add(img, EVAS_CALLBACK_DEL, + _ibar_cb_icon_menu_img_del, it); + txt = e_border_name_get(bd); + w = bd->cw->pw; + h = bd->cw->ph; + e_popup_object_add(ic->menu->win, img); + evas_object_show(img); + edje_extern_object_aspect_set(img, EDJE_ASPECT_CONTROL_BOTH, w, h); + edje_object_part_swallow(it, "e.swallow.icon", img); + edje_object_part_text_set(it, "e.text.title", txt); + edje_object_calc_force(it); + edje_object_size_min_calc(it, &w, &h); + edje_extern_object_min_size_set(it, w, h); + evas_object_size_hint_min_set(it, w, h); + evas_object_show(it); + evas_object_event_callback_add(it, EVAS_CALLBACK_MOUSE_UP, + _ibar_cb_icon_menu_mouse_up, bd); + evas_object_data_set(it, "ibar_icon", ic); + edje_object_part_box_append(o, "e.box", it); + } } if (!ic->menu->win->objects) { @@ -1293,35 +1308,56 @@ _ibar_cb_icon_reset(void *data) static void _ibar_cb_icon_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) { - Evas_Event_Mouse_Wheel *ev; + Evas_Event_Mouse_Wheel *ev = event_info; E_Exec_Instance *exe; - IBar_Icon *ic; + IBar_Icon *ic = data; + E_Border *cur, *sel = NULL; + Eina_List *l; - ev = event_info; - ic = data; - if (!ic->exes) return; + cur = e_border_focused_get(); if (!ic->exe_current) - ic->exe_current = eina_list_nth_list(ic->exes, 0); - + ic->exe_current = ic->exes; + + exe = eina_list_data_get(ic->exe_current); if (ev->z < 0) - { - ic->exe_current = eina_list_next(ic->exe_current); - if (!ic->exe_current) - ic->exe_current = eina_list_nth_list(ic->exes, 0); + { + if (cur->exe_inst == exe) + { + l = eina_list_data_find_list(exe->borders, cur); + if (l) sel = eina_list_data_get(eina_list_next(l)); + } + if (!sel) + { + ic->exe_current = eina_list_next(ic->exe_current); + if (!ic->exe_current) + ic->exe_current = ic->exes; + } } else if (ev->z > 0) { - ic->exe_current = eina_list_prev(ic->exe_current); - if (!ic->exe_current) - ic->exe_current = eina_list_last(ic->exes); + if (cur->exe_inst == exe) + { + l = eina_list_data_find_list(exe->borders, cur); + if (l) sel = eina_list_data_get(eina_list_prev(l)); + } + if (!sel) + { + ic->exe_current = eina_list_prev(ic->exe_current); + if (!ic->exe_current) + ic->exe_current = eina_list_last(ic->exes); + } + } + + if (!sel) + { + exe = eina_list_data_get(ic->exe_current); + sel = eina_list_data_get(exe->borders); } - exe = eina_list_data_get(ic->exe_current); - - if (!exe->bd) return; - e_border_activate(exe->bd, 1); + if (sel) + e_border_activate(sel, 1); } static void @@ -2237,14 +2273,52 @@ _ibar_cb_exec_del(void *d EINA_UNUSED, int t EINA_UNUSED, E_Exec_Instance *exe) } static Eina_Bool -_ibar_cb_exec_new(void *d EINA_UNUSED, int t EINA_UNUSED, E_Exec_Instance *exe) +_ibar_cb_exec_new_client(void *d EINA_UNUSED, int t EINA_UNUSED, E_Exec_Instance *exe) { IBar *b; + E_Border *bd; Eina_List *l; Eina_Bool skip; if (!exe->desktop) return ECORE_CALLBACK_RENEW; //can't do anything here :( - skip = exe->bd && exe->bd->client.netwm.state.skip_taskbar; + bd = eina_list_last_data_get(exe->borders); //only care about last (new) one + skip = bd->client.netwm.state.skip_taskbar; + EINA_LIST_FOREACH(ibars, l, b) + { + IBar_Icon *ic; + + ic = eina_hash_find(b->icon_hash, _desktop_name_get(exe->desktop)); + if (ic) + { + _ibar_icon_signal_emit(ic, "e,state,started", "e"); + if (!ic->exes) _ibar_icon_signal_emit(ic, "e,state,on", "e"); + if (skip) continue; + if (!eina_list_data_find(ic->exes, exe)) + ic->exes = eina_list_append(ic->exes, exe); + } + else if (!b->inst->ci->dont_add_nonorder) + { + if (skip) continue; + _ibar_sep_create(b); + ic = _ibar_icon_notinorder_new(b, exe); + _ibar_resize_handle(b); + } + } + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_ibar_cb_exec_new(void *d EINA_UNUSED, int t EINA_UNUSED, E_Exec_Instance *exe) +{ + IBar *b; + E_Border *bd; + Eina_List *l; + Eina_Bool skip = EINA_TRUE; + + if (!exe->desktop) return ECORE_CALLBACK_RENEW; //can't do anything here :( + EINA_LIST_FOREACH(exe->borders, l, bd) + if (!bd->client.netwm.state.skip_taskbar) + skip = EINA_FALSE; EINA_LIST_FOREACH(ibars, l, b) { IBar_Icon *ic; @@ -2325,6 +2399,8 @@ e_modapi_init(E_Module *m) _ibar_cb_config_icons, NULL); E_LIST_HANDLER_APPEND(ibar_config->handlers, E_EVENT_EXEC_NEW, _ibar_cb_exec_new, NULL); + E_LIST_HANDLER_APPEND(ibar_config->handlers, E_EVENT_EXEC_NEW_CLIENT, + _ibar_cb_exec_new_client, NULL); E_LIST_HANDLER_APPEND(ibar_config->handlers, E_EVENT_EXEC_DEL, _ibar_cb_exec_del, NULL); E_LIST_HANDLER_APPEND(ibar_config->handlers, E_EVENT_BORDER_PROPERTY,