X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fevent.c;h=918024969f4cda9387894703c7b82e2594fef37c;hb=9bac22eb402a477b802416287b9e76bf908408ed;hp=051e29c03556edb0b13b230afaeec05c4024d1dc;hpb=16f46c296d1fcd3f27fc62a18e71c55fb3fd3e88;p=chaz%2Fopenbox diff --git a/openbox/event.c b/openbox/event.c index 051e29c0..91802496 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -16,7 +16,9 @@ See the COPYING file for a copy of the GNU General Public License. */ +#include "event.h" #include "debug.h" +#include "window.h" #include "openbox.h" #include "dock.h" #include "client.h" @@ -36,7 +38,6 @@ #include "group.h" #include "stacking.h" #include "extensions.h" -#include "event.h" #include #include @@ -68,7 +69,7 @@ static void event_handle_client(ObClient *c, XEvent *e); static void event_handle_group(ObGroup *g, XEvent *e); static gboolean focus_delay_func(gpointer data); -static void focus_delay_client_dest(gpointer data); +static void focus_delay_client_dest(ObClient *client, gpointer data); static gboolean menu_hide_delay_func(gpointer data); @@ -95,7 +96,7 @@ static const int mask_table[] = { }; static int mask_table_size; -static ObClient *focus_delay_client; +static guint ignore_enter_focus = 0; static gboolean menu_can_hide; @@ -156,7 +157,7 @@ void event_startup(gboolean reconfig) IceAddConnectionWatch(ice_watch, NULL); #endif - client_add_destructor(focus_delay_client_dest); + client_add_destructor(focus_delay_client_dest, NULL); } void event_shutdown(gboolean reconfig) @@ -302,6 +303,11 @@ static void event_hack_mods(XEvent *e) 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: /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut because of RevertToPointerRoot. If the focus ends up reverting to @@ -420,34 +426,7 @@ static gboolean event_ignore(XEvent *e, ObClient *client) focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS); } } - break; - case EnterNotify: - case LeaveNotify: - /* NotifyUngrab occurs when a mouse button is released and the event is - caused, like when lowering a window */ - /* NotifyVirtual and NotifyAncestor occurs when ungrabbing the - pointer (Ancestor happens when the pointer is on a window border) */ - if (e->xcrossing.mode == NotifyGrab || - e->xcrossing.detail == NotifyInferior || - (e->xcrossing.mode == NotifyUngrab && - (e->xcrossing.detail == NotifyAncestor || - e->xcrossing.detail == NotifyNonlinearVirtual || - e->xcrossing.detail == NotifyVirtual))) { -#ifdef DEBUG_FOCUS - ob_debug("%sNotify mode %d detail %d on %lx IGNORED\n", - (e->type == EnterNotify ? "Enter" : "Leave"), - e->xcrossing.mode, - e->xcrossing.detail, client?client->window:0); -#endif - return TRUE; - } -#ifdef DEBUG_FOCUS - ob_debug("%sNotify mode %d detail %d on %lx\n", - (e->type == EnterNotify ? "Enter" : "Leave"), - e->xcrossing.mode, - e->xcrossing.detail, client?client->window:0); -#endif - break; + break; } return FALSE; } @@ -541,9 +520,14 @@ static void event_process(const XEvent *ec, gpointer data) event_handle_menu(e); else { if (!keyboard_process_interactive_grab(e, &client)) { - if (moveresize_in_progress) + if (moveresize_in_progress) { moveresize_event(e); + /* make further actions work on the client being + moved/resized */ + client = moveresize_client; + } + menu_can_hide = FALSE; ob_main_loop_timeout_add(ob_main_loop, G_USEC_PER_SEC / 4, @@ -558,8 +542,7 @@ static void event_process(const XEvent *ec, gpointer data) causes the window which appears to be focused to be the one on which the actions will be executed */ keyboard_event((focus_cycle_target ? - focus_cycle_target : - (client ? client : focus_client)), e); + focus_cycle_target : client), e); } } } @@ -623,6 +606,22 @@ static void event_handle_group(ObGroup *group, XEvent *e) event_handle_client(it->data, e); } +void event_enter_client(ObClient *client) +{ + g_assert(config_focus_follow); + + if (client_normal(client) && client_can_focus(client)) { + if (config_focus_delay) { + ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func); + ob_main_loop_timeout_add(ob_main_loop, + config_focus_delay, + focus_delay_func, + client, NULL); + } else + focus_delay_func(client); + } +} + static void event_handle_client(ObClient *client, XEvent *e) { XEvent ce; @@ -675,22 +674,16 @@ static void event_handle_client(ObClient *client, XEvent *e) 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\n", client->window); #endif - /* are we a fullscreen window or a transient of one? (checks layer) - if we are then we need to be iconified since we are losing focus - */ - if (client->layer == OB_STACKING_LAYER_FULLSCREEN && !client->iconic && - !client_search_focus_tree_full(client)) - /* iconify fullscreen windows when they and their transients - aren't focused */ - client_iconify(client, TRUE, TRUE); frame_adjust_focus(client->frame, FALSE); - break; + client_calc_layer(client); + break; case LeaveNotify: con = frame_context(client, e->xcrossing.window); switch (con) { @@ -715,19 +708,26 @@ static void event_handle_client(ObClient *client, XEvent *e) frame_adjust_state(client->frame); break; case OB_FRAME_CONTEXT_FRAME: - /* XXX if doing a 'reconfigure' make sure you kill this timer, - maybe all timers.. */ - if (config_focus_delay && client == focus_delay_client) { + /* + if (config_focus_follow && config_focus_delay) ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, - focus_delay_client); - focus_delay_client = NULL; - } + client); + */ + break; default: break; } break; case EnterNotify: + { + gboolean nofocus = FALSE; + + if (ignore_enter_focus) { + ignore_enter_focus--; + nofocus = TRUE; + } + con = frame_context(client, e->xcrossing.window); switch (con) { case OB_FRAME_CONTEXT_MAXIMIZE: @@ -751,27 +751,32 @@ static void event_handle_client(ObClient *client, XEvent *e) frame_adjust_state(client->frame); break; case OB_FRAME_CONTEXT_FRAME: - if (client_normal(client)) { - if (config_focus_follow) { + if (e->xcrossing.mode == NotifyGrab || + e->xcrossing.mode == NotifyUngrab) + { #ifdef DEBUG_FOCUS - ob_debug("EnterNotify on %lx, focusing window\n", - client->window); + ob_debug("%sNotify mode %d detail %d on %lx IGNORED\n", + (e->type == EnterNotify ? "Enter" : "Leave"), + e->xcrossing.mode, + e->xcrossing.detail, client?client->window:0); #endif - if (config_focus_delay) { - ob_main_loop_timeout_add(ob_main_loop, - config_focus_delay, - focus_delay_func, - client, NULL); - focus_delay_client = client; - } else - client_focus(client); - } + } else { +#ifdef DEBUG_FOCUS + ob_debug("%sNotify mode %d detail %d on %lx, " + "focusing window\n", + (e->type == EnterNotify ? "Enter" : "Leave"), + e->xcrossing.mode, + e->xcrossing.detail, client?client->window:0); +#endif + if (!nofocus && config_focus_follow) + event_enter_client(client); } break; default: break; } break; + } case ConfigureRequest: /* compress these */ while (XCheckTypedWindowEvent(ob_display, client->window, @@ -857,14 +862,14 @@ static void event_handle_client(ObClient *client, XEvent *e) switch (e->xconfigurerequest.detail) { case Below: case BottomIf: - stacking_lower(CLIENT_AS_WINDOW(client)); - break; + client_lower(client); + break; case Above: case TopIf: default: - stacking_raise(CLIENT_AS_WINDOW(client)); - break; + client_raise(client); + break; } } break; @@ -899,73 +904,64 @@ static void event_handle_client(ObClient *client, XEvent *e) 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! */ - if (screen_showing_desktop) - screen_show_desktop(FALSE); - client_iconify(client, FALSE, TRUE); - if (!client->frame->visible) - /* if its not visible still, then don't mess with it */ - break; - if (client->shaded) - client_shade(client, FALSE); - client_focus(client); - stacking_raise(CLIENT_AS_WINDOW(client)); - break; + client_activate(client, FALSE); + break; case ClientMessage: - /* validate cuz we query stuff off the client here */ - if (!client_validate(client)) break; - - if (e->xclient.format != 32) return; + /* validate cuz we query stuff off the client here */ + if (!client_validate(client)) break; - msgtype = e->xclient.message_type; - if (msgtype == prop_atoms.wm_change_state) { - /* compress changes into a single change */ - while (XCheckTypedWindowEvent(ob_display, client->window, - e->type, &ce)) { - /* XXX: it would be nice to compress ALL messages of a - type, not just messages in a row without other - message types between. */ - if (ce.xclient.message_type != msgtype) { - XPutBackEvent(ob_display, &ce); - break; - } - e->xclient = ce.xclient; - } - client_set_wm_state(client, e->xclient.data.l[0]); - } else if (msgtype == prop_atoms.net_wm_desktop) { - /* compress changes into a single change */ - while (XCheckTypedWindowEvent(ob_display, client->window, - e->type, &ce)) { - /* XXX: it would be nice to compress ALL messages of a - type, not just messages in a row without other - message types between. */ - if (ce.xclient.message_type != msgtype) { - XPutBackEvent(ob_display, &ce); - break; - } - e->xclient = ce.xclient; - } + if (e->xclient.format != 32) return; + + msgtype = e->xclient.message_type; + if (msgtype == prop_atoms.wm_change_state) { + /* compress changes into a single change */ + while (XCheckTypedWindowEvent(ob_display, client->window, + e->type, &ce)) { + /* XXX: it would be nice to compress ALL messages of a + type, not just messages in a row without other + message types between. */ + if (ce.xclient.message_type != msgtype) { + XPutBackEvent(ob_display, &ce); + break; + } + e->xclient = ce.xclient; + } + client_set_wm_state(client, e->xclient.data.l[0]); + } else if (msgtype == prop_atoms.net_wm_desktop) { + /* compress changes into a single change */ + while (XCheckTypedWindowEvent(ob_display, client->window, + e->type, &ce)) { + /* XXX: it would be nice to compress ALL messages of a + type, not just messages in a row without other + message types between. */ + if (ce.xclient.message_type != msgtype) { + XPutBackEvent(ob_display, &ce); + break; + } + e->xclient = ce.xclient; + } if ((unsigned)e->xclient.data.l[0] < screen_num_desktops || (unsigned)e->xclient.data.l[0] == DESKTOP_ALL) client_set_desktop(client, (unsigned)e->xclient.data.l[0], FALSE); - } else if (msgtype == prop_atoms.net_wm_state) { - /* can't compress these */ - ob_debug("net_wm_state %s %ld %ld for 0x%lx\n", + } else if (msgtype == prop_atoms.net_wm_state) { + /* can't compress these */ + ob_debug("net_wm_state %s %ld %ld for 0x%lx\n", (e->xclient.data.l[0] == 0 ? "Remove" : e->xclient.data.l[0] == 1 ? "Add" : e->xclient.data.l[0] == 2 ? "Toggle" : "INVALID"), e->xclient.data.l[1], e->xclient.data.l[2], client->window); - client_set_state(client, e->xclient.data.l[0], - e->xclient.data.l[1], e->xclient.data.l[2]); - } else if (msgtype == prop_atoms.net_close_window) { - 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_set_state(client, e->xclient.data.l[0], + e->xclient.data.l[1], e->xclient.data.l[2]); + } else if (msgtype == prop_atoms.net_close_window) { + 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); - } else if (msgtype == prop_atoms.net_wm_moveresize) { - ob_debug("net_wm_moveresize for 0x%lx\n", client->window); + } else if (msgtype == prop_atoms.net_wm_moveresize) { + ob_debug("net_wm_moveresize for 0x%lx\n", client->window); if ((Atom)e->xclient.data.l[2] == prop_atoms.net_wm_moveresize_size_topleft || (Atom)e->xclient.data.l[2] == @@ -1042,18 +1038,18 @@ static void event_handle_client(ObClient *client, XEvent *e) client->gravity = oldg; } - break; + break; case PropertyNotify: - /* validate cuz we query stuff off the client here */ - if (!client_validate(client)) break; + /* validate cuz we query stuff off the client here */ + if (!client_validate(client)) break; - /* compress changes to a single property into a single change */ - while (XCheckTypedWindowEvent(ob_display, client->window, - e->type, &ce)) { + /* compress changes to a single property into a single change */ + while (XCheckTypedWindowEvent(ob_display, client->window, + e->type, &ce)) { Atom a, b; /* XXX: it would be nice to compress ALL changes to a property, - not just changes in a row without other props between. */ + not just changes in a row without other props between. */ a = ce.xproperty.atom; b = e->xproperty.atom; @@ -1080,38 +1076,38 @@ static void event_handle_client(ObClient *client, XEvent *e) XPutBackEvent(ob_display, &ce); break; - } + } - msgtype = e->xproperty.atom; - if (msgtype == XA_WM_NORMAL_HINTS) { - client_update_normal_hints(client); - /* normal hints can make a window non-resizable */ - client_setup_decor_and_functions(client); - } else if (msgtype == XA_WM_HINTS) { - client_update_wmhints(client); - } else if (msgtype == XA_WM_TRANSIENT_FOR) { - client_update_transient_for(client); - client_get_type(client); - /* type may have changed, so update the layer */ - client_calc_layer(client); - client_setup_decor_and_functions(client); - } else if (msgtype == prop_atoms.net_wm_name || + msgtype = e->xproperty.atom; + if (msgtype == XA_WM_NORMAL_HINTS) { + client_update_normal_hints(client); + /* normal hints can make a window non-resizable */ + client_setup_decor_and_functions(client); + } else if (msgtype == XA_WM_HINTS) { + client_update_wmhints(client); + } else if (msgtype == XA_WM_TRANSIENT_FOR) { + client_update_transient_for(client); + client_get_type(client); + /* type may have changed, so update the layer */ + client_calc_layer(client); + client_setup_decor_and_functions(client); + } else if (msgtype == prop_atoms.net_wm_name || msgtype == prop_atoms.wm_name || 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); + 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); - } - else if (msgtype == prop_atoms.net_wm_strut) { - client_update_strut(client); + client_update_protocols(client); + client_setup_decor_and_functions(client); + } + else if (msgtype == prop_atoms.net_wm_strut) { + client_update_strut(client); } - else if (msgtype == prop_atoms.net_wm_icon || + else if (msgtype == prop_atoms.net_wm_icon || msgtype == prop_atoms.kwm_win_icon) { - client_update_icons(client); + client_update_icons(client); } else if (msgtype == prop_atoms.sm_client_id) { client_update_sm_client_id(client); @@ -1149,18 +1145,18 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e) dock_app_drag(app, &e->xmotion); break; case UnmapNotify: - if (app->ignore_unmaps) { - app->ignore_unmaps--; - break; - } - dock_remove(app, TRUE); - break; + if (app->ignore_unmaps) { + app->ignore_unmaps--; + break; + } + dock_remove(app, TRUE); + break; case DestroyNotify: - dock_remove(app, FALSE); - break; + dock_remove(app, FALSE); + break; case ReparentNotify: - dock_remove(app, FALSE); - break; + dock_remove(app, FALSE); + break; case ConfigureNotify: dock_app_configure(app, e->xconfigure.width, e->xconfigure.height); break; @@ -1170,14 +1166,25 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e) ObMenuFrame* find_active_menu() { GList *it; - ObMenuFrame *f; + ObMenuFrame *ret = NULL; for (it = menu_frame_visible; it; it = g_list_next(it)) { - f = it->data; - if (f->selected) + ret = it->data; + if (ret->selected) break; + ret = NULL; } - return it ? it->data : NULL; + return ret; +} + +ObMenuFrame* find_active_or_last_menu() +{ + ObMenuFrame *ret = NULL; + + ret = find_active_menu(); + if (!ret && menu_frame_visible) + ret = menu_frame_visible->data; + return ret; } static void event_handle_menu(XEvent *ev) @@ -1187,11 +1194,13 @@ static void event_handle_menu(XEvent *ev) switch (ev->type) { case ButtonRelease: - if ((e = menu_entry_frame_under(ev->xbutton.x_root, - ev->xbutton.y_root))) - menu_entry_frame_execute(e, ev->xbutton.state); - else if (menu_can_hide) - menu_frame_hide_all(); + 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); + else + menu_frame_hide_all(); + } break; case MotionNotify: if ((f = menu_frame_under(ev->xmotion.x_root, @@ -1221,19 +1230,19 @@ static void event_handle_menu(XEvent *ev) menu_entry_frame_execute(f->selected, ev->xkey.state); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) { ObMenuFrame *f; - if ((f = find_active_menu()) && f->parent) + if ((f = find_active_or_last_menu()) && f->parent) menu_frame_select(f, NULL); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) { ObMenuFrame *f; - if ((f = find_active_menu()) && f->child) + if ((f = find_active_or_last_menu()) && f->child) menu_frame_select_next(f->child); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_UP)) { ObMenuFrame *f; - if ((f = find_active_menu())) + if ((f = find_active_or_last_menu())) menu_frame_select_previous(f); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_DOWN)) { ObMenuFrame *f; - if ((f = find_active_menu())) + if ((f = find_active_or_last_menu())) menu_frame_select_next(f); } break; @@ -1248,16 +1257,43 @@ static gboolean menu_hide_delay_func(gpointer data) static gboolean focus_delay_func(gpointer data) { - client_focus(focus_delay_client); + ObClient *c = data; + + if (focus_client != c) { + client_focus(c); + if (config_focus_raise) + client_raise(c); + } return FALSE; /* no repeat */ } -static void focus_delay_client_dest(gpointer data) +static void focus_delay_client_dest(ObClient *client, gpointer data) { - ObClient *c = data; - if (c == focus_delay_client) { - ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, - focus_delay_client); - focus_delay_client = NULL; + ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, client); +} + +void event_ignore_queued_enters() +{ + GSList *saved = NULL, *it; + XEvent *e; + + XSync(ob_display, FALSE); + + /* count the events */ + while (TRUE) { + e = g_new(XEvent, 1); + if (XCheckTypedEvent(ob_display, EnterNotify, e)) { + saved = g_slist_append(saved, e); + ++ignore_enter_focus; + } else { + g_free(e); + break; + } + } + /* put the events back */ + for (it = saved; it; it = g_slist_next(it)) { + XPutBackEvent(ob_display, it->data); + g_free(it->data); } + g_slist_free(saved); }