}
}
-static gboolean wanted_focusevent(XEvent *e)
+static gboolean wanted_focusevent(XEvent *e, gboolean in_client_only)
{
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. */
/* These are the ones we want.. */
- if (win == RootWindow(ob_display, ob_screen)) {
+ if (win == RootWindow(ob_display, ob_screen) && !in_client_only) {
/* This means focus reverted off of a client */
if (detail == NotifyPointerRoot || detail == NotifyDetailNone ||
detail == NotifyInferior)
if (detail == NotifyNonlinearVirtual)
return TRUE;
/* This means focus moved to the frame window */
- if (detail == NotifyInferior)
+ if (detail == NotifyInferior && !in_client_only)
return TRUE;
/* Otherwise.. */
} else {
g_assert(e->type == FocusOut);
-
/* These are ones we never want.. */
/* This means focus was taken by a keyboard/mouse grab. */
static Bool look_for_focusin(Display *d, XEvent *e, XPointer arg)
{
- return e->type == FocusIn && wanted_focusevent(e);
+ return e->type == FocusIn && wanted_focusevent(e, FALSE);
+}
+
+static Bool look_for_focusin_client(Display *d, XEvent *e, XPointer arg)
+{
+ return e->type == FocusIn && wanted_focusevent(e, TRUE);
+}
+
+static void print_focusevent(XEvent *e)
+{
+ gint mode = e->xfocus.mode;
+ gint detail = e->xfocus.detail;
+ Window win = e->xany.window;
+ const gchar *modestr, *detailstr;
+
+ switch (mode) {
+ case NotifyNormal: modestr="NotifyNormal"; break;
+ case NotifyGrab: modestr="NotifyGrab"; break;
+ case NotifyUngrab: modestr="NotifyUngrab"; break;
+ case NotifyWhileGrabbed: modestr="NotifyWhileGrabbed"; break;
+ }
+ switch (detail) {
+ case NotifyAncestor: detailstr="NotifyAncestor"; break;
+ case NotifyVirtual: detailstr="NotifyVirtual"; break;
+ case NotifyInferior: detailstr="NotifyInferior"; break;
+ case NotifyNonlinear: detailstr="NotifyNonlinear"; break;
+ case NotifyNonlinearVirtual: detailstr="NotifyNonlinearVirtual"; break;
+ case NotifyPointer: detailstr="NotifyPointer"; break;
+ case NotifyPointerRoot: detailstr="NotifyPointerRoot"; break;
+ case NotifyDetailNone: detailstr="NotifyDetailNone"; break;
+ }
+
+ g_assert(modestr);
+ g_assert(detailstr);
+ ob_debug_type(OB_DEBUG_FOCUS, "Focus%s 0x%x mode=%s detail=%s\n",
+ (e->xfocus.type == FocusIn ? "In" : "Out"),
+ win,
+ modestr, detailstr);
+
}
static gboolean event_ignore(XEvent *e, ObClient *client)
{
switch(e->type) {
case FocusIn:
- if (!wanted_focusevent(e))
+ print_focusevent(e);
+ if (!wanted_focusevent(e, FALSE))
return TRUE;
break;
case FocusOut:
- if (!wanted_focusevent(e))
+ print_focusevent(e);
+ if (!wanted_focusevent(e, FALSE))
return TRUE;
break;
}
event_handle_menu(e);
} else if (e->type == FocusIn) {
if (e->xfocus.detail == NotifyPointerRoot ||
- e->xfocus.detail == NotifyDetailNone)
+ e->xfocus.detail == NotifyDetailNone ||
+ e->xfocus.detail == NotifyInferior)
{
- ob_debug_type(OB_DEBUG_FOCUS, "Focus went to pointer root/none\n");
- /* Focus has been reverted to the root window or nothing.
- FocusOut events come after UnmapNotify, so we don't need to
- worry about focusing an invalid window
- */
- if (!focus_left_screen)
- focus_fallback(TRUE);
- } else if (e->xfocus.detail == NotifyInferior) {
+ XEvent ce;
ob_debug_type(OB_DEBUG_FOCUS,
- "Focus went to root or our frame window");
- /* Focus has been given to the root window. */
- focus_fallback(TRUE);
+ "Focus went to pointer root/none or to our frame "
+ "window\n");
+
+ /* If another FocusIn is in the queue then don't fallback yet. This
+ fixes the fun case of:
+ window map -> send focusin
+ window unmap -> get focusout
+ window map -> send focusin
+ get first focus out -> fall back to something (new window
+ hasn't received focus yet, so something else) -> send focusin
+ which means the "something else" is the last thing to get a
+ focusin sent to it, so the new window doesn't end up with focus.
+
+ But if the other focus in is something like PointerRoot then we
+ still want to fall back.
+ */
+ if (XCheckIfEvent(ob_display, &ce, look_for_focusin_client, NULL)){
+ XPutBackEvent(ob_display, &ce);
+ ob_debug_type(OB_DEBUG_FOCUS,
+ " but another FocusIn is coming\n");
+ } else {
+ /* Focus has been reverted to the root window, nothing, or to
+ our frame window.
+
+ FocusOut events come after UnmapNotify, so we don't need to
+ worry about focusing an invalid window
+ */
+
+ /* In this case we know focus is in our screen */
+ if (e->xfocus.detail == NotifyInferior)
+ focus_left_screen = FALSE;
+
+ if (!focus_left_screen)
+ focus_fallback(TRUE);
+ }
} else if (client && client != focus_client) {
focus_left_screen = FALSE;
frame_adjust_focus(client->frame, TRUE);
gboolean nomove = FALSE;
XEvent ce;
- ob_debug_type(OB_DEBUG_FOCUS, "FocusOut Event\n");
-
/* 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
ob_debug_type(OB_DEBUG_APP_BUGS,
"_NET_CURRENT_DESKTOP message is missing "
"a timestamp\n");
- screen_set_desktop(d);
+ screen_set_desktop(d, TRUE);
}
} else if (msgtype == prop_atoms.net_number_of_desktops) {
guint d = e->xclient.data.l[0];
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);
} else if (msgtype == prop_atoms.wm_protocols) {
client_update_protocols(client);
client_setup_decor_and_functions(client);
client_update_sync_request_counter(client);
}
#endif
- else if (msgtype == prop_atoms.sm_client_id) {
- client_update_sm_client_id(client);
- }
case ColormapNotify:
client_update_colormap(client, e->xcolormap.colormap);
break;
ObMenuEntryFrame *e = it->data;
gunichar entrykey = 0;
- if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL &&
- e->entry->data.normal.enabled)
+ if (e->entry->type == OB_MENU_ENTRY_TYPE_NORMAL)
entrykey = e->entry->data.normal.shortcut;
else if (e->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
entrykey = e->entry->data.submenu.submenu->shortcut;
num_found == 1)
{
menu_frame_select(frame, found, TRUE);
- usleep(50000);
+ usleep(50000); /* highlight the item for a short bit so the
+ user can see what happened */
menu_entry_frame_execute(found, state, ev->xkey.time);
} else {
menu_frame_select(frame, found, TRUE);