diff --git a/src/bin/e_comp_x.c b/src/bin/e_comp_x.c index 44ddb0737..e3a33d4e1 100644 --- a/src/bin/e_comp_x.c +++ b/src/bin/e_comp_x.c @@ -15,6 +15,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; @@ -90,6 +93,21 @@ _e_comp_x_focus_check(E_Comp *comp) e_grabinput_focus(comp->ee_win, E_FOCUS_METHOD_PASSIVE); } +static void +_e_comp_x_client_modal_setup(E_Client *ec) +{ + ec->parent->modal = ec; + ec->parent->lock_close = 1; + if (!ec->parent->comp_data->lock_win) + { + eina_hash_add(clients_win_hash, &ec->parent->comp_data->lock_win, ec->parent); + ec->parent->comp_data->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, ec->parent->comp_data->lock_win); + ecore_x_window_show(ec->parent->comp_data->lock_win); + ecore_x_icccm_name_class_set(ec->parent->comp_data->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) { @@ -1948,7 +1966,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) && + /* efl < 1.15 does not have a valid time member, so I guess just accept all such + * events here? + */ + ((!ev->time) || (ev->time - focus_time < PARENT_ACTIVATE_TIME))) + { + if (ec->comp_data) + { + ec->comp_data->parent_activate_count++; + if (ec->comp_data->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); @@ -3440,18 +3482,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) - { - ec->parent->modal = ec; - ec->parent->lock_close = 1; - if (!ec->parent->comp_data->lock_win) - { - eina_hash_add(clients_win_hash, &ec->parent->comp_data->lock_win, ec->parent); - ec->parent->comp_data->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, ec->parent->comp_data->lock_win); - ecore_x_window_show(ec->parent->comp_data->lock_win); - ecore_x_icccm_name_class_set(ec->parent->comp_data->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 9eec6e3b6..1de8c24d7 100644 --- a/src/bin/e_comp_x.h +++ b/src/bin/e_comp_x.h @@ -105,6 +105,7 @@ struct _E_Comp_X_Client_Data Eina_Bool frame_update : 1; Eina_Bool evas_init : 1; Eina_Bool unredirected_single : 1; + unsigned int parent_activate_count; //number of times a win has activated itself when parent was focused }; EINTERN Eina_Bool e_comp_x_init(void);