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
This commit is contained in:
Dana Jansens 2009-12-17 16:20:03 -05:00
parent 965ed8907a
commit ad812e6299
6 changed files with 89 additions and 12 deletions

View file

@ -61,6 +61,7 @@
<xsd:element minOccurs="0" name="underMouse" type="ob:bool"/>
<xsd:element minOccurs="0" name="focusDelay" type="xsd:integer"/>
<xsd:element minOccurs="0" name="raiseOnFocus" type="ob:bool"/>
<xsd:element minOccurs="0" name="unfocusOnLeave" type="ob:bool"/>
</xsd:all>
</xsd:complexType>
<xsd:complexType name="placement">

View file

@ -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)

View file

@ -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);

View file

@ -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;

View file

@ -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)

View file

@ -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);