X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fevent.c;h=1b3c1c23e66e86f054ddda8d7f8c0d4cc269ffec;hb=619fd7e666944aa83c636d14cd2777cbd5dc1094;hp=522305a821765728cbd8816c59f33032d4fc6898;hpb=1ed9988132cb57a94508e20bd50b98b673d576a3;p=chaz%2Fopenbox diff --git a/openbox/event.c b/openbox/event.c index 522305a8..1b3c1c23 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -43,6 +43,7 @@ #include "stacking.h" #include "extensions.h" #include "translate.h" +#include "ping.h" #include #include @@ -74,6 +75,7 @@ typedef struct { ObClient *client; Time time; + gulong serial; } ObFocusDelayData; typedef struct @@ -90,7 +92,8 @@ 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); static void event_handle_user_input(ObClient *client, XEvent *e); -static gboolean is_enter_focus_event_ignored(XEvent *e); +static gboolean is_enter_focus_event_ignored(gulong serial); +static void event_ignore_enter_range(gulong start, gulong end); static void focus_delay_dest(gpointer data); static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2); @@ -99,7 +102,9 @@ static void focus_delay_client_dest(ObClient *client, gpointer data); Time event_curtime = CurrentTime; Time event_last_user_time = CurrentTime; +/*! The serial of the current X event */ +static gulong event_curserial; static gboolean focus_left_screen = FALSE; /*! A list of ObSerialRanges which are to be ignored for mouse enter events */ static GSList *ignore_serials = NULL; @@ -247,6 +252,10 @@ static void event_set_curtime(XEvent *e) static void event_hack_mods(XEvent *e) { +#ifdef XKB + XkbStateRec xkb_state; +#endif + switch (e->type) { case ButtonPress: case ButtonRelease: @@ -256,10 +265,21 @@ static void event_hack_mods(XEvent *e) e->xkey.state = modkeys_only_modifier_masks(e->xkey.state); break; case KeyRelease: - e->xkey.state = modkeys_only_modifier_masks(e->xkey.state); - /* remove from the state the mask of the modifier key being released, - if it is a modifier key being released that is */ - e->xkey.state &= ~modkeys_keycode_to_mask(e->xkey.keycode); +#ifdef XKB + /* If XKB is present, then the modifiers are all strange from its + magic. Our X core protocol stuff won't work, so we use this to + find what the modifier state is instead. */ + if (XkbGetState(ob_display, XkbUseCoreKbd, &xkb_state) == Success) + e->xkey.state = + modkeys_only_modifier_masks(xkb_state.compat_state); + else +#endif + { + e->xkey.state = modkeys_only_modifier_masks(e->xkey.state); + /* remove from the state the mask of the modifier key being + released, if it is a modifier key being released that is */ + e->xkey.state &= ~modkeys_keycode_to_mask(e->xkey.keycode); + } break; case MotionNotify: e->xmotion.state = modkeys_only_modifier_masks(e->xmotion.state); @@ -457,14 +477,17 @@ static void event_process(const XEvent *ec, gpointer data) client = WINDOW_AS_CLIENT(obwin); break; case Window_Menu: - case Window_Internal: /* not to be used for events */ g_assert_not_reached(); break; + case Window_Internal: + /* we don't do anything with events directly on these windows */ + break; } } event_set_curtime(e); + event_curserial = e->xany.serial; event_hack_mods(e); if (event_ignore(e, client)) { if (ed) @@ -489,19 +512,18 @@ static void event_process(const XEvent *ec, gpointer data) focus_left_screen = FALSE; - focus_fallback(FALSE, config_focus_under_mouse, TRUE); + focus_fallback(FALSE, config_focus_under_mouse, TRUE, TRUE); /* We don't get a FocusOut for this case, because it's just moving from our Inferior up to us. This happens when iconifying a window with RevertToParent focus */ frame_adjust_focus(client->frame, FALSE); /* focus_set_client(NULL) has already been called */ - client_calc_layer(client); } - if (e->xfocus.detail == NotifyPointerRoot || - e->xfocus.detail == NotifyDetailNone || - e->xfocus.detail == NotifyInferior || - e->xfocus.detail == NotifyNonlinear) + else if (e->xfocus.detail == NotifyPointerRoot || + e->xfocus.detail == NotifyDetailNone || + e->xfocus.detail == NotifyInferior || + e->xfocus.detail == NotifyNonlinear) { XEvent ce; @@ -541,7 +563,8 @@ static void event_process(const XEvent *ec, gpointer data) */ if (!focus_left_screen) - focus_fallback(FALSE, config_focus_under_mouse, TRUE); + focus_fallback(FALSE, config_focus_under_mouse, + TRUE, TRUE); } } else if (!client) @@ -597,7 +620,7 @@ static void event_process(const XEvent *ec, gpointer data) ob_debug_type(OB_DEBUG_FOCUS, "Focus went to an unmanaged window 0x%x !\n", ce.xfocus.window); - focus_fallback(TRUE, config_focus_under_mouse, TRUE); + focus_fallback(TRUE, config_focus_under_mouse, TRUE, TRUE); } } @@ -605,7 +628,6 @@ static void event_process(const XEvent *ec, gpointer data) frame_adjust_focus(client->frame, FALSE); /* focus_set_client(NULL) has already been called in this section or by focus_fallback */ - client_calc_layer(client); } } else if (client) @@ -618,6 +640,14 @@ static void event_process(const XEvent *ec, gpointer data) event_handle_root(e); else if (e->type == MapRequest) client_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"); + modkeys_shutdown(TRUE); + modkeys_startup(TRUE); + keyboard_rebind(); + } else if (e->type == ClientMessage) { /* This is for _NET_WM_REQUEST_FRAME_EXTENTS messages. They come for windows that are not managed yet. */ @@ -669,16 +699,34 @@ static void event_process(const XEvent *ec, gpointer data) } #endif - if (e->type == ButtonPress || e->type == ButtonRelease || - e->type == MotionNotify || e->type == KeyPress || - e->type == KeyRelease) - { - event_handle_user_input(client, e); + if (e->type == ButtonPress || e->type == ButtonRelease) { + /* If the button press was on some non-root window, or was physically + on the root window, then process it */ + if (window != RootWindow(ob_display, ob_screen) || + e->xbutton.subwindow == None) + { + event_handle_user_input(client, e); + } + /* Otherwise only process it if it was physically on an openbox + internal window */ + else { + ObWindow *w; + + if ((w = g_hash_table_lookup(window_map, &e->xbutton.subwindow)) && + WINDOW_IS_INTERNAL(w)) + { + event_handle_user_input(client, e); + } + } } + else if (e->type == KeyPress || e->type == KeyRelease || + e->type == MotionNotify) + event_handle_user_input(client, e); /* if something happens and it's not from an XEvent, then we don't know the time */ event_curtime = CurrentTime; + event_curserial = 0; } static void event_handle_root(XEvent *e) @@ -717,6 +765,11 @@ static void event_handle_root(XEvent *e) ob_reconfigure(); else if (e->xclient.data.l[0] == 2) ob_restart(); + else if (e->xclient.data.l[0] == 3) + ob_exit(0); + } else if (msgtype == prop_atoms.wm_protocols) { + if ((Atom)e->xclient.data.l[0] == prop_atoms.net_wm_ping) + ping_got_pong(e->xclient.data.l[1]); } break; case PropertyNotify: @@ -742,6 +795,12 @@ void event_enter_client(ObClient *client) { g_assert(config_focus_follow); + if (is_enter_focus_event_ignored(event_curserial)) { + ob_debug_type(OB_DEBUG_FOCUS, "Ignoring enter event with serial %lu\n" + "on client 0x%x", event_curserial, client->window); + return; + } + if (client_enter_focusable(client) && client_can_focus(client)) { if (config_focus_delay) { ObFocusDelayData *data; @@ -751,15 +810,17 @@ void event_enter_client(ObClient *client) data = g_new(ObFocusDelayData, 1); data->client = client; data->time = event_curtime; + data->serial = event_curserial; ob_main_loop_timeout_add(ob_main_loop, - config_focus_delay, + config_focus_delay * 1000, focus_delay_func, data, focus_delay_cmp, focus_delay_dest); } else { ObFocusDelayData data; data.client = client; data.time = event_curtime; + data.serial = event_curserial; focus_delay_func(&data); } } @@ -984,22 +1045,26 @@ static void event_handle_client(ObClient *client, XEvent *e) if (e->xcrossing.mode == NotifyGrab || e->xcrossing.mode == NotifyUngrab || /*ignore enters when we're already in the window */ - e->xcrossing.detail == NotifyInferior || - is_enter_focus_event_ignored(e)) + e->xcrossing.detail == NotifyInferior) { ob_debug_type(OB_DEBUG_FOCUS, - "%sNotify mode %d detail %d on %lx IGNORED\n", + "%sNotify mode %d detail %d serial %lu on %lx " + "IGNORED\n", (e->type == EnterNotify ? "Enter" : "Leave"), e->xcrossing.mode, - e->xcrossing.detail, client?client->window:0); + e->xcrossing.detail, + e->xcrossing.serial, + client?client->window:0); } else { ob_debug_type(OB_DEBUG_FOCUS, - "%sNotify mode %d detail %d on %lx, " + "%sNotify mode %d detail %d serial %lu on %lx, " "focusing window\n", (e->type == EnterNotify ? "Enter" : "Leave"), e->xcrossing.mode, - e->xcrossing.detail, (client?client->window:0)); + e->xcrossing.detail, + e->xcrossing.serial, + (client?client->window:0)); if (config_focus_follow) event_enter_client(client); } @@ -1290,7 +1355,7 @@ static void event_handle_client(ObClient *client, XEvent *e) ob_debug_type(OB_DEBUG_APP_BUGS, "_NET_ACTIVE_WINDOW message for window %s is " "missing source indication\n"); - client_activate(client, FALSE, TRUE, TRUE, + client_activate(client, TRUE, TRUE, TRUE, (e->xclient.data.l[0] == 0 || e->xclient.data.l[0] == 2)); } else if (msgtype == prop_atoms.net_wm_moveresize) { @@ -1504,7 +1569,8 @@ static void event_handle_client(ObClient *client, XEvent *e) } else if (msgtype == prop_atoms.net_wm_user_time) { guint32 t; - if (PROP_GET32(client->window, net_wm_user_time, cardinal, &t) && + if (client == focus_client && + PROP_GET32(client->window, net_wm_user_time, cardinal, &t) && t && !event_time_after(t, e->xproperty.time) && (!event_last_user_time || event_time_after(t, event_last_user_time))) @@ -1577,7 +1643,7 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e) } } -static ObMenuFrame* find_active_menu() +static ObMenuFrame* find_active_menu(void) { GList *it; ObMenuFrame *ret = NULL; @@ -1591,7 +1657,7 @@ static ObMenuFrame* find_active_menu() return ret; } -static ObMenuFrame* find_active_or_last_menu() +static ObMenuFrame* find_active_or_last_menu(void) { ObMenuFrame *ret = NULL; @@ -1618,6 +1684,8 @@ static gboolean event_handle_menu_keyboard(XEvent *ev) /* Allow control while going thru the menu */ else if (ev->type == KeyPress && (state & ~ControlMask) == 0) { + frame->got_press = TRUE; + if (keycode == ob_keycode(OB_KEY_ESCAPE)) { menu_frame_hide_all(); ret = TRUE; @@ -1651,7 +1719,7 @@ static gboolean event_handle_menu_keyboard(XEvent *ev) Allow ControlMask only, and don't bother if the menu is empty */ else if (ev->type == KeyRelease && (state & ~ControlMask) == 0 && - frame->entries) + frame->entries && frame->got_press) { if (keycode == ob_keycode(OB_KEY_RETURN)) { /* Enter runs the active item or goes into the submenu. @@ -1841,10 +1909,9 @@ static gboolean focus_delay_func(gpointer data) if (menu_frame_visible || moveresize_in_progress) return FALSE; event_curtime = d->time; - if (focus_client != d->client) { - if (client_focus(d->client) && config_focus_raise) - stacking_raise(CLIENT_AS_WINDOW(d->client)); - } + event_curserial = d->serial; + if (client_focus(d->client) && config_focus_raise) + stacking_raise(CLIENT_AS_WINDOW(d->client)); event_curtime = old; return FALSE; /* no repeat */ } @@ -1855,59 +1922,69 @@ static void focus_delay_client_dest(ObClient *client, gpointer data) client, FALSE); } -void event_halt_focus_delay() +void event_halt_focus_delay(void) { + /* ignore all enter events up till the event which caused this to occur */ + if (event_curserial) event_ignore_enter_range(1, event_curserial); ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func); } -gulong event_start_ignore_all_enters() +gulong event_start_ignore_all_enters(void) { - XSync(ob_display, FALSE); - return LastKnownRequestProcessed(ob_display); + return NextRequest(ob_display); } -void event_end_ignore_all_enters(gulong start) +static void event_ignore_enter_range(gulong start, gulong end) { ObSerialRange *r; g_assert(start != 0); - XSync(ob_display, FALSE); + g_assert(end != 0); r = g_new(ObSerialRange, 1); r->start = start; - r->end = LastKnownRequestProcessed(ob_display); + r->end = end; ignore_serials = g_slist_prepend(ignore_serials, r); + ob_debug_type(OB_DEBUG_FOCUS, "ignoring enters from %lu until %lu\n", + r->start, r->end); + /* increment the serial so we don't ignore events we weren't meant to */ - XSync(ob_display, FALSE); + PROP_ERASE(screen_support_win, motif_wm_hints); } -static gboolean is_enter_focus_event_ignored(XEvent *e) +void event_end_ignore_all_enters(gulong start) { - GSList *it, *next; + /* 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(ob_display)-1); +} - g_assert(e->type == EnterNotify && - !(e->xcrossing.mode == NotifyGrab || - e->xcrossing.mode == NotifyUngrab || - e->xcrossing.detail == NotifyInferior)); +static gboolean is_enter_focus_event_ignored(gulong serial) +{ + GSList *it, *next; for (it = ignore_serials; it; it = next) { ObSerialRange *r = it->data; next = g_slist_next(it); - if ((glong)(e->xany.serial - r->end) > 0) { + if ((glong)(serial - r->end) > 0) { /* past the end */ ignore_serials = g_slist_delete_link(ignore_serials, it); g_free(r); } - else if ((glong)(e->xany.serial - r->start) >= 0) + else if ((glong)(serial - r->start) >= 0) return TRUE; } return FALSE; } -void event_cancel_all_key_grabs() +void event_cancel_all_key_grabs(void) { if (actions_interactive_act_running()) { actions_interactive_cancel_act(); @@ -1927,6 +2004,8 @@ void event_cancel_all_key_grabs() } else ungrab_passive_key(); + + XSync(ob_display, FALSE); } gboolean event_time_after(Time t1, Time t2) @@ -1954,7 +2033,7 @@ gboolean event_time_after(Time t1, Time t2) return t1 >= t2 && t1 < (t2 + TIME_HALF); } -Time event_get_server_time() +Time event_get_server_time(void) { /* Generate a timestamp */ XEvent event;