X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fevent.c;h=5388e227c4a3a7ce6d823496bf9d8645100cdf4a;hb=d5f9df0845eb28dee542a789e43ca4cc1b6d0a4f;hp=68d511352201e9afe33b584ed4168be7bd558666;hpb=4ccc4c5ed7d5cffc4bf733191f7bc30fbbf069c8;p=chaz%2Fopenbox diff --git a/openbox/event.c b/openbox/event.c index 68d51135..5388e227 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -1,4 +1,24 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + event.c for the Openbox window manager + Copyright (c) 2003 Ben Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + +#include "event.h" #include "debug.h" +#include "window.h" #include "openbox.h" #include "dock.h" #include "client.h" @@ -18,7 +38,6 @@ #include "group.h" #include "stacking.h" #include "extensions.h" -#include "event.h" #include #include @@ -42,7 +61,6 @@ typedef struct } ObEventData; static void event_process(const XEvent *e, gpointer data); -static void event_done(gpointer data); static void event_handle_root(XEvent *e); static void event_handle_menu(XEvent *e); static void event_handle_dock(ObDock *s, XEvent *e); @@ -78,7 +96,7 @@ static const int mask_table[] = { }; static int mask_table_size; -static ObClient *focus_delay_client; +static guint ignore_enter_focus = 0; static gboolean menu_can_hide; @@ -133,7 +151,7 @@ void event_startup(gboolean reconfig) } } - ob_main_loop_x_add(ob_main_loop, event_process, event_done, NULL, NULL); + ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL); #ifdef USE_SM IceAddConnectionWatch(ice_watch, NULL); @@ -284,32 +302,24 @@ static void event_hack_mods(XEvent *e) static gboolean event_ignore(XEvent *e, ObClient *client) { - gboolean ignore = FALSE; - XEvent ce; - switch(e->type) { case FocusIn: - while (XCheckTypedWindowEvent(ob_display, e->xfocus.window, - FocusIn, &ce)) - { - if (!INVALID_FOCUSIN(&ce)) { - XPutBackEvent(ob_display, &ce); - ignore = TRUE; - break; - } - } - /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut because of RevertToPointerRoot. If the focus ends up reverting to pointer root on a workspace change, then the FocusIn event that we want will be of type NotifyAncestor. This situation does not occur for FocusOut, so it is safely ignored there. */ - if (ignore || INVALID_FOCUSIN(e) || client == NULL) { + if (INVALID_FOCUSIN(e) || + client == NULL) { #ifdef DEBUG_FOCUS ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n", e->xfocus.window, e->xfocus.mode, e->xfocus.detail); #endif + /* says a client was not found for the event (or a valid FocusIn + event was not found. + */ + e->xfocus.window = None; return TRUE; } @@ -319,20 +329,10 @@ static gboolean event_ignore(XEvent *e, ObClient *client) #endif break; case FocusOut: - while (XCheckTypedWindowEvent(ob_display, e->xfocus.window, - FocusOut, &ce)) - { - if (!INVALID_FOCUSOUT(&ce)) { - XPutBackEvent(ob_display, &ce); - ignore = TRUE; - break; - } - } - - if (ignore || INVALID_FOCUSOUT(e)) { + if (INVALID_FOCUSOUT(e)) { #ifdef DEBUG_FOCUS - ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n", - e->xfocus.window, e->xfocus.mode, e->xfocus.detail); + ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n", + e->xfocus.window, e->xfocus.mode, e->xfocus.detail); #endif return TRUE; } @@ -341,34 +341,87 @@ static gboolean event_ignore(XEvent *e, ObClient *client) ob_debug("FocusOut on %lx mode %d detail %d\n", e->xfocus.window, e->xfocus.mode, e->xfocus.detail); #endif - break; - case EnterNotify: - case LeaveNotify: - /* NotifyUngrab occurs when a mouse button is released and the event is - caused, like when lowering a window */ - /* NotifyVirtual and NotifyAncestor occurs when ungrabbing the - pointer (Ancestor happens when the pointer is on a window border) */ - if (e->xcrossing.mode == NotifyGrab || - e->xcrossing.detail == NotifyInferior || - (e->xcrossing.mode == NotifyUngrab && - (e->xcrossing.detail == NotifyAncestor || - e->xcrossing.detail == NotifyNonlinearVirtual || - e->xcrossing.detail == NotifyVirtual))) { -#ifdef aDEBUG_FOCUS - ob_debug("%sNotify mode %d detail %d on %lx IGNORED\n", - (e->type == EnterNotify ? "Enter" : "Leave"), - e->xcrossing.mode, - e->xcrossing.detail, client?client->window:0); + + { + XEvent fe; + gboolean fallback = TRUE; + + while (TRUE) { + if (!XCheckTypedWindowEvent(ob_display, e->xfocus.window, + FocusOut, &fe)) + if (!XCheckTypedEvent(ob_display, FocusIn, &fe)) + break; + if (fe.type == FocusOut) { +#ifdef DEBUG_FOCUS + ob_debug("found pending FocusOut\n"); #endif - return TRUE; - } -#ifdef aDEBUG_FOCUS - ob_debug("%sNotify mode %d detail %d on %lx\n", - (e->type == EnterNotify ? "Enter" : "Leave"), - e->xcrossing.mode, - e->xcrossing.detail, client?client->window:0); + if (!INVALID_FOCUSOUT(&fe)) { + /* if there is a VALID FocusOut still coming, don't + fallback focus yet, we'll deal with it then */ + XPutBackEvent(ob_display, &fe); + fallback = FALSE; + break; + } + } else { +#ifdef DEBUG_FOCUS + ob_debug("found pending FocusIn\n"); #endif - break; + /* is the focused window getting a FocusOut/In back to + itself? + */ + if (fe.xfocus.window == e->xfocus.window && + !event_ignore(&fe, client)) { + /* + if focus_client is not set, then we can't do + this. we need the FocusIn. This happens in the + case when the set_focus_client(NULL) in the + focus_fallback function fires and then + focus_fallback picks the currently focused + window (such as on a SendToDesktop-esque action. + */ + if (focus_client) { +#ifdef DEBUG_FOCUS + ob_debug("focused window got an Out/In back to " + "itself IGNORED both\n"); +#endif + return TRUE; + } else { + event_process(&fe, NULL); +#ifdef DEBUG_FOCUS + ob_debug("focused window got an Out/In back to " + "itself but focus_client was null " + "IGNORED just the Out\n"); +#endif + return TRUE; + } + } + + { + ObEventData d; + + /* once all the FocusOut's have been dealt with, if + there is a FocusIn still left and it is valid, then + use it */ + event_process(&fe, &d); + if (!d.ignored) { +#ifdef DEBUG_FOCUS + ob_debug("FocusIn was OK, so don't fallback\n"); +#endif + fallback = FALSE; + break; + } + } + } + } + if (fallback) { +#ifdef DEBUG_FOCUS + ob_debug("no valid FocusIn and no FocusOut events found, " + "falling back\n"); +#endif + focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS); + } + } + break; } return FALSE; } @@ -462,9 +515,14 @@ static void event_process(const XEvent *ec, gpointer data) event_handle_menu(e); else { if (!keyboard_process_interactive_grab(e, &client)) { - if (moveresize_in_progress) + if (moveresize_in_progress) { moveresize_event(e); + /* make further actions work on the client being + moved/resized */ + client = moveresize_client; + } + menu_can_hide = FALSE; ob_main_loop_timeout_add(ob_main_loop, G_USEC_PER_SEC / 4, @@ -479,19 +537,12 @@ static void event_process(const XEvent *ec, gpointer data) causes the window which appears to be focused to be the one on which the actions will be executed */ keyboard_event((focus_cycle_target ? - focus_cycle_target : - (client ? client : focus_client)), e); + focus_cycle_target : client), e); } } } } -static void event_done(gpointer data) -{ - if (!focus_client) - focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS); -} - static void event_handle_root(XEvent *e) { Atom msgtype; @@ -499,7 +550,7 @@ static void event_handle_root(XEvent *e) switch(e->type) { case SelectionClear: ob_debug("Another WM has requested to replace us. Exiting.\n"); - ob_exit(); + ob_exit(0); break; case ClientMessage: @@ -550,6 +601,22 @@ static void event_handle_group(ObGroup *group, XEvent *e) event_handle_client(it->data, e); } +void event_enter_client(ObClient *client) +{ + g_assert(config_focus_follow); + + if (client_normal(client) && client_can_focus(client)) { + if (config_focus_delay) { + ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func); + ob_main_loop_timeout_add(ob_main_loop, + config_focus_delay, + focus_delay_func, + client, NULL); + } else + focus_delay_func(client); + } +} + static void event_handle_client(ObClient *client, XEvent *e) { XEvent ce; @@ -597,22 +664,27 @@ static void event_handle_client(ObClient *client, XEvent *e) break; case FocusIn: #ifdef DEBUG_FOCUS - ob_debug("Focus%s on client for %lx\n", (e->type==FocusIn?"In":"Out"), - client->window); + ob_debug("FocusIn on client for %lx\n", client->window); #endif - if (client != focus_client) + if (client != focus_client) { focus_set_client(client); - frame_adjust_focus(client->frame, e->type == FocusIn); + frame_adjust_focus(client->frame, TRUE); + } break; case FocusOut: #ifdef DEBUG_FOCUS - ob_debug("Focus%s on client for %lx\n", (e->type==FocusIn?"In":"Out"), - client->window); + ob_debug("FocusOut on client for %lx\n", client->window); #endif - if (client == focus_client) - focus_client = NULL; - frame_adjust_focus(client->frame, e->type == FocusIn); - break; + /* are we a fullscreen window or a transient of one? (checks layer) + if we are then we need to be iconified since we are losing focus + */ + if (client->layer == OB_STACKING_LAYER_FULLSCREEN && !client->iconic && + !client_search_focus_tree_full(client)) + /* iconify fullscreen windows when they and their transients + aren't focused */ + client_iconify(client, TRUE, TRUE); + frame_adjust_focus(client->frame, FALSE); + break; case LeaveNotify: con = frame_context(client, e->xcrossing.window); switch (con) { @@ -637,19 +709,26 @@ static void event_handle_client(ObClient *client, XEvent *e) frame_adjust_state(client->frame); break; case OB_FRAME_CONTEXT_FRAME: - /* XXX if doing a 'reconfigure' make sure you kill this timer, - maybe all timers.. */ - if (config_focus_delay && client == focus_delay_client) { + /* + if (config_focus_follow && config_focus_delay) ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, - focus_delay_client); - focus_delay_client = NULL; - } + client); + */ + break; default: break; } break; case EnterNotify: + { + gboolean nofocus = FALSE; + + if (ignore_enter_focus) { + ignore_enter_focus--; + nofocus = TRUE; + } + con = frame_context(client, e->xcrossing.window); switch (con) { case OB_FRAME_CONTEXT_MAXIMIZE: @@ -673,27 +752,33 @@ static void event_handle_client(ObClient *client, XEvent *e) frame_adjust_state(client->frame); break; case OB_FRAME_CONTEXT_FRAME: - if (client_normal(client)) { - if (config_focus_follow) { -#ifdef aDEBUG_FOCUS - ob_debug("EnterNotify on %lx, focusing window\n", - client->window); + if (e->xcrossing.mode == NotifyGrab || + e->xcrossing.detail == NotifyInferior || + e->xcrossing.mode == NotifyUngrab) + { +#ifdef DEBUG_FOCUS + ob_debug("%sNotify mode %d detail %d on %lx IGNORED\n", + (e->type == EnterNotify ? "Enter" : "Leave"), + e->xcrossing.mode, + e->xcrossing.detail, client?client->window:0); #endif - if (config_focus_delay) { - ob_main_loop_timeout_add(ob_main_loop, - config_focus_delay, - focus_delay_func, - client, NULL); - focus_delay_client = client; - } else - client_focus(client); - } + } else { +#ifdef DEBUG_FOCUS + ob_debug("%sNotify mode %d detail %d on %lx, " + "focusing window\n", + (e->type == EnterNotify ? "Enter" : "Leave"), + e->xcrossing.mode, + e->xcrossing.detail, client?client->window:0); +#endif + if (!nofocus && config_focus_follow) + event_enter_client(client); } break; default: break; } break; + } case ConfigureRequest: /* compress these */ while (XCheckTypedWindowEvent(ob_display, client->window, @@ -1170,16 +1255,43 @@ static gboolean menu_hide_delay_func(gpointer data) static gboolean focus_delay_func(gpointer data) { - client_focus(focus_delay_client); + ObClient *c = data; + + client_focus(c); + if (config_focus_raise) + stacking_raise(CLIENT_AS_WINDOW(c)); return FALSE; /* no repeat */ } static void focus_delay_client_dest(gpointer data) { ObClient *c = data; - if (c == focus_delay_client) { - ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, - focus_delay_client); - focus_delay_client = NULL; + + ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, c); +} + +void event_ignore_queued_enters() +{ + GSList *saved = NULL, *it; + XEvent *e; + + XSync(ob_display, FALSE); + + /* count the events */ + while (TRUE) { + e = g_new(XEvent, 1); + if (XCheckTypedEvent(ob_display, EnterNotify, e)) { + saved = g_slist_append(saved, e); + ++ignore_enter_focus; + } else { + g_free(e); + break; + } + } + /* put the events back */ + for (it = saved; it; it = g_slist_next(it)) { + XPutBackEvent(ob_display, it->data); + g_free(it->data); } + g_slist_free(saved); }