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)
-
-/* The most recent time at which an event with a timestamp occured. */
-static Time event_lasttime = 0;
-/* The time for the current event being processed
- (it's the event_lasttime for events without times, if this is a bug then
- use CurrentTime instead, but it seems ok) */
+/* The time for the current event being processed */
Time event_curtime = CurrentTime;
/*! The value of the mask for the NumLock modifier */
return window;
}
-static void event_set_lasttime(XEvent *e)
+static void event_set_curtime(XEvent *e)
{
- Time t = 0;
+ Time t = CurrentTime;
/* grab the lasttime and hack up the state */
switch (e->type) {
break;
}
- if (t > event_lasttime) {
- event_lasttime = t;
- event_curtime = event_lasttime;
- } else if (t == 0) {
- event_curtime = event_lasttime;
- } else {
- event_curtime = t;
- }
+ event_curtime = t;
}
#define STRIP_MODS(s) \
}
}
+static gboolean wanted_focusevent(XEvent *e)
+{
+ gint mode = e->xfocus.mode;
+ gint detail = e->xfocus.detail;
+ Window win = e->xany.window;
+
+ if (e->type == FocusIn) {
+
+ /* These are ones we never want.. */
+
+ /* This means focus was given by a keyboard/mouse grab. */
+ if (mode == NotifyGrab)
+ return FALSE;
+ /* This means focus was given back from a keyboard/mouse grab. */
+ if (mode == NotifyUngrab)
+ return FALSE;
+
+ /* These are the ones we want.. */
+
+ if (win == RootWindow(ob_display, ob_screen)) {
+ /* This means focus reverted off of a client */
+ if (detail == NotifyPointerRoot || detail == NotifyDetailNone)
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ /* This means focus moved from the root window to a client */
+ if (detail == NotifyVirtual)
+ return TRUE;
+ /* This means focus moved from one client to another */
+ if (detail == NotifyNonlinearVirtual)
+ return TRUE;
+
+ /* This means focus reverted off of a client */
+ if (detail == NotifyInferior)
+ return TRUE;
+
+ /* Otherwise.. */
+ return FALSE;
+ } else {
+ g_assert(e->type == FocusOut);
+
+
+ /* These are ones we never want.. */
+
+ /* This means focus was taken by a keyboard/mouse grab. */
+ if (mode == NotifyGrab)
+ return FALSE;
+
+ /* Focus left the root window revertedto state */
+ if (win == RootWindow(ob_display, ob_screen))
+ return FALSE;
+
+ /* These are the ones we want.. */
+
+ /* This means focus moved from a client to the root window */
+ if (detail == NotifyVirtual)
+ return TRUE;
+ /* This means focus moved from one client to another */
+ if (detail == NotifyNonlinearVirtual)
+ return TRUE;
+
+ /* Otherwise.. */
+ return FALSE;
+ }
+}
+
+static Bool look_for_focusin(Display *d, XEvent *e, XPointer arg)
+{
+ return e->type == FocusIn && wanted_focusevent(e);
+}
+
static gboolean event_ignore(XEvent *e, ObClient *client)
{
switch(e->type) {
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;
- 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
+ /* I don't think this should ever happen with our event masks, but
+ if it does, we don't want it. */
+ if (client == NULL)
+ return TRUE;
+ if (!wanted_focusevent(e))
return TRUE;
- }
-
-#ifdef DEBUG_FOCUS
- ob_debug("FocusOut on %lx mode %d detail %d\n",
- e->xfocus.window, e->xfocus.mode, e->xfocus.detail);
-#endif
- {
- 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);
- }
- }
break;
}
return FALSE;
}
}
- event_set_lasttime(e);
+#if 1 /* focus debugging stuff */
+ if (e->type == FocusIn || e->type == FocusOut) {
+ gint mode = e->xfocus.mode;
+ gint detail = e->xfocus.detail;
+ Window window = e->xfocus.window;
+ if (detail == NotifyVirtual) {
+ ob_debug("FOCUS %s NOTIFY VIRTUAL window 0x%x\n",
+ (e->type == FocusIn ? "IN" : "OUT"), window);
+ }
+
+ else if (detail == NotifyNonlinearVirtual) {
+ ob_debug("FOCUS %s NOTIFY NONLINVIRTUAL window 0x%x\n",
+ (e->type == FocusIn ? "IN" : "OUT"), window);
+ }
+
+ else
+ ob_debug("UNKNOWN FOCUS %s (d %d, m %d) window 0x%x\n",
+ (e->type == FocusIn ? "IN" : "OUT"),
+ detail, mode, window);
+ }
+#endif
+
+ event_set_curtime(e);
event_hack_mods(e);
if (event_ignore(e, client)) {
if (ed)
if (e->type == ButtonPress || e->type == ButtonRelease ||
e->type == MotionNotify)
mouse_event(client, e);
- else if (e->type == KeyPress)
+ else if (e->type == KeyPress) {
keyboard_event((focus_cycle_target ? focus_cycle_target :
(focus_hilite ? focus_hilite : client)),
e);
+ }
}
}
}
+ /* if something happens and it's not from an XEvent, then we don't know
+ the time */
+ event_curtime = CurrentTime;
}
static void event_handle_root(XEvent *e)
msgtype = e->xclient.message_type;
if (msgtype == prop_atoms.net_current_desktop) {
guint d = e->xclient.data.l[0];
+ event_curtime = e->xclient.data.l[1];
if (d < screen_num_desktops)
screen_set_desktop(d);
} else if (msgtype == prop_atoms.net_number_of_desktops) {
}
break;
case FocusIn:
-#ifdef DEBUG_FOCUS
- 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);
}
break;
case FocusOut:
-#ifdef DEBUG_FOCUS
- 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
+ /* Look for the followup FocusIn */
+ if (!XCheckIfEvent(ob_display, &ce, look_for_focusin, NULL)) {
+ /* There is no FocusIn, this means focus went to a window that
+ is not being managed, or a window on another screen. */
+ ob_debug("Focus went to a black hole !\n");
+ } else if (ce.xany.window == e->xany.window) {
+ /* If focus didn't actually move anywhere, there is nothing to do*/
+ break;
+ } else if (ce.xfocus.detail == NotifyPointerRoot ||
+ ce.xfocus.detail == NotifyDetailNone) {
+ ob_debug("Focus went to root\n");
+ /* Focus has been reverted to the root window or nothing, so fall
+ back to something other than the window which just had it. */
+ focus_fallback(FALSE);
+ } else if (ce.xfocus.detail == NotifyInferior) {
+ ob_debug("Focus went to parent\n");
+ /* Focus has been reverted to parent, which is our frame window,
+ so fall back to something other than the window which had it. */
+ focus_fallback(FALSE);
+ } else {
+ /* Focus did move, so process the FocusIn event */
+ ObEventData ed = { .ignored = FALSE };
+ event_process(&ce, &ed);
+ if (ed.ignored) {
+ /* The FocusIn was ignored, this means it was on a window
+ that isn't a client. */
+ ob_debug("Focus went to an unmanaged window 0x%x !\n",
+ ce.xfocus.window);
+ focus_fallback(TRUE);
+ }
+ }
+
+ /* This client is no longer focused, so show that */
focus_hilite = NULL;
frame_adjust_focus(client->frame, FALSE);
client_calc_layer(client);
}
break;
case UnmapNotify:
+ ob_debug("UnmapNotify for window 0x%x\n", client->window);
if (client->ignore_unmaps) {
client->ignore_unmaps--;
break;
client_unmanage(client);
break;
case DestroyNotify:
+ ob_debug("DestroyNotify for window 0x%x\n", client->window);
client_unmanage(client);
break;
case ReparentNotify:
it can happen now when the window is on
another desktop, but we still don't
want it! */
- client_activate(client, FALSE, TRUE, CurrentTime);
+ client_activate(client, FALSE, TRUE);
break;
case ClientMessage:
/* validate cuz we query stuff off the client here */
(e->xclient.data.l[0] == 0 ? "unknown" :
(e->xclient.data.l[0] == 1 ? "application" :
(e->xclient.data.l[0] == 2 ? "user" : "INVALID"))));
- /* XXX make use of data.l[1] and [2] ! */
+ /* XXX make use of data.l[2] ! */
+ event_curtime = e->xclient.data.l[1];
client_activate(client, FALSE,
(e->xclient.data.l[0] == 0 ||
- e->xclient.data.l[0] == 2),
- e->xclient.data.l[1]);
+ e->xclient.data.l[0] == 2));
} else if (msgtype == prop_atoms.net_wm_moveresize) {
ob_debug("net_wm_moveresize for 0x%lx direction %d\n",
client->window, e->xclient.data.l[2]);
switch (e->type) {
case ButtonPress:
if (e->xbutton.button == 1)
- stacking_raise(DOCK_AS_WINDOW(s), FALSE);
+ stacking_raise(DOCK_AS_WINDOW(s));
else if (e->xbutton.button == 2)
- stacking_lower(DOCK_AS_WINDOW(s), FALSE);
+ stacking_lower(DOCK_AS_WINDOW(s));
break;
case EnterNotify:
dock_hide(FALSE);
ObClient *c = data;
if (focus_client != c) {
- client_focus(c);
- if (config_focus_raise)
- client_raise(c);
+ if (client_validate(c)) {
+ client_focus(c);
+ if (config_focus_raise)
+ client_raise(c);
+ }
}
return FALSE; /* no repeat */
}