From ad812e6299223efb0cb4faee03ce99870e5c7ce5 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Thu, 17 Dec 2009 16:20:03 -0500 Subject: [PATCH] Add a focus option, unfocusOnLeave that removes focus from a window when the pointer leaves it This uses the same delay to unfocus as is used for focusing on enter --- data/rc.xsd | 1 + openbox/actions.c | 20 +++++++++----- openbox/config.c | 4 +++ openbox/config.h | 3 +++ openbox/event.c | 69 +++++++++++++++++++++++++++++++++++++++++++---- openbox/event.h | 4 +++ 6 files changed, 89 insertions(+), 12 deletions(-) diff --git a/data/rc.xsd b/data/rc.xsd index 499b81c9..06286426 100644 --- a/data/rc.xsd +++ b/data/rc.xsd @@ -61,6 +61,7 @@ + diff --git a/openbox/actions.c b/openbox/actions.c index 78546361..5d47b33f 100644 --- a/openbox/actions.c +++ b/openbox/actions.c @@ -408,13 +408,19 @@ void actions_client_move(ObActionsData *data, gboolean start) are ignored during a grab, so don't force fake ones when they should be ignored */ - if ((c = client_under_pointer()) && c != data->client && - !grab_on_pointer()) - { - ob_debug_type(OB_DEBUG_FOCUS, - "Generating fake enter because we did a " - "mouse-event action"); - event_enter_client(c); + if (!grab_on_pointer()) { + if ((c = client_under_pointer()) && c != data->client) { + ob_debug_type(OB_DEBUG_FOCUS, + "Generating fake enter because we did a " + "mouse-event action"); + event_enter_client(c); + } + else if (!c && c != data->client) { + ob_debug_type(OB_DEBUG_FOCUS, + "Generating fake leave because we did a " + "mouse-event action"); + event_enter_client(data->client); + } } } else if (!data->button && !config_focus_under_mouse) diff --git a/openbox/config.c b/openbox/config.c index 0d28be2c..33fadeb7 100644 --- a/openbox/config.c +++ b/openbox/config.c @@ -34,6 +34,7 @@ guint config_focus_delay; gboolean config_focus_raise; gboolean config_focus_last; gboolean config_focus_under_mouse; +gboolean config_unfocus_leave; ObPlacePolicy config_place_policy; gboolean config_place_center; @@ -504,6 +505,8 @@ static void parse_focus(xmlNodePtr node, gpointer d) config_focus_last = obt_parse_node_bool(n); if ((n = obt_parse_find_node(node, "underMouse"))) config_focus_under_mouse = obt_parse_node_bool(n); + if ((n = obt_parse_find_node(node, "unfocusOnLeave"))) + config_unfocus_leave = obt_parse_node_bool(n); } static void parse_placement(xmlNodePtr node, gpointer d) @@ -926,6 +929,7 @@ void config_startup(ObtParseInst *i) config_focus_raise = FALSE; config_focus_last = TRUE; config_focus_under_mouse = FALSE; + config_unfocus_leave = FALSE; obt_parse_register(i, "focus", parse_focus, NULL); diff --git a/openbox/config.h b/openbox/config.h index d9e897a1..18c97ede 100644 --- a/openbox/config.h +++ b/openbox/config.h @@ -73,6 +73,9 @@ extern gboolean config_focus_last; /*! Try keep focus on the window under the mouse when the mouse is not moving */ extern gboolean config_focus_under_mouse; +/*! Remove focus from windows when the mouse leaves them + */ +extern gboolean config_unfocus_leave; /*! The algorithm to use for placing new windows */ extern ObPlacePolicy config_place_policy; diff --git a/openbox/event.c b/openbox/event.c index 63f23ff9..1b7b7739 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -97,6 +97,7 @@ static void event_ignore_enter_range(gulong start, gulong end); static void focus_delay_dest(gpointer data); static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2); static gboolean focus_delay_func(gpointer data); +static gboolean unfocus_delay_func(gpointer data); static void focus_delay_client_dest(ObClient *client, gpointer data); Time event_curtime = CurrentTime; @@ -845,6 +846,41 @@ void event_enter_client(ObClient *client) } } +void event_leave_client(ObClient *client) +{ + g_assert(config_focus_follow); + + if (is_enter_focus_event_ignored(event_curserial)) { + ob_debug_type(OB_DEBUG_FOCUS, "Ignoring leave event with serial %lu\n" + "on client 0x%x", event_curserial, client->window); + return; + } + + if (client == focus_client) { + if (config_focus_delay) { + ObFocusDelayData *data; + + obt_main_loop_timeout_remove(ob_main_loop, unfocus_delay_func); + + data = g_new(ObFocusDelayData, 1); + data->client = client; + data->time = event_curtime; + data->serial = event_curserial; + + obt_main_loop_timeout_add(ob_main_loop, + config_focus_delay * 1000, + unfocus_delay_func, + data, focus_delay_cmp, focus_delay_dest); + } else { + ObFocusDelayData data; + data.client = client; + data.time = event_curtime; + data.serial = event_curserial; + unfocus_delay_func(&data); + } + } +} + static gboolean *context_to_button(ObFrame *f, ObFrameContext con, gboolean press) { if (press) { @@ -1014,15 +1050,18 @@ static void event_handle_client(ObClient *client, XEvent *e) e->xcrossing.detail, (client?client->window:0)); if (grab_on_keyboard()) break; - if (config_focus_follow && config_focus_delay && + if (config_focus_follow && /* leave inferior events can happen when the mouse goes onto the window's border and then into the window before the delay is up */ e->xcrossing.detail != NotifyInferior) { - obt_main_loop_timeout_remove_data(ob_main_loop, - focus_delay_func, - client, FALSE); + if (config_focus_delay) + obt_main_loop_timeout_remove_data(ob_main_loop, + focus_delay_func, + client, FALSE); + if (config_unfocus_leave) + event_leave_client(client); } break; default: @@ -1069,8 +1108,13 @@ static void event_handle_client(ObClient *client, XEvent *e) e->xcrossing.detail, e->xcrossing.serial, (client?client->window:0)); - if (config_focus_follow) + if (config_focus_follow) { + if (config_focus_delay) + obt_main_loop_timeout_remove_data(ob_main_loop, + unfocus_delay_func, + client, FALSE); event_enter_client(client); + } } break; default: @@ -1956,10 +2000,24 @@ static gboolean focus_delay_func(gpointer data) return FALSE; /* no repeat */ } +static gboolean unfocus_delay_func(gpointer data) +{ + ObFocusDelayData *d = data; + Time old = event_curtime; + + event_curtime = d->time; + event_curserial = d->serial; + focus_nothing(); + event_curtime = old; + return FALSE; /* no repeat */ +} + static void focus_delay_client_dest(ObClient *client, gpointer data) { obt_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, client, FALSE); + obt_main_loop_timeout_remove_data(ob_main_loop, unfocus_delay_func, + client, FALSE); } void event_halt_focus_delay(void) @@ -1967,6 +2025,7 @@ void event_halt_focus_delay(void) /* ignore all enter events up till the event which caused this to occur */ if (event_curserial) event_ignore_enter_range(1, event_curserial); obt_main_loop_timeout_remove(ob_main_loop, focus_delay_func); + obt_main_loop_timeout_remove(ob_main_loop, unfocus_delay_func); } gulong event_start_ignore_all_enters(void) diff --git a/openbox/event.h b/openbox/event.h index 4fd72865..4a8d7901 100644 --- a/openbox/event.h +++ b/openbox/event.h @@ -40,6 +40,10 @@ void event_shutdown(gboolean reconfig); follows mouse */ void event_enter_client(struct _ObClient *client); +/*! Make as if the mouse just left the client, use only when using focus + follows mouse */ +void event_leave_client(struct _ObClient *client); + /*! Make mouse focus not move at all from the stuff that happens between these two function calls. */ gulong event_start_ignore_all_enters(void); -- 2.39.2