diff --git a/src/bin/e_comp_x.c b/src/bin/e_comp_x.c index 7bf14db1e..e7bfc5680 100644 --- a/src/bin/e_comp_x.c +++ b/src/bin/e_comp_x.c @@ -19,6 +19,9 @@ */ #define MOVE_COUNTER_LIMIT 50 +#define PARENT_ACTIVATE_TIME 200 +#define PARENT_ACTIVATE_LIMIT 2 + EINTERN void _e_main_cb_x_fatal(void *data EINA_UNUSED); typedef struct _Frame_Extents Frame_Extents; @@ -115,6 +118,24 @@ _e_comp_x_focus_check(void) e_grabinput_focus(e_comp->ee_win, E_FOCUS_METHOD_PASSIVE); } +static void +_e_comp_x_client_modal_setup(E_Client *ec) +{ + E_Comp_X_Client_Data *pcd; + + ec->parent->modal = ec; + ec->parent->lock_close = 1; + pcd = _e_comp_x_client_data_get(ec->parent); + if (!pcd->lock_win) + { + eina_hash_add(clients_win_hash, &pcd->lock_win, ec->parent); + pcd->lock_win = ecore_x_window_input_new(e_client_util_pwin_get(ec->parent), 0, 0, ec->parent->w, ec->parent->h); + e_comp_ignore_win_add(E_PIXMAP_TYPE_X, pcd->lock_win); + ecore_x_window_show(pcd->lock_win); + ecore_x_icccm_name_class_set(pcd->lock_win, "comp_data->lock_win", "comp_data->lock_win"); + } +} + static void _e_comp_x_client_frame_update(E_Client *ec, int l, int r, int t, int b) { @@ -1980,7 +2001,31 @@ _e_comp_x_message(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Cl (!ec->desk->visible)) e_client_urgent_set(ec, 1); else - e_client_activate(ec, EINA_TRUE); + { + /* some apps, eg. libreoffice, create "modal" windows which + * do not have the netwm modal state set. instead, attempting to + * focus the parent window results in the app immediately trying to + * activate the "modal" window, triggering an infinite loop. + * + * by treating this "modal" window as a genuine modal window, + * we (eventually) can ignore this type of bad behavior and + * give the application/user the expected behavior + */ + if (ec->parent && (!ec->parent->modal) && (e_client_focused_get() == ec->parent) && + (ev->time - focus_time < PARENT_ACTIVATE_TIME)) + { + E_Comp_X_Client_Data *cd; + + cd = _e_comp_x_client_data_get(ec); + if (cd) + { + cd->parent_activate_count++; + if (cd->parent_activate_count >= PARENT_ACTIVATE_LIMIT) + _e_comp_x_client_modal_setup(ec); + } + } + e_client_activate(ec, EINA_TRUE); + } } else evas_object_raise(ec->frame); @@ -3525,21 +3570,7 @@ _e_comp_x_hook_client_fetch(void *d EINA_UNUSED, E_Client *ec) { evas_object_layer_set(ec->frame, ec->parent->layer); if (ec->netwm.state.modal) - { - E_Comp_X_Client_Data *pcd; - - ec->parent->modal = ec; - ec->parent->lock_close = 1; - pcd = _e_comp_x_client_data_get(ec->parent); - if (!pcd->lock_win) - { - eina_hash_add(clients_win_hash, &pcd->lock_win, ec->parent); - pcd->lock_win = ecore_x_window_input_new(e_client_util_pwin_get(ec->parent), 0, 0, ec->parent->w, ec->parent->h); - e_comp_ignore_win_add(E_PIXMAP_TYPE_X, pcd->lock_win); - ecore_x_window_show(pcd->lock_win); - ecore_x_icccm_name_class_set(pcd->lock_win, "comp_data->lock_win", "comp_data->lock_win"); - } - } + _e_comp_x_client_modal_setup(ec); if (e_config->focus_setting == E_FOCUS_NEW_DIALOG || (ec->parent->focused && (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED))) diff --git a/src/bin/e_comp_x.h b/src/bin/e_comp_x.h index 33360e588..af1a01c9a 100644 --- a/src/bin/e_comp_x.h +++ b/src/bin/e_comp_x.h @@ -36,6 +36,8 @@ struct _E_Comp_X_Client_Data Ecore_Timer *first_draw_delay; //configurable placebo Eina_Bool first_damage : 1; //ignore first damage on non-re_manage clients + unsigned int parent_activate_count; //number of times a win has activated itself when parent was focused + struct { struct