X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fevent.c;h=5207e093d23df035ceb9eb520ada9781387c60e4;hb=5563e251c36a1fbda703cf4bc3c8c6ae543829bd;hp=7867e9669425bd621ffe105a09e30d3d5ac74867;hpb=29637976e6aecf45bae84ba9ce3ecb26635012f7;p=chaz%2Fopenbox diff --git a/openbox/event.c b/openbox/event.c index 7867e966..5207e093 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -83,8 +83,8 @@ typedef struct static void event_process(const XEvent *e, gpointer data); static void event_handle_root(XEvent *e); -static gboolean event_handle_menu_keyboard(XEvent *e); -static gboolean event_handle_menu(XEvent *e); +static gboolean event_handle_menu_input(XEvent *e); +static void event_handle_menu(ObMenuFrame *frame, XEvent *e); static void event_handle_dock(ObDock *s, XEvent *e); static void event_handle_dockapp(ObDockApp *app, XEvent *e); static void event_handle_client(ObClient *c, XEvent *e); @@ -159,9 +159,15 @@ static Window event_get_window(XEvent *e) /* pick a window */ switch (e->type) { case SelectionClear: - window = RootWindow(obt_display, ob_screen); + window = obt_root(ob_screen); + break; + case CreateNotify: + window = e->xcreatewindow.window; break; case MapRequest: + window = e->xmaprequest.window; + break; + case MapNotify: window = e->xmap.window; break; case UnmapNotify: @@ -269,7 +275,8 @@ static void event_hack_mods(XEvent *e) magic. Our X core protocol stuff won't work, so we use this to find what the modifier state is instead. */ if (XkbGetState(obt_display, XkbUseCoreKbd, &xkb_state) == Success) - e->xkey.state = xkb_state.compat_state; + e->xkey.state = + obt_keyboard_only_modmasks(xkb_state.compat_state); else #endif { @@ -314,7 +321,7 @@ static gboolean wanted_focusevent(XEvent *e, gboolean in_client_only) /* These are the ones we want.. */ - if (win == RootWindow(obt_display, ob_screen)) { + if (win == obt_root(ob_screen)) { /* If looking for a focus in on a client, then always return FALSE for focus in's to the root window */ if (in_client_only) @@ -368,7 +375,7 @@ static gboolean wanted_focusevent(XEvent *e, gboolean in_client_only) return FALSE; /* Focus left the root window revertedto state */ - if (win == RootWindow(obt_display, ob_screen)) + if (win == obt_root(ob_screen)) return FALSE; /* These are the ones we want.. */ @@ -424,7 +431,7 @@ static void print_focusevent(XEvent *e) g_assert(modestr); g_assert(detailstr); - ob_debug_type(OB_DEBUG_FOCUS, "Focus%s 0x%x mode=%s detail=%s\n", + ob_debug_type(OB_DEBUG_FOCUS, "Focus%s 0x%x mode=%s detail=%s", (e->xfocus.type == FocusIn ? "In" : "Out"), win, modestr, detailstr); @@ -450,20 +457,24 @@ static gboolean event_ignore(XEvent *e, ObClient *client) static void event_process(const XEvent *ec, gpointer data) { + XEvent ee, *e; + ObEventData *ed = data; + Window window; ObClient *client = NULL; ObDock *dock = NULL; ObDockApp *dockapp = NULL; ObWindow *obwin = NULL; - XEvent ee, *e; - ObEventData *ed = data; + ObMenuFrame *menu = NULL; /* make a copy we can mangle */ ee = *ec; e = ⅇ window = event_get_window(e); - if ((obwin = window_find(window))) { + if (window == obt_root(ob_screen)) + /* don't do any lookups, waste of cpu */; + else if ((obwin = window_find(window))) { switch (obwin->type) { case OB_WINDOW_CLASS_DOCK: dock = WINDOW_AS_DOCK(obwin); @@ -472,9 +483,9 @@ static void event_process(const XEvent *ec, gpointer data) client = WINDOW_AS_CLIENT(obwin); break; case OB_WINDOW_CLASS_MENUFRAME: - /* XXX use this to handle events more uniformly */ + menu = WINDOW_AS_MENUFRAME(obwin); break; - case OB_WINDOW_CLASS_INTERNALWINDOW: + case OB_WINDOW_CLASS_INTERNAL: /* we don't do anything with events directly on these windows */ break; } @@ -494,12 +505,7 @@ static void event_process(const XEvent *ec, gpointer data) /* deal with it in the kernel */ - if (menu_frame_visible && - (e->type == EnterNotify || e->type == LeaveNotify)) - { - /* crossing events for menu */ - event_handle_menu(e); - } else if (e->type == FocusIn) { + if (e->type == FocusIn) { if (client && e->xfocus.detail == NotifyInferior) { @@ -525,7 +531,7 @@ static void event_process(const XEvent *ec, gpointer data) XEvent ce; ob_debug_type(OB_DEBUG_FOCUS, - "Focus went to root or pointer root/none\n"); + "Focus went to root or pointer root/none"); if (e->xfocus.detail == NotifyInferior || e->xfocus.detail == NotifyNonlinear) @@ -551,7 +557,7 @@ static void event_process(const XEvent *ec, gpointer data) { XPutBackEvent(obt_display, &ce); ob_debug_type(OB_DEBUG_FOCUS, - " but another FocusIn is coming\n"); + " but another FocusIn is coming"); } else { /* Focus has been reverted. @@ -567,7 +573,7 @@ static void event_process(const XEvent *ec, gpointer data) else if (!client) { ob_debug_type(OB_DEBUG_FOCUS, - "Focus went to a window that is already gone\n"); + "Focus went to a window that is already gone"); /* If you send focus to a window and then it disappears, you can get the FocusIn for it, after it is unmanaged. @@ -595,15 +601,15 @@ static void event_process(const XEvent *ec, gpointer data) obt_display_ignore_errors(TRUE); if (XGetInputFocus(obt_display, &win, &i) && XGetGeometry(obt_display, win, &root, &i,&i,&u,&u,&u,&u) && - root != RootWindow(obt_display, ob_screen)) + root != obt_root(ob_screen)) { ob_debug_type(OB_DEBUG_FOCUS, - "Focus went to another screen !\n"); + "Focus went to another screen !"); focus_left_screen = TRUE; } else ob_debug_type(OB_DEBUG_FOCUS, - "Focus went to a black hole !\n"); + "Focus went to a black hole !"); obt_display_ignore_errors(FALSE); /* nothing is focused */ focus_set_client(NULL); @@ -615,7 +621,7 @@ static void event_process(const XEvent *ec, gpointer data) /* The FocusIn was ignored, this means it was on a window that isn't a client. */ ob_debug_type(OB_DEBUG_FOCUS, - "Focus went to an unmanaged window 0x%x !\n", + "Focus went to an unmanaged window 0x%x !", ce.xfocus.window); focus_fallback(TRUE, config_focus_under_mouse, TRUE, TRUE); } @@ -634,14 +640,16 @@ static void event_process(const XEvent *ec, gpointer data) event_handle_dockapp(dockapp, e); else if (dock) event_handle_dock(dock, e); - else if (window == RootWindow(obt_display, ob_screen)) + else if (menu) + event_handle_menu(menu, e); + else if (window == obt_root(ob_screen)) event_handle_root(e); else if (e->type == MapRequest) - client_manage(window); + window_manage(window); else if (e->type == MappingNotify) { /* keyboard layout changes for modifier mapping changes. reload the modifier map, and rebind all the key bindings as appropriate */ - ob_debug("Kepboard map changed. Reloading keyboard bindings.\n"); + ob_debug("Kepboard map changed. Reloading keyboard bindings."); obt_keyboard_reload(); keyboard_rebind(); } @@ -701,7 +709,7 @@ static void event_process(const XEvent *ec, gpointer data) if (e->type == ButtonPress || e->type == ButtonRelease) { /* If the button press was on some non-root window, or was physically on the root window, the process it */ - if (window != RootWindow(obt_display, ob_screen) || + if (window != obt_root(ob_screen) || e->xbutton.subwindow == None) { event_handle_user_input(client, e); @@ -712,7 +720,7 @@ static void event_process(const XEvent *ec, gpointer data) ObWindow *w; if ((w = window_find(e->xbutton.subwindow)) && - WINDOW_IS_INTERNALWINDOW(w)) + WINDOW_IS_INTERNAL(w)) { event_handle_user_input(client, e); } @@ -734,7 +742,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_debug("Another WM has requested to replace us. Exiting."); ob_exit_replace(); break; @@ -749,7 +757,7 @@ static void event_handle_root(XEvent *e) if (event_curtime == 0) ob_debug_type(OB_DEBUG_APP_BUGS, "_NET_CURRENT_DESKTOP message is missing " - "a timestamp\n"); + "a timestamp"); screen_set_desktop(d, TRUE); } } else if (msgtype == OBT_PROP_ATOM(NET_NUMBER_OF_DESKTOPS)) { @@ -759,7 +767,7 @@ static void event_handle_root(XEvent *e) } else if (msgtype == OBT_PROP_ATOM(NET_SHOWING_DESKTOP)) { screen_show_desktop(e->xclient.data.l[0] != 0, NULL); } else if (msgtype == OBT_PROP_ATOM(OB_CONTROL)) { - ob_debug("OB_CONTROL: %d\n", e->xclient.data.l[0]); + ob_debug("OB_CONTROL: %d", e->xclient.data.l[0]); if (e->xclient.data.l[0] == 1) ob_reconfigure(); else if (e->xclient.data.l[0] == 2) @@ -773,7 +781,7 @@ static void event_handle_root(XEvent *e) break; case PropertyNotify: if (e->xproperty.atom == OBT_PROP_ATOM(NET_DESKTOP_NAMES)) { - ob_debug("UPDATE DESKTOP NAMES\n"); + ob_debug("UPDATE DESKTOP NAMES"); screen_update_desktop_names(); } else if (e->xproperty.atom == OBT_PROP_ATOM(NET_DESKTOP_LAYOUT)) @@ -986,7 +994,7 @@ static void event_handle_client(ObClient *client, XEvent *e) event_end_ignore_all_enters(event_start_ignore_all_enters()); ob_debug_type(OB_DEBUG_FOCUS, - "%sNotify mode %d detail %d on %lx\n", + "%sNotify mode %d detail %d on %lx", (e->type == EnterNotify ? "Enter" : "Leave"), e->xcrossing.mode, e->xcrossing.detail, (client?client->window:0)); @@ -1043,7 +1051,7 @@ static void event_handle_client(ObClient *client, XEvent *e) { ob_debug_type(OB_DEBUG_FOCUS, "%sNotify mode %d detail %d serial %lu on %lx " - "IGNORED\n", + "IGNORED", (e->type == EnterNotify ? "Enter" : "Leave"), e->xcrossing.mode, e->xcrossing.detail, @@ -1053,7 +1061,7 @@ static void event_handle_client(ObClient *client, XEvent *e) else { ob_debug_type(OB_DEBUG_FOCUS, "%sNotify mode %d detail %d serial %lu on %lx, " - "focusing window\n", + "focusing window", (e->type == EnterNotify ? "Enter" : "Leave"), e->xcrossing.mode, e->xcrossing.detail, @@ -1084,10 +1092,10 @@ static void event_handle_client(ObClient *client, XEvent *e) RECT_TO_DIMS(client->area, x, y, w, h); ob_debug("ConfigureRequest for \"%s\" desktop %d wmstate %d " - "visibile %d\n" - " x %d y %d w %d h %d b %d\n", + "visibile %d", client->title, - screen_desktop, client->wmstate, client->frame->visible, + screen_desktop, client->wmstate, client->frame->visible); + ob_debug(" x %d y %d w %d h %d b %d", x, y, w, h, client->border_width); if (e->xconfigurerequest.value_mask & CWBorderWidth) @@ -1167,7 +1175,7 @@ static void event_handle_client(ObClient *client, XEvent *e) } ob_debug("ConfigureRequest x(%d) %d y(%d) %d w(%d) %d h(%d) %d " - "move %d resize %d\n", + "move %d resize %d", e->xconfigurerequest.value_mask & CWX, x, e->xconfigurerequest.value_mask & CWY, y, e->xconfigurerequest.value_mask & CWWidth, w, @@ -1193,7 +1201,7 @@ static void event_handle_client(ObClient *client, XEvent *e) ob_debug_type(OB_DEBUG_APP_BUGS, "Application %s is trying to move via " "ConfigureRequest to it's root window position " - "but it is not using StaticGravity\n", + "but it is not using StaticGravity", client->title); /* don't move it */ x = client->area.x; @@ -1221,25 +1229,25 @@ static void event_handle_client(ObClient *client, XEvent *e) client_find_onscreen(client, &x, &y, w, h, FALSE); - ob_debug("Granting ConfigureRequest x %d y %d w %d h %d\n", + ob_debug("Granting ConfigureRequest x %d y %d w %d h %d", x, y, w, h); client_configure(client, x, y, w, h, FALSE, TRUE, TRUE); } break; } case UnmapNotify: + ob_debug("UnmapNotify for window 0x%x eventwin 0x%x sendevent %d " + "ignores left %d", + client->window, e->xunmap.event, e->xunmap.from_configure, + client->ignore_unmaps); if (client->ignore_unmaps) { client->ignore_unmaps--; break; } - ob_debug("UnmapNotify for window 0x%x eventwin 0x%x sendevent %d " - "ignores left %d\n", - client->window, e->xunmap.event, e->xunmap.from_configure, - client->ignore_unmaps); client_unmanage(client); break; case DestroyNotify: - ob_debug("DestroyNotify for window 0x%x\n", client->window); + ob_debug("DestroyNotify for window 0x%x", client->window); client_unmanage(client); break; case ReparentNotify: @@ -1257,11 +1265,11 @@ static void event_handle_client(ObClient *client, XEvent *e) X server to deal with after we unmanage the window */ XPutBackEvent(obt_display, e); - ob_debug("ReparentNotify for window 0x%x\n", client->window); + ob_debug("ReparentNotify for window 0x%x", client->window); client_unmanage(client); break; case MapRequest: - ob_debug("MapRequest for 0x%lx\n", client->window); + ob_debug("MapRequest for 0x%lx", client->window); if (!client->iconic) break; /* this normally doesn't happen, but if it does, we don't want it! it can happen now when the window is on @@ -1311,7 +1319,7 @@ static void event_handle_client(ObClient *client, XEvent *e) gulong ignore_start; /* can't compress these */ - ob_debug("net_wm_state %s %ld %ld for 0x%lx\n", + ob_debug("net_wm_state %s %ld %ld for 0x%lx", (e->xclient.data.l[0] == 0 ? "Remove" : e->xclient.data.l[0] == 1 ? "Add" : e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"), @@ -1326,10 +1334,10 @@ static void event_handle_client(ObClient *client, XEvent *e) if (!config_focus_under_mouse) event_end_ignore_all_enters(ignore_start); } else if (msgtype == OBT_PROP_ATOM(NET_CLOSE_WINDOW)) { - ob_debug("net_close_window for 0x%lx\n", client->window); + ob_debug("net_close_window for 0x%lx", client->window); client_close(client); } else if (msgtype == OBT_PROP_ATOM(NET_ACTIVE_WINDOW)) { - ob_debug("net_active_window for 0x%lx source=%s\n", + ob_debug("net_active_window for 0x%lx source=%s", client->window, (e->xclient.data.l[0] == 0 ? "unknown" : (e->xclient.data.l[0] == 1 ? "application" : @@ -1343,16 +1351,16 @@ static void event_handle_client(ObClient *client, XEvent *e) if (e->xclient.data.l[1] == 0) ob_debug_type(OB_DEBUG_APP_BUGS, "_NET_ACTIVE_WINDOW message for window %s is" - " missing a timestamp\n", client->title); + " missing a timestamp", client->title); } else ob_debug_type(OB_DEBUG_APP_BUGS, "_NET_ACTIVE_WINDOW message for window %s is " - "missing source indication\n"); + "missing source indication"); client_activate(client, FALSE, TRUE, TRUE, (e->xclient.data.l[0] == 0 || e->xclient.data.l[0] == 2)); } else if (msgtype == OBT_PROP_ATOM(NET_WM_MOVERESIZE)) { - ob_debug("net_wm_moveresize for 0x%lx direction %d\n", + ob_debug("net_wm_moveresize for 0x%lx direction %d", client->window, e->xclient.data.l[2]); if ((Atom)e->xclient.data.l[2] == OBT_PROP_ATOM(NET_WM_MOVERESIZE_SIZE_TOPLEFT) || @@ -1425,7 +1433,7 @@ static void event_handle_client(ObClient *client, XEvent *e) else h = client->area.height; - ob_debug("MOVERESIZE x %d %d y %d %d (gravity %d)\n", + ob_debug("MOVERESIZE x %d %d y %d %d (gravity %d)", e->xclient.data.l[0] & 1 << 8, x, e->xclient.data.l[0] & 1 << 9, y, client->gravity); @@ -1439,7 +1447,7 @@ static void event_handle_client(ObClient *client, XEvent *e) if (e->xclient.data.l[0] != 2) { ob_debug_type(OB_DEBUG_APP_BUGS, "_NET_RESTACK_WINDOW sent for window %s with " - "invalid source indication %ld\n", + "invalid source indication %ld", client->title, e->xclient.data.l[0]); } else { ObClient *sibling = NULL; @@ -1453,7 +1461,7 @@ static void event_handle_client(ObClient *client, XEvent *e) if (sibling == NULL) ob_debug_type(OB_DEBUG_APP_BUGS, "_NET_RESTACK_WINDOW sent for window %s " - "with invalid sibling 0x%x\n", + "with invalid sibling 0x%x", client->title, e->xclient.data.l[1]); } if (e->xclient.data.l[2] == Below || @@ -1478,7 +1486,7 @@ static void event_handle_client(ObClient *client, XEvent *e) } else ob_debug_type(OB_DEBUG_APP_BUGS, "_NET_RESTACK_WINDOW sent for window %s " - "with invalid detail %d\n", + "with invalid detail %d", client->title, e->xclient.data.l[2]); } } @@ -1521,7 +1529,7 @@ static void event_handle_client(ObClient *client, XEvent *e) msgtype = e->xproperty.atom; if (msgtype == XA_WM_NORMAL_HINTS) { - ob_debug("Update NORMAL hints\n"); + ob_debug("Update NORMAL hints"); client_update_normal_hints(client); /* normal hints can make a window non-resizable */ client_setup_decor_and_functions(client, FALSE); @@ -1623,13 +1631,13 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e) app->ignore_unmaps--; break; } - dock_remove(app, TRUE); + dock_unmanage(app, TRUE); break; case DestroyNotify: - dock_remove(app, FALSE); + dock_unmanage(app, FALSE); break; case ReparentNotify: - dock_remove(app, FALSE); + dock_unmanage(app, FALSE); break; case ConfigureNotify: dock_app_configure(app, e->xconfigure.width, e->xconfigure.height); @@ -1661,124 +1669,156 @@ static ObMenuFrame* find_active_or_last_menu(void) return ret; } -static gboolean event_handle_menu_keyboard(XEvent *ev) +static gboolean event_handle_menu_input(XEvent *ev) { - guint keycode, state; - gunichar unikey; - ObMenuFrame *frame; gboolean ret = FALSE; - keycode = ev->xkey.keycode; - state = ev->xkey.state; - unikey = obt_keyboard_keycode_to_unichar(keycode); + if (ev->type == ButtonRelease) { + ObMenuEntryFrame *e; - frame = find_active_or_last_menu(); - if (frame == NULL) - g_assert_not_reached(); /* there is no active menu */ + if (menu_hide_delay_reached() && + (ev->xbutton.button < 4 || ev->xbutton.button > 5)) + { + if ((e = menu_entry_frame_under(ev->xbutton.x_root, + ev->xbutton.y_root))) + { + menu_frame_select(e->frame, e, TRUE); + menu_entry_frame_execute(e, ev->xbutton.state); + } + else + menu_frame_hide_all(); + } + ret = TRUE; + } + else if (ev->type == MotionNotify) { + ObMenuFrame *f; + ObMenuEntryFrame *e; - /* Allow control while going thru the menu */ - else if (ev->type == KeyPress && (state & ~ControlMask) == 0) { - frame->got_press = TRUE; + if ((e = menu_entry_frame_under(ev->xmotion.x_root, + ev->xmotion.y_root))) + if (!(f = find_active_menu()) || + f == e->frame || + f->parent == e->frame || + f->child == e->frame) + menu_frame_select(e->frame, e, FALSE); + } + else if (ev->type == KeyPress || ev->type == KeyRelease) { + guint keycode, state; + gunichar unikey; + ObMenuFrame *frame; - if (keycode == ob_keycode(OB_KEY_ESCAPE)) { - menu_frame_hide_all(); - ret = TRUE; - } + keycode = ev->xkey.keycode; + state = ev->xkey.state; + unikey = obt_keyboard_keycode_to_unichar(keycode); - else if (keycode == ob_keycode(OB_KEY_LEFT)) { - /* Left goes to the parent menu */ - menu_frame_select(frame, NULL, TRUE); - ret = TRUE; - } + frame = find_active_or_last_menu(); + if (frame == NULL) + g_assert_not_reached(); /* there is no active menu */ - else if (keycode == ob_keycode(OB_KEY_RIGHT)) { - /* Right goes to the selected submenu */ - if (frame->child) menu_frame_select_next(frame->child); - ret = TRUE; - } + /* Allow control while going thru the menu */ + else if (ev->type == KeyPress && (state & ~ControlMask) == 0) { + frame->got_press = TRUE; - else if (keycode == ob_keycode(OB_KEY_UP)) { - menu_frame_select_previous(frame); - ret = TRUE; - } + if (keycode == ob_keycode(OB_KEY_ESCAPE)) { + menu_frame_hide_all(); + ret = TRUE; + } - else if (keycode == ob_keycode(OB_KEY_DOWN)) { - menu_frame_select_next(frame); - ret = TRUE; - } - } + else if (keycode == ob_keycode(OB_KEY_LEFT)) { + /* Left goes to the parent menu */ + menu_frame_select(frame, NULL, TRUE); + ret = TRUE; + } - /* Use KeyRelease events for running things so that the key release doesn't - get sent to the focused application. + else if (keycode == ob_keycode(OB_KEY_RIGHT)) { + /* Right goes to the selected submenu */ + if (frame->child) menu_frame_select_next(frame->child); + ret = TRUE; + } - Allow ControlMask only, and don't bother if the menu is empty */ - else if (ev->type == KeyRelease && (state & ~ControlMask) == 0 && - frame->entries && frame->got_press) - { - if (keycode == ob_keycode(OB_KEY_RETURN)) { - /* Enter runs the active item or goes into the submenu. - Control-Enter runs it without closing the menu. */ - if (frame->child) - menu_frame_select_next(frame->child); - else if (frame->selected) - menu_entry_frame_execute(frame->selected, state); - - ret = TRUE; - } + else if (keycode == ob_keycode(OB_KEY_UP)) { + menu_frame_select_previous(frame); + ret = TRUE; + } - /* keyboard accelerator shortcuts. (if it was a valid key) */ - else if (unikey != 0) { - GList *start; - GList *it; - ObMenuEntryFrame *found = NULL; - guint num_found = 0; - - /* start after the selected one */ - start = frame->entries; - if (frame->selected) { - for (it = start; frame->selected != it->data; - it = g_list_next(it)) - g_assert(it != NULL); /* nothing was selected? */ - /* next with wraparound */ - start = g_list_next(it); - if (start == NULL) start = frame->entries; + else if (keycode == ob_keycode(OB_KEY_DOWN)) { + menu_frame_select_next(frame); + ret = TRUE; } + } - it = start; - do { - ObMenuEntryFrame *e = it->data; - gunichar entrykey = 0; + /* Use KeyRelease events for running things so that the key release + doesn't get sent to the focused application. - 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; + Allow ControlMask only, and don't bother if the menu is empty */ + else if (ev->type == KeyRelease && (state & ~ControlMask) == 0 && + frame->entries && frame->got_press) + { + if (keycode == ob_keycode(OB_KEY_RETURN)) { + /* Enter runs the active item or goes into the submenu. + Control-Enter runs it without closing the menu. */ + if (frame->child) + menu_frame_select_next(frame->child); + else if (frame->selected) + menu_entry_frame_execute(frame->selected, state); - if (unikey == entrykey) { - if (found == NULL) found = e; - ++num_found; + ret = TRUE; + } + + /* keyboard accelerator shortcuts. (if it was a valid key) */ + else if (unikey != 0) { + GList *start; + GList *it; + ObMenuEntryFrame *found = NULL; + guint num_found = 0; + + /* start after the selected one */ + start = frame->entries; + if (frame->selected) { + for (it = start; frame->selected != it->data; + it = g_list_next(it)) + g_assert(it != NULL); /* nothing was selected? */ + /* next with wraparound */ + start = g_list_next(it); + if (start == NULL) start = frame->entries; } - /* next with wraparound */ - it = g_list_next(it); - if (it == NULL) it = frame->entries; - } while (it != start); + it = start; + do { + ObMenuEntryFrame *e = it->data; + gunichar entrykey = 0; - if (found) { - if (found->entry->type == OB_MENU_ENTRY_TYPE_NORMAL && - num_found == 1) - { - menu_frame_select(frame, found, TRUE); - usleep(50000); /* highlight the item for a short bit so the - user can see what happened */ - menu_entry_frame_execute(found, state); - } else { - menu_frame_select(frame, found, TRUE); - if (num_found == 1) - menu_frame_select_next(frame->child); - } + 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; - ret = TRUE; + if (unikey == entrykey) { + if (found == NULL) found = e; + ++num_found; + } + + /* next with wraparound */ + it = g_list_next(it); + if (it == NULL) it = frame->entries; + } while (it != start); + + if (found) { + if (found->entry->type == OB_MENU_ENTRY_TYPE_NORMAL && + num_found == 1) + { + menu_frame_select(frame, found, TRUE); + usleep(50000); /* highlight the item for a short bit so + the user can see what happened */ + menu_entry_frame_execute(found, state); + } else { + menu_frame_select(frame, found, TRUE); + if (num_found == 1) + menu_frame_select_next(frame->child); + } + + ret = TRUE; + } } } } @@ -1786,27 +1826,12 @@ static gboolean event_handle_menu_keyboard(XEvent *ev) return ret; } -static gboolean event_handle_menu(XEvent *ev) +static void event_handle_menu(ObMenuFrame *frame, XEvent *ev) { ObMenuFrame *f; ObMenuEntryFrame *e; - gboolean ret = TRUE; switch (ev->type) { - case ButtonRelease: - if (menu_hide_delay_reached() && - (ev->xbutton.button < 4 || ev->xbutton.button > 5)) - { - if ((e = menu_entry_frame_under(ev->xbutton.x_root, - ev->xbutton.y_root))) - { - menu_frame_select(e->frame, e, TRUE); - menu_entry_frame_execute(e, ev->xbutton.state); - } - else - menu_frame_hide_all(); - } - break; case EnterNotify: if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window))) { if (e->ignore_enters) @@ -1830,21 +1855,7 @@ static gboolean event_handle_menu(XEvent *ev) menu_frame_select(e->frame, NULL, FALSE); } break; - case MotionNotify: - if ((e = menu_entry_frame_under(ev->xmotion.x_root, - ev->xmotion.y_root))) - if (!(f = find_active_menu()) || - f == e->frame || - f->parent == e->frame || - f->child == e->frame) - menu_frame_select(e->frame, e, FALSE); - break; - case KeyPress: - case KeyRelease: - ret = event_handle_menu_keyboard(ev); - break; } - return ret; } static void event_handle_user_input(ObClient *client, XEvent *e) @@ -1854,7 +1865,7 @@ static void event_handle_user_input(ObClient *client, XEvent *e) e->type == KeyRelease); if (menu_frame_visible) { - if (event_handle_menu(e)) + if (event_handle_menu_input(e)) /* don't use the event if the menu used it, but if the menu didn't use it and it's a keypress that is bound, it will close the menu and be used */ @@ -1925,8 +1936,7 @@ void event_halt_focus_delay(void) gulong event_start_ignore_all_enters(void) { - XSync(obt_display, FALSE); - return LastKnownRequestProcessed(obt_display); + return NextRequest(obt_display); } static void event_ignore_enter_range(gulong start, gulong end) @@ -1941,17 +1951,22 @@ static void event_ignore_enter_range(gulong start, gulong end) r->end = end; ignore_serials = g_slist_prepend(ignore_serials, r); - ob_debug_type(OB_DEBUG_FOCUS, "ignoring enters from %lu until %lu\n", + ob_debug_type(OB_DEBUG_FOCUS, "ignoring enters from %lu until %lu", r->start, r->end); /* increment the serial so we don't ignore events we weren't meant to */ - XSync(obt_display, FALSE); + OBT_PROP_ERASE(screen_support_win, MOTIF_WM_HINTS); } void event_end_ignore_all_enters(gulong start) { - XSync(obt_display, FALSE); - event_ignore_enter_range(start, LastKnownRequestProcessed(obt_display)); + /* Use (NextRequest-1) so that we ignore up to the current serial only. + Inside event_ignore_enter_range, we increment the serial by one, but if + we ignore that serial too, then any enter events generated by mouse + movement will be ignored until we create some further network traffic. + Instead ignore up to NextRequest-1, then when we increment the serial, + we will be *past* the range of ignored serials */ + event_ignore_enter_range(start, NextRequest(obt_display)-1); } static gboolean is_enter_focus_event_ignored(XEvent *e) @@ -1983,19 +1998,19 @@ void event_cancel_all_key_grabs(void) { if (actions_interactive_act_running()) { actions_interactive_cancel_act(); - ob_debug("KILLED interactive action\n"); + ob_debug("KILLED interactive action"); } else if (menu_frame_visible) { menu_frame_hide_all(); - ob_debug("KILLED open menus\n"); + ob_debug("KILLED open menus"); } else if (moveresize_in_progress) { moveresize_end(TRUE); - ob_debug("KILLED interactive moveresize\n"); + ob_debug("KILLED interactive moveresize"); } else if (grab_on_keyboard()) { ungrab_keyboard(); - ob_debug("KILLED active grab on keyboard\n"); + ob_debug("KILLED active grab on keyboard"); } else ungrab_passive_key();