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"
#include "group.h"
#include "stacking.h"
#include "extensions.h"
-#include "event.h"
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/ICE/ICElib.h>
#endif
-typedef struct
-{
- gboolean ignored;
-} ObEventData;
-
static void event_process(const XEvent *e, gpointer data);
+static void event_done(gpointer data);
+static void event_client_dest(ObClient *client, 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);
static void event_handle_group(ObGroup *g, XEvent *e);
static gboolean focus_delay_func(gpointer data);
-static void focus_delay_client_dest(gpointer data);
+static void focus_delay_client_dest(ObClient *client, gpointer data);
static gboolean menu_hide_delay_func(gpointer data);
-#define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \
- (e)->xfocus.detail == NotifyAncestor || \
- (e)->xfocus.detail > NotifyNonlinearVirtual)
-#define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \
- (e)->xfocus.detail == NotifyInferior || \
- (e)->xfocus.detail == NotifyAncestor || \
- (e)->xfocus.detail > NotifyNonlinearVirtual)
-
Time event_lasttime = 0;
/*! The value of the mask for the NumLock modifier */
static int mask_table_size;
static guint ignore_enter_focus = 0;
-static ObClient *focus_delay_client;
static gboolean menu_can_hide;
+static ObClient *focus_in, *focus_out;
+
#ifdef USE_SM
static void ice_handler(int fd, gpointer conn)
{
}
}
- ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL);
+ ob_main_loop_x_add(ob_main_loop, event_process, event_done, NULL, NULL);
#ifdef USE_SM
IceAddConnectionWatch(ice_watch, NULL);
#endif
- client_add_destructor(focus_delay_client_dest);
+ client_add_destructor(focus_delay_client_dest, NULL);
+ client_add_destructor(event_client_dest, NULL);
}
void event_shutdown(gboolean reconfig)
static gboolean event_ignore(XEvent *e, ObClient *client)
{
switch(e->type) {
+ case EnterNotify:
+ case LeaveNotify:
+ if (e->xcrossing.detail == NotifyInferior)
+ return TRUE;
+ break;
case FocusIn:
- /* 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 (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;
+ if (e->xfocus.detail > NotifyNonlinearVirtual)
return TRUE;
- }
-
-#ifdef DEBUG_FOCUS
- ob_debug("FocusIn on %lx mode %d detail %d\n", e->xfocus.window,
- e->xfocus.mode, e->xfocus.detail);
-#endif
break;
case FocusOut:
- 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);
-#endif
+ if (e->xfocus.detail > NotifyNonlinearVirtual)
return TRUE;
- }
+ if (e->xfocus.detail == NotifyInferior ||
+ e->xfocus.mode == NotifyGrab)
+ return TRUE;
+ break;
+ }
+ return FALSE;
+}
-#ifdef DEBUG_FOCUS
- ob_debug("FocusOut on %lx mode %d detail %d\n",
- e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
-#endif
+static void event_client_dest(ObClient *client, gpointer data)
+{
+ if (client == focus_in)
+ focus_in = NULL;
+ if (client == focus_out)
+ focus_out = NULL;
+}
- {
- 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
- 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
- /* 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);
- }
+static void event_done(gpointer data)
+{
+ static ObClient *last = NULL;
+
+ if (focus_in) {
+ if (focus_in != focus_client) {
+ focus_set_client(focus_in);
+ frame_adjust_focus(focus_in->frame, TRUE);
+ client_calc_layer(focus_in);
}
- break;
+ }
+ if (focus_out) {
+ if (focus_out == focus_client)
+ focus_set_client(NULL);
+ frame_adjust_focus(focus_out->frame, FALSE);
+ client_calc_layer(focus_out);
}
- return FALSE;
+
+ if (focus_client != last) {
+ if (!focus_client)
+ focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS);
+ last = focus_client;
+ }
+
+ focus_in = focus_out = NULL;
}
static void event_process(const XEvent *ec, gpointer data)
ObDockApp *dockapp = NULL;
ObWindow *obwin = NULL;
XEvent ee, *e;
- ObEventData *ed = data;
/* make a copy we can mangle */
ee = *ec;
event_set_lasttime(e);
event_hack_mods(e);
- if (event_ignore(e, client)) {
- if (ed)
- ed->ignored = TRUE;
+ if (event_ignore(e, client))
return;
- } else if (ed)
- ed->ignored = FALSE;
/* deal with it in the kernel */
if (group)
- event_handle_group(group, e);
+ event_handle_group(group, e);
else if (client)
- event_handle_client(client, e);
+ event_handle_client(client, e);
else if (dockapp)
- event_handle_dockapp(dockapp, e);
+ event_handle_dockapp(dockapp, e);
else if (dock)
- event_handle_dock(dock, e);
+ event_handle_dock(dock, e);
else if (window == RootWindow(ob_display, ob_screen))
- event_handle_root(e);
+ event_handle_root(e);
else if (e->type == MapRequest)
- client_manage(window);
+ client_manage(window);
else if (e->type == ConfigureRequest) {
- /* unhandled configure requests must be used to configure the
- window directly */
- XWindowChanges xwc;
+ /* unhandled configure requests must be used to configure the
+ window directly */
+ XWindowChanges xwc;
xwc.x = e->xconfigurerequest.x;
xwc.y = e->xconfigurerequest.y;
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);
+ ob_debug("added focus timeout\n");
+ } else
+ focus_delay_func(client);
+ }
+}
+
static void event_handle_client(ObClient *client, XEvent *e)
{
XEvent ce;
break;
case FocusIn:
#ifdef DEBUG_FOCUS
- ob_debug("FocusIn on client for %lx\n", client->window);
+ ob_debug("FocusIn on client for %lx (client %lx) mode %d detail %d\n",
+ e->xfocus.window, client->window, e->xfocus.mode, e->xfocus.detail);
#endif
- if (client != focus_client) {
- focus_set_client(client);
- frame_adjust_focus(client->frame, TRUE);
- }
+ focus_in = client;
+ if (focus_out == client)
+ focus_out = NULL;
break;
case FocusOut:
#ifdef DEBUG_FOCUS
- ob_debug("FocusOut on client for %lx\n", client->window);
+ ob_debug("FocusOut on client for %lx (client %lx) mode %d detail %d\n",
+ e->xfocus.window, client->window, e->xfocus.mode, e->xfocus.detail);
#endif
- /* 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;
+ if (focus_in == client)
+ focus_in = NULL;
+ if (client == focus_client)
+ focus_out = client;
+ break;
case LeaveNotify:
con = frame_context(client, e->xcrossing.window);
switch (con) {
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;
}
frame_adjust_state(client->frame);
break;
case OB_FRAME_CONTEXT_FRAME:
- if (!nofocus && client_normal(client) && config_focus_follow) {
- if (e->xcrossing.mode == NotifyGrab ||
- e->xcrossing.detail == NotifyInferior)
- {
+ if (e->xcrossing.mode == NotifyGrab ||
+ 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);
+ 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
- } else {
+ } 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);
+ ob_debug("%sNotify mode %d detail %d on %lx, "
+ "focusing window: %d\n",
+ (e->type == EnterNotify ? "Enter" : "Leave"),
+ e->xcrossing.mode,
+ e->xcrossing.detail, (client?client->window:0),
+ !nofocus);
#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);
- }
+ if (!nofocus && config_focus_follow)
+ event_enter_client(client);
}
break;
default:
switch (e->xconfigurerequest.detail) {
case Below:
case BottomIf:
- stacking_lower(CLIENT_AS_WINDOW(client));
- break;
+ client_lower(client);
+ break;
case Above:
case TopIf:
default:
- stacking_raise(CLIENT_AS_WINDOW(client));
- break;
+ client_raise(client);
+ break;
}
}
break;
ob_debug("MapRequest for 0x%lx\n", client->window);
if (!client->iconic) break; /* this normally doesn't happen, but if it
does, we don't want it! */
- if (screen_showing_desktop)
- screen_show_desktop(FALSE);
- client_iconify(client, FALSE, TRUE);
- if (!client->frame->visible)
- /* if its not visible still, then don't mess with it */
- break;
- if (client->shaded)
- client_shade(client, FALSE);
- client_focus(client);
- stacking_raise(CLIENT_AS_WINDOW(client));
- break;
+ client_activate(client, FALSE);
+ break;
case ClientMessage:
- /* validate cuz we query stuff off the client here */
- if (!client_validate(client)) break;
-
- if (e->xclient.format != 32) return;
+ /* validate cuz we query stuff off the client here */
+ if (!client_validate(client)) break;
- msgtype = e->xclient.message_type;
- if (msgtype == prop_atoms.wm_change_state) {
- /* compress changes into a single change */
- while (XCheckTypedWindowEvent(ob_display, client->window,
- e->type, &ce)) {
- /* XXX: it would be nice to compress ALL messages of a
- type, not just messages in a row without other
- message types between. */
- if (ce.xclient.message_type != msgtype) {
- XPutBackEvent(ob_display, &ce);
- break;
- }
- e->xclient = ce.xclient;
- }
- client_set_wm_state(client, e->xclient.data.l[0]);
- } else if (msgtype == prop_atoms.net_wm_desktop) {
- /* compress changes into a single change */
- while (XCheckTypedWindowEvent(ob_display, client->window,
- e->type, &ce)) {
- /* XXX: it would be nice to compress ALL messages of a
- type, not just messages in a row without other
- message types between. */
- if (ce.xclient.message_type != msgtype) {
- XPutBackEvent(ob_display, &ce);
- break;
- }
- e->xclient = ce.xclient;
- }
+ if (e->xclient.format != 32) return;
+
+ msgtype = e->xclient.message_type;
+ if (msgtype == prop_atoms.wm_change_state) {
+ /* compress changes into a single change */
+ while (XCheckTypedWindowEvent(ob_display, client->window,
+ e->type, &ce)) {
+ /* XXX: it would be nice to compress ALL messages of a
+ type, not just messages in a row without other
+ message types between. */
+ if (ce.xclient.message_type != msgtype) {
+ XPutBackEvent(ob_display, &ce);
+ break;
+ }
+ e->xclient = ce.xclient;
+ }
+ client_set_wm_state(client, e->xclient.data.l[0]);
+ } else if (msgtype == prop_atoms.net_wm_desktop) {
+ /* compress changes into a single change */
+ while (XCheckTypedWindowEvent(ob_display, client->window,
+ e->type, &ce)) {
+ /* XXX: it would be nice to compress ALL messages of a
+ type, not just messages in a row without other
+ message types between. */
+ if (ce.xclient.message_type != msgtype) {
+ XPutBackEvent(ob_display, &ce);
+ break;
+ }
+ e->xclient = ce.xclient;
+ }
if ((unsigned)e->xclient.data.l[0] < screen_num_desktops ||
(unsigned)e->xclient.data.l[0] == DESKTOP_ALL)
client_set_desktop(client, (unsigned)e->xclient.data.l[0],
FALSE);
- } else if (msgtype == prop_atoms.net_wm_state) {
- /* can't compress these */
- ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
+ } else if (msgtype == prop_atoms.net_wm_state) {
+ /* can't compress these */
+ ob_debug("net_wm_state %s %ld %ld for 0x%lx\n",
(e->xclient.data.l[0] == 0 ? "Remove" :
e->xclient.data.l[0] == 1 ? "Add" :
e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"),
e->xclient.data.l[1], e->xclient.data.l[2],
client->window);
- client_set_state(client, e->xclient.data.l[0],
- e->xclient.data.l[1], e->xclient.data.l[2]);
- } else if (msgtype == prop_atoms.net_close_window) {
- ob_debug("net_close_window for 0x%lx\n", client->window);
- client_close(client);
- } else if (msgtype == prop_atoms.net_active_window) {
- ob_debug("net_active_window for 0x%lx\n", client->window);
+ client_set_state(client, e->xclient.data.l[0],
+ e->xclient.data.l[1], e->xclient.data.l[2]);
+ } else if (msgtype == prop_atoms.net_close_window) {
+ ob_debug("net_close_window for 0x%lx\n", client->window);
+ client_close(client);
+ } else if (msgtype == prop_atoms.net_active_window) {
+ ob_debug("net_active_window for 0x%lx\n", client->window);
client_activate(client, FALSE);
- } else if (msgtype == prop_atoms.net_wm_moveresize) {
- ob_debug("net_wm_moveresize for 0x%lx\n", client->window);
+ } else if (msgtype == prop_atoms.net_wm_moveresize) {
+ ob_debug("net_wm_moveresize for 0x%lx\n", client->window);
if ((Atom)e->xclient.data.l[2] ==
prop_atoms.net_wm_moveresize_size_topleft ||
(Atom)e->xclient.data.l[2] ==
client->gravity = oldg;
}
- break;
+ break;
case PropertyNotify:
- /* validate cuz we query stuff off the client here */
- if (!client_validate(client)) break;
+ /* validate cuz we query stuff off the client here */
+ if (!client_validate(client)) break;
- /* compress changes to a single property into a single change */
- while (XCheckTypedWindowEvent(ob_display, client->window,
- e->type, &ce)) {
+ /* compress changes to a single property into a single change */
+ while (XCheckTypedWindowEvent(ob_display, client->window,
+ e->type, &ce)) {
Atom a, b;
/* XXX: it would be nice to compress ALL changes to a property,
- not just changes in a row without other props between. */
+ not just changes in a row without other props between. */
a = ce.xproperty.atom;
b = e->xproperty.atom;
XPutBackEvent(ob_display, &ce);
break;
- }
+ }
- msgtype = e->xproperty.atom;
- if (msgtype == XA_WM_NORMAL_HINTS) {
- client_update_normal_hints(client);
- /* normal hints can make a window non-resizable */
- client_setup_decor_and_functions(client);
- } else if (msgtype == XA_WM_HINTS) {
- client_update_wmhints(client);
- } else if (msgtype == XA_WM_TRANSIENT_FOR) {
- client_update_transient_for(client);
- client_get_type(client);
- /* type may have changed, so update the layer */
- client_calc_layer(client);
- client_setup_decor_and_functions(client);
- } else if (msgtype == prop_atoms.net_wm_name ||
+ msgtype = e->xproperty.atom;
+ if (msgtype == XA_WM_NORMAL_HINTS) {
+ client_update_normal_hints(client);
+ /* normal hints can make a window non-resizable */
+ client_setup_decor_and_functions(client);
+ } else if (msgtype == XA_WM_HINTS) {
+ client_update_wmhints(client);
+ } else if (msgtype == XA_WM_TRANSIENT_FOR) {
+ client_update_transient_for(client);
+ client_get_type(client);
+ /* type may have changed, so update the layer */
+ client_calc_layer(client);
+ client_setup_decor_and_functions(client);
+ } else if (msgtype == prop_atoms.net_wm_name ||
msgtype == prop_atoms.wm_name ||
msgtype == prop_atoms.net_wm_icon_name ||
msgtype == prop_atoms.wm_icon_name) {
- client_update_title(client);
- } else if (msgtype == prop_atoms.wm_class) {
- client_update_class(client);
+ client_update_title(client);
+ } else if (msgtype == prop_atoms.wm_class) {
+ client_update_class(client);
} else if (msgtype == prop_atoms.wm_protocols) {
- client_update_protocols(client);
- client_setup_decor_and_functions(client);
- }
- else if (msgtype == prop_atoms.net_wm_strut) {
- client_update_strut(client);
+ client_update_protocols(client);
+ client_setup_decor_and_functions(client);
}
- else if (msgtype == prop_atoms.net_wm_icon ||
+ else if (msgtype == prop_atoms.net_wm_strut) {
+ client_update_strut(client);
+ }
+ else if (msgtype == prop_atoms.net_wm_icon ||
msgtype == prop_atoms.kwm_win_icon) {
- client_update_icons(client);
+ client_update_icons(client);
}
else if (msgtype == prop_atoms.sm_client_id) {
client_update_sm_client_id(client);
dock_app_drag(app, &e->xmotion);
break;
case UnmapNotify:
- if (app->ignore_unmaps) {
- app->ignore_unmaps--;
- break;
- }
- dock_remove(app, TRUE);
- break;
+ if (app->ignore_unmaps) {
+ app->ignore_unmaps--;
+ break;
+ }
+ dock_remove(app, TRUE);
+ break;
case DestroyNotify:
- dock_remove(app, FALSE);
- break;
+ dock_remove(app, FALSE);
+ break;
case ReparentNotify:
- dock_remove(app, FALSE);
- break;
+ dock_remove(app, FALSE);
+ break;
case ConfigureNotify:
dock_app_configure(app, e->xconfigure.width, e->xconfigure.height);
break;
ObMenuFrame* find_active_menu()
{
GList *it;
- ObMenuFrame *f;
+ ObMenuFrame *ret = NULL;
for (it = menu_frame_visible; it; it = g_list_next(it)) {
- f = it->data;
- if (f->selected)
+ ret = it->data;
+ if (ret->selected)
break;
+ ret = NULL;
}
- return it ? it->data : NULL;
+ return ret;
+}
+
+ObMenuFrame* find_active_or_last_menu()
+{
+ ObMenuFrame *ret = NULL;
+
+ ret = find_active_menu();
+ if (!ret && menu_frame_visible)
+ ret = menu_frame_visible->data;
+ return ret;
}
static void event_handle_menu(XEvent *ev)
switch (ev->type) {
case ButtonRelease:
- if ((e = menu_entry_frame_under(ev->xbutton.x_root,
- ev->xbutton.y_root)))
- menu_entry_frame_execute(e, ev->xbutton.state);
- else if (menu_can_hide)
- menu_frame_hide_all();
+ if (menu_can_hide) {
+ if ((e = menu_entry_frame_under(ev->xbutton.x_root,
+ ev->xbutton.y_root)))
+ menu_entry_frame_execute(e, ev->xbutton.state);
+ else
+ menu_frame_hide_all();
+ }
break;
case MotionNotify:
if ((f = menu_frame_under(ev->xmotion.x_root,
menu_entry_frame_execute(f->selected, ev->xkey.state);
} else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) {
ObMenuFrame *f;
- if ((f = find_active_menu()) && f->parent)
+ if ((f = find_active_or_last_menu()) && f->parent)
menu_frame_select(f, NULL);
} else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) {
ObMenuFrame *f;
- if ((f = find_active_menu()) && f->child)
+ if ((f = find_active_or_last_menu()) && f->child)
menu_frame_select_next(f->child);
} else if (ev->xkey.keycode == ob_keycode(OB_KEY_UP)) {
ObMenuFrame *f;
- if ((f = find_active_menu()))
+ if ((f = find_active_or_last_menu()))
menu_frame_select_previous(f);
} else if (ev->xkey.keycode == ob_keycode(OB_KEY_DOWN)) {
ObMenuFrame *f;
- if ((f = find_active_menu()))
+ if ((f = find_active_or_last_menu()))
menu_frame_select_next(f);
}
break;
static gboolean focus_delay_func(gpointer data)
{
- client_focus(focus_delay_client);
+ ObClient *c = data;
+
+ ob_debug("focus timeout %d\n", focus_client != c);
+ if (focus_client != c) {
+ client_focus(c);
+ if (config_focus_raise)
+ client_raise(c);
+ }
return FALSE; /* no repeat */
}
-static void focus_delay_client_dest(gpointer data)
+static void focus_delay_client_dest(ObClient *client, 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, client);
}
-void event_ignore_enter_focus(guint num)
+void event_ignore_queued_enters()
{
- ignore_enter_focus += num;
+ 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)) {
+ ObWindow *win;
+
+ win = g_hash_table_lookup(window_map, &e->xany.window);
+ if (win && WINDOW_IS_CLIENT(win))
+ ++ignore_enter_focus;
+
+ saved = g_slist_append(saved, e);
+ } 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);
}