X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fevent.c;h=7e66cc28ed6318c550bad537d96665a8127e68a6;hb=eb2a0feb0154e86a1c6c117fd0f6d1a18959b694;hp=700013b8d793911b619ea408a36dd9c567ef74ee;hpb=53a259f60d932eb963ff0105e77084bab40f2459;p=chaz%2Fopenbox diff --git a/openbox/event.c b/openbox/event.c index 700013b8..7e66cc28 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -1,19 +1,20 @@ /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- -event.c for the Openbox window manager -Copyright (c) 2003 Ben Jansens + event.c for the Openbox window manager + Copyright (c) 2006 Mikael Magnusson + Copyright (c) 2003 Ben Jansens -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -See the COPYING file for a copy of the GNU General Public License. + See the COPYING file for a copy of the GNU General Public License. */ #include "event.h" @@ -50,13 +51,20 @@ See the COPYING file for a copy of the GNU General Public License. #ifdef HAVE_SIGNAL_H # include #endif +#ifdef XKB +# include +#endif #ifdef USE_SM #include #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); @@ -70,7 +78,8 @@ static void focus_delay_client_dest(ObClient *client, gpointer data); static gboolean menu_hide_delay_func(gpointer data); -Time event_lasttime = 0; +/* The time for the current event being processed */ +Time event_curtime = CurrentTime; /*! The value of the mask for the NumLock modifier */ guint NumLockMask; @@ -89,8 +98,6 @@ static guint ignore_enter_focus = 0; static gboolean menu_can_hide; -static ObClient *focus_in, *focus_out; - #ifdef USE_SM static void ice_handler(gint fd, gpointer conn) { @@ -131,10 +138,10 @@ void event_startup(gboolean reconfig) const KeyCode num_lock = XKeysymToKeycode(ob_display, XK_Num_Lock); const KeyCode scroll_lock = XKeysymToKeycode(ob_display, XK_Scroll_Lock); - + for (cnt = 0; cnt < size; ++cnt) { if (! modmap->modifiermap[cnt]) continue; - + if (num_lock == modmap->modifiermap[cnt]) NumLockMask = mask_table[cnt / modmap->max_keypermod]; if (scroll_lock == modmap->modifiermap[cnt]) @@ -142,7 +149,7 @@ void event_startup(gboolean reconfig) } } - ob_main_loop_x_add(ob_main_loop, event_process, event_done, NULL, NULL); + ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL); #ifdef USE_SM IceAddConnectionWatch(ice_watch, NULL); @@ -161,6 +168,7 @@ void event_shutdown(gboolean reconfig) #endif client_remove_destructor(focus_delay_client_dest); + client_remove_destructor(event_client_dest); XFreeModifiermap(modmap); } @@ -204,9 +212,9 @@ static Window event_get_window(XEvent *e) 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) { @@ -236,18 +244,20 @@ static void event_set_lasttime(XEvent *e) break; } - if (t > event_lasttime) - event_lasttime = t; + event_curtime = t; } #define STRIP_MODS(s) \ - s &= ~(LockMask | NumLockMask | ScrollLockMask), \ - /* kill off the Button1Mask etc, only want the modifiers */ \ - s &= (ControlMask | ShiftMask | Mod1Mask | \ + s &= ~(LockMask | NumLockMask | ScrollLockMask), \ + /* kill off the Button1Mask etc, only want the modifiers */ \ + s &= (ControlMask | ShiftMask | Mod1Mask | \ Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask) \ static void event_hack_mods(XEvent *e) { +#ifdef XKB + XkbStateRec xkb_state; +#endif KeyCode *kp; gint i, k; @@ -263,6 +273,12 @@ static void event_hack_mods(XEvent *e) STRIP_MODS(e->xkey.state); /* remove from the state the mask of the modifier being released, if it is a modifier key being released (this is a little ugly..) */ +#ifdef XKB + if (XkbGetState(ob_display, XkbUseCoreKbd, &xkb_state) == Success) { + e->xkey.state = xkb_state.compat_state; + break; + } +#endif kp = modmap->modifiermap; for (i = 0; i < mask_table_size; ++i) { for (k = 0; k < modmap->max_keypermod; ++k) { @@ -292,90 +308,99 @@ static void event_hack_mods(XEvent *e) } } -static gboolean event_ignore(XEvent *e, ObClient *client) +static gboolean wanted_focusevent(XEvent *e) { - switch(e->type) { - case EnterNotify: - case LeaveNotify: - if (e->xcrossing.detail == NotifyInferior) - return TRUE; - break; - case FocusIn: - if (e->xfocus.detail > NotifyNonlinearVirtual) + 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 || + detail == NotifyInferior) + return TRUE; + else + return FALSE; + } + + /* This means focus moved from the root window to a client */ + if (detail == NotifyVirtual) return TRUE; - break; - case FocusOut: - if (e->xfocus.detail > NotifyNonlinearVirtual) + /* This means focus moved from one client to another */ + if (detail == NotifyNonlinearVirtual) return TRUE; - if (e->xfocus.detail == NotifyInferior || - e->xfocus.mode == NotifyGrab) + + /* This means focus reverted off of a client */ + if (detail == NotifyInferior) return TRUE; - break; - } - return FALSE; -} -static void event_client_dest(ObClient *client, gpointer data) -{ - if (client == focus_in) - focus_in = NULL; - if (client == focus_out) - focus_out = NULL; - if (client == focus_hilite) - focus_hilite = NULL; -} + /* Otherwise.. */ + return FALSE; + } else { + g_assert(e->type == FocusOut); -static void event_done(gpointer data) -{ - static ObClient *last = NULL; - /* sometimes focus_hilite can be on an unfocused window, this make sure - it loses its focus hilite when focus moves */ - if (focus_hilite && - (focus_in && focus_hilite != focus_in) && - (focus_out && focus_hilite != focus_out)) - { - frame_adjust_focus(focus_hilite->frame, FALSE); - } + /* These are ones we never want.. */ - 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); - } + /* This means focus was taken by a keyboard/mouse grab. */ + if (mode == NotifyGrab) + return FALSE; - focus_hilite = focus_in; - } - if (focus_out) { - if (focus_out == focus_client) - focus_set_client(NULL); - frame_adjust_focus(focus_out->frame, FALSE); - client_calc_layer(focus_out); + /* Focus left the root window revertedto state */ + if (win == RootWindow(ob_display, ob_screen)) + return FALSE; - if (!focus_in) - focus_hilite = NULL; - } + /* These are the ones we want.. */ - if (focus_client != last) { - if (!focus_client) { - Window w; - gint r; + /* 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; - /* is focus anywhere valid? */ - XGetInputFocus(ob_display, &w, &r); + /* Otherwise.. */ + return FALSE; + } +} -#ifdef DEBUG_FOCUS - ob_debug("Focus was found on 0x%x revert %d\n", w, r); -#endif +static Bool look_for_focusin(Display *d, XEvent *e, XPointer arg) +{ + return e->type == FocusIn && wanted_focusevent(e); +} - if (!w || w == PointerRoot) - focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS); - } - last = focus_client; +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: + case FocusOut: + /* 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; + break; } - - focus_in = focus_out = NULL; + return FALSE; } static void event_process(const XEvent *ec, gpointer data) @@ -387,6 +412,7 @@ 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; @@ -414,10 +440,36 @@ static void event_process(const XEvent *ec, gpointer data) } } - 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 (event_ignore(e, client)) { + if (ed) + ed->ignored = TRUE; return; + } else if (ed) + ed->ignored = FALSE; /* deal with it in the kernel */ if (group) @@ -436,7 +488,7 @@ static void event_process(const XEvent *ec, gpointer data) /* unhandled configure requests must be used to configure the window directly */ XWindowChanges xwc; - + xwc.x = e->xconfigurerequest.x; xwc.y = e->xconfigurerequest.y; xwc.width = e->xconfigurerequest.width; @@ -472,20 +524,24 @@ static void event_process(const XEvent *ec, gpointer data) menu_can_hide = FALSE; ob_main_loop_timeout_add(ob_main_loop, - G_USEC_PER_SEC / 4, + config_menu_hide_delay * 1000, menu_hide_delay_func, NULL, NULL); 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) @@ -495,7 +551,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_exit(0); + ob_exit_replace(); break; case ClientMessage: @@ -504,6 +560,7 @@ 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) { @@ -512,6 +569,11 @@ static void event_handle_root(XEvent *e) screen_set_num_desktops(d); } else if (msgtype == prop_atoms.net_showing_desktop) { screen_show_desktop(e->xclient.data.l[0] != 0); + } else if (msgtype == prop_atoms.ob_control) { + if (e->xclient.data.l[0] == 1) + ob_reconfigure(); + else if (e->xclient.data.l[0] == 2) + ob_restart(); } break; case PropertyNotify: @@ -528,11 +590,6 @@ static void event_handle_root(XEvent *e) break; default: ; -#ifdef VIDMODE - if (extensions_vidmode && e->type == extensions_vidmode_event_basep) { - ob_debug("VIDMODE EVENT\n"); - } -#endif } } @@ -608,25 +665,50 @@ static void event_handle_client(ObClient *client, XEvent *e) } 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 - focus_in = client; - if (focus_out == client) - focus_out = NULL; + if (client != focus_client) { + focus_set_client(client); + frame_adjust_focus(client->frame, TRUE); + client_calc_layer(client); + } 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 - if (focus_hilite == client || focus_client == client) - focus_out = client; - if (focus_in == client) - focus_in = NULL; + /* 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, + or the root 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 LeaveNotify: con = frame_context(client, e->xcrossing.window); @@ -655,7 +737,7 @@ static void event_handle_client(ObClient *client, XEvent *e) if (config_focus_follow && config_focus_delay) ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, - client); + client, TRUE); break; default: break; @@ -773,14 +855,19 @@ static void event_handle_client(ObClient *client, XEvent *e) client->frame->size.left + client->frame->size.right; gint fh = h + client->frame->size.top + client->frame->size.bottom; + /* make this rude for size-only changes but not for position + changes.. */ + gboolean moving = ((e->xconfigurerequest.value_mask & CWX) || + (e->xconfigurerequest.value_mask & CWY)); + client_find_onscreen(client, &newx, &newy, fw, fh, - client_normal(client)); + !moving); if (e->xconfigurerequest.value_mask & CWX) x = newx; if (e->xconfigurerequest.value_mask & CWY) y = newy; } - + switch (client->gravity) { case NorthEastGravity: case EastGravity: @@ -805,18 +892,26 @@ static void event_handle_client(ObClient *client, XEvent *e) switch (e->xconfigurerequest.detail) { case Below: case BottomIf: - client_lower(client); + /* Apps are so rude. And this is totally disconnected from + activation/focus. Bleh. */ + /*client_lower(client);*/ break; case Above: case TopIf: default: - client_raise(client); + /* Apps are so rude. And this is totally disconnected from + activation/focus. Bleh. */ + /*client_raise(client);*/ break; } } break; case UnmapNotify: + 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); if (client->ignore_unmaps) { client->ignore_unmaps--; break; @@ -824,6 +919,7 @@ static void event_handle_client(ObClient *client, XEvent *e) client_unmanage(client); break; case DestroyNotify: + ob_debug("DestroyNotify for window 0x%x\n", client->window); client_unmanage(client); break; case ReparentNotify: @@ -841,13 +937,17 @@ static void event_handle_client(ObClient *client, XEvent *e) X server to deal with after we unmanage the window */ XPutBackEvent(ob_display, e); + ob_debug("ReparentNotify for window 0x%x\n", client->window); client_unmanage(client); break; case MapRequest: 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! */ - client_activate(client, FALSE); + does, we don't want it! + it can happen now when the window is on + another desktop, but we still don't + want it! */ + client_activate(client, FALSE, TRUE); break; case ClientMessage: /* validate cuz we query stuff off the client here */ @@ -901,10 +1001,19 @@ static void event_handle_client(ObClient *client, XEvent *e) 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); + ob_debug("net_active_window for 0x%lx source=%s\n", + client->window, + (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[2] ! */ + event_curtime = e->xclient.data.l[1]; + client_activate(client, FALSE, + (e->xclient.data.l[0] == 0 || + e->xclient.data.l[0] == 2)); } else if (msgtype == prop_atoms.net_wm_moveresize) { - ob_debug("net_wm_moveresize for 0x%lx\n", client->window); + ob_debug("net_wm_moveresize for 0x%lx direction %d\n", + client->window, e->xclient.data.l[2]); if ((Atom)e->xclient.data.l[2] == prop_atoms.net_wm_moveresize_size_topleft || (Atom)e->xclient.data.l[2] == @@ -934,6 +1043,9 @@ static void event_handle_client(ObClient *client, XEvent *e) e->xclient.data.l[1], e->xclient.data.l[3], e->xclient.data.l[2]); } + else if ((Atom)e->xclient.data.l[2] == + prop_atoms.net_wm_moveresize_cancel) + moveresize_end(TRUE); } else if (msgtype == prop_atoms.net_moveresize_window) { gint oldg = client->gravity; gint tmpg, x, y, w, h; @@ -975,7 +1087,7 @@ static void event_handle_client(ObClient *client, XEvent *e) if (e->xclient.data.l[0] & 1 << 9) y = newy; } - + client_configure(client, OB_CORNER_TOPLEFT, x, y, w, h, FALSE, TRUE); @@ -1010,11 +1122,8 @@ static void event_handle_client(ObClient *client, XEvent *e) b == prop_atoms.wm_icon_name)) { continue; } - if ((a == prop_atoms.net_wm_icon || - a == prop_atoms.kwm_win_icon) - && - (b == prop_atoms.net_wm_icon || - b == prop_atoms.kwm_win_icon)) + if (a == prop_atoms.net_wm_icon && + b == prop_atoms.net_wm_icon) continue; XPutBackEvent(ob_display, &ce); @@ -1048,10 +1157,12 @@ static void event_handle_client(ObClient *client, XEvent *e) 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) { + else if (msgtype == prop_atoms.net_wm_icon) { client_update_icons(client); } + else if (msgtype == prop_atoms.net_wm_user_time) { + client_update_user_time(client, TRUE); + } else if (msgtype == prop_atoms.sm_client_id) { client_update_sm_client_id(client); } @@ -1070,7 +1181,10 @@ static void event_handle_dock(ObDock *s, XEvent *e) { switch (e->type) { case ButtonPress: - stacking_raise(DOCK_AS_WINDOW(s)); + if (e->xbutton.button == 1) + stacking_raise(DOCK_AS_WINDOW(s)); + else if (e->xbutton.button == 2) + stacking_lower(DOCK_AS_WINDOW(s)); break; case EnterNotify: dock_hide(FALSE); @@ -1140,7 +1254,8 @@ static void event_handle_menu(XEvent *ev) 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); + menu_entry_frame_execute(e, ev->xbutton.state, + ev->xbutton.time); else menu_frame_hide_all(); } @@ -1170,7 +1285,8 @@ static void event_handle_menu(XEvent *ev) else if (ev->xkey.keycode == ob_keycode(OB_KEY_RETURN)) { ObMenuFrame *f; if ((f = find_active_menu())) - menu_entry_frame_execute(f->selected, ev->xkey.state); + menu_entry_frame_execute(f->selected, ev->xkey.state, + ev->xkey.time); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) { ObMenuFrame *f; if ((f = find_active_or_last_menu()) && f->parent) @@ -1203,16 +1319,25 @@ static gboolean focus_delay_func(gpointer data) 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 */ } static void focus_delay_client_dest(ObClient *client, gpointer data) { - ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, client); + ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, + client, TRUE); +} + +static void event_client_dest(ObClient *client, gpointer data) +{ + if (client == focus_hilite) + focus_hilite = NULL; } void event_halt_focus_delay()