X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fevent.c;h=68d511352201e9afe33b584ed4168be7bd558666;hb=ebf24d5224781e47b62cf20fb3852ef9782f200b;hp=00036b48c83ed8b228bd5c2bbfe03c453b208776;hpb=418095b48ea33dfce904a0250f1659a6a0feeb78;p=chaz%2Fopenbox diff --git a/openbox/event.c b/openbox/event.c index 00036b48..68d51135 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -15,6 +15,7 @@ #include "framerender.h" #include "focus.h" #include "moveresize.h" +#include "group.h" #include "stacking.h" #include "extensions.h" #include "event.h" @@ -24,10 +25,6 @@ #include #include -#ifdef USE_LIBSN -# include -#endif - #ifdef HAVE_SYS_SELECT_H # include #endif @@ -39,16 +36,25 @@ #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_handle_root(XEvent *e); static void event_handle_menu(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); +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 gboolean menu_hide_delay_func(gpointer data); + #define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \ (e)->xfocus.detail == NotifyAncestor || \ (e)->xfocus.detail > NotifyNonlinearVirtual) @@ -72,6 +78,10 @@ static const int mask_table[] = { }; static int mask_table_size; +static ObClient *focus_delay_client; + +static gboolean menu_can_hide; + #ifdef USE_SM static void ice_handler(int fd, gpointer conn) { @@ -94,18 +104,10 @@ static void ice_watch(IceConn conn, IcePointer data, Bool opening, } #endif -#ifdef USE_LIBSN -static void sn_handler(const XEvent *e, gpointer display) +void event_startup(gboolean reconfig) { - XEvent ec; - ec = *e; - sn_display_process_event(display, &ec); -} -#endif + if (reconfig) return; - -void event_startup() -{ mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]); /* get lock masks that are defined by the display (not constant) */ @@ -131,21 +133,23 @@ void event_startup() } } - ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL); + ob_main_loop_x_add(ob_main_loop, event_process, event_done, NULL, NULL); #ifdef USE_SM IceAddConnectionWatch(ice_watch, NULL); #endif -#ifdef USE_LIBSN - ob_main_loop_x_add(ob_main_loop, sn_handler, ob_sn_display, NULL); -#endif - client_add_destructor(focus_delay_client_dest); } -void event_shutdown() +void event_shutdown(gboolean reconfig) { + if (reconfig) return; + +#ifdef USE_SM + IceRemoveConnectionWatch(ice_watch, NULL); +#endif + client_remove_destructor(focus_delay_client_dest); XFreeModifiermap(modmap); } @@ -280,24 +284,32 @@ static void event_hack_mods(XEvent *e) static gboolean event_ignore(XEvent *e, ObClient *client) { + gboolean ignore = FALSE; + XEvent ce; + switch(e->type) { case FocusIn: + while (XCheckTypedWindowEvent(ob_display, e->xfocus.window, + FocusIn, &ce)) + { + if (!INVALID_FOCUSIN(&ce)) { + XPutBackEvent(ob_display, &ce); + ignore = TRUE; + break; + } + } + /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut because of RevertToPointerRoot. If the focus ends up reverting to pointer root on a workspace change, then the FocusIn event that we want will be of type NotifyAncestor. This situation does not occur for FocusOut, so it is safely ignored there. */ - if (INVALID_FOCUSIN(e) || - client == NULL) { + if (ignore || INVALID_FOCUSIN(e) || client == NULL) { #ifdef DEBUG_FOCUS - ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n", - e->xfocus.window, e->xfocus.mode, e->xfocus.detail); + ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n", + e->xfocus.window, e->xfocus.mode, e->xfocus.detail); #endif - /* says a client was not found for the event (or a valid FocusIn - event was not found. - */ - e->xfocus.window = None; return TRUE; } @@ -307,10 +319,20 @@ static gboolean event_ignore(XEvent *e, ObClient *client) #endif break; case FocusOut: - if (INVALID_FOCUSOUT(e)) { + while (XCheckTypedWindowEvent(ob_display, e->xfocus.window, + FocusOut, &ce)) + { + if (!INVALID_FOCUSOUT(&ce)) { + XPutBackEvent(ob_display, &ce); + ignore = TRUE; + break; + } + } + + if (ignore || INVALID_FOCUSOUT(e)) { #ifdef DEBUG_FOCUS - ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n", - e->xfocus.window, e->xfocus.mode, e->xfocus.detail); + ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n", + e->xfocus.window, e->xfocus.mode, e->xfocus.detail); #endif return TRUE; } @@ -319,100 +341,29 @@ static gboolean event_ignore(XEvent *e, ObClient *client) ob_debug("FocusOut on %lx mode %d detail %d\n", e->xfocus.window, e->xfocus.mode, e->xfocus.detail); #endif - - { - XEvent fe; - gboolean fallback = TRUE; - - while (TRUE) { - if (!XCheckTypedWindowEvent(ob_display, e->xfocus.window, - FocusOut, &fe)) - if (!XCheckTypedEvent(ob_display, FocusIn, &fe)) - break; - if (fe.type == FocusOut) { -#ifdef DEBUG_FOCUS - ob_debug("found pending FocusOut"); -#endif - if (!INVALID_FOCUSOUT(&fe)) { - /* if there is a VALID FocusOut still coming, don't - fallback focus yet, we'll deal with it then */ - XPutBackEvent(ob_display, &fe); - fallback = FALSE; - break; - } - } else { -#ifdef DEBUG_FOCUS - ob_debug("found pending FocusIn"); -#endif - /* is the focused window getting a FocusOut/In back to - itself? - */ - if (fe.xfocus.window == e->xfocus.window && - !event_ignore(&fe, client)) { - /* - if focus_client is not set, then we can't do - this. we need the FocusIn. This happens in the - case when the set_focus_client(NULL) in the - focus_fallback function fires and then - focus_fallback picks the currently focused - window (such as on a SendToDesktop-esque action. - */ - if (focus_client) { -#ifdef DEBUG_FOCUS - ob_debug("focused window got an Out/In back to " - "itself IGNORED both"); -#endif - return TRUE; - } else { - event_process(&fe, NULL); -#ifdef DEBUG_FOCUS - ob_debug("focused window got an Out/In back to " - "itself but focus_client was null " - "IGNORED just the Out"); -#endif - return TRUE; - } - } - - /* once all the FocusOut's have been dealt with, if there - is a FocusIn still left and it is valid, then use it */ - event_process(&fe, NULL); - /* secret magic way of event_process telling us that no - client was found for the FocusIn event. ^_^ */ - if (fe.xfocus.window != None) { - fallback = FALSE; - break; - } - } - } - if (fallback) { -#ifdef DEBUG_FOCUS - ob_debug("no valid FocusIn and no FocusOut events found, " - "falling back"); -#endif - 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 occurs when ungrabbing the pointer */ + /* 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 == NotifyVirtual)) { -#ifdef DEBUG_FOCUS - ob_debug("%sNotify mode %d detail %d on %lx IGNORED", + (e->xcrossing.detail == NotifyAncestor || + e->xcrossing.detail == NotifyNonlinearVirtual || + e->xcrossing.detail == NotifyVirtual))) { +#ifdef aDEBUG_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", +#ifdef aDEBUG_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); @@ -425,43 +376,53 @@ static gboolean event_ignore(XEvent *e, ObClient *client) static void event_process(const XEvent *ec, gpointer data) { Window window; + ObGroup *group = NULL; ObClient *client = NULL; ObDock *dock = NULL; ObDockApp *dockapp = NULL; ObWindow *obwin = NULL; XEvent ee, *e; + ObEventData *ed = data; /* make a copy we can mangle */ ee = *ec; e = ⅇ window = event_get_window(e); - if ((obwin = g_hash_table_lookup(window_map, &window))) { - switch (obwin->type) { - case Window_Dock: - dock = WINDOW_AS_DOCK(obwin); - break; - case Window_DockApp: - dockapp = WINDOW_AS_DOCKAPP(obwin); - break; - case Window_Client: - client = WINDOW_AS_CLIENT(obwin); - break; - case Window_Menu: - case Window_Internal: - /* not to be used for events */ - g_assert_not_reached(); - break; + if (!(e->type == PropertyNotify && + (group = g_hash_table_lookup(group_map, &window)))) + if ((obwin = g_hash_table_lookup(window_map, &window))) { + switch (obwin->type) { + case Window_Dock: + dock = WINDOW_AS_DOCK(obwin); + break; + case Window_DockApp: + dockapp = WINDOW_AS_DOCKAPP(obwin); + break; + case Window_Client: + client = WINDOW_AS_CLIENT(obwin); + break; + case Window_Menu: + case Window_Internal: + /* not to be used for events */ + g_assert_not_reached(); + break; + } } - } event_set_lasttime(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 (client) + if (group) + event_handle_group(group, e); + else if (client) event_handle_client(client, e); else if (dockapp) event_handle_dockapp(dockapp, e); @@ -499,24 +460,38 @@ static void event_process(const XEvent *ec, gpointer data) { if (menu_frame_visible) event_handle_menu(e); - else if (moveresize_in_progress) - moveresize_event(e); else { - ObFrameContext context; + if (!keyboard_process_interactive_grab(e, &client)) { + if (moveresize_in_progress) + moveresize_event(e); - context = frame_context(client, e->xany.window); + menu_can_hide = FALSE; + ob_main_loop_timeout_add(ob_main_loop, + G_USEC_PER_SEC / 4, + menu_hide_delay_func, + NULL, NULL); - if (!keyboard_process_interactive_grab(e, &client, &context)) { if (e->type == ButtonPress || e->type == ButtonRelease || e->type == MotionNotify) - mouse_event(client, context, e); + mouse_event(client, e); else if (e->type == KeyPress) - keyboard_event(client, e); + /* when in the middle of a focus cycling action, this + 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); } } } } +static void event_done(gpointer data) +{ + if (!focus_client) + focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS); +} + static void event_handle_root(XEvent *e) { Atom msgtype; @@ -565,6 +540,16 @@ static void event_handle_root(XEvent *e) } } +static void event_handle_group(ObGroup *group, XEvent *e) +{ + GSList *it; + + g_assert(e->type == PropertyNotify); + + for (it = group->members; it; it = g_slist_next(it)) + event_handle_client(it->data, e); +} + static void event_handle_client(ObClient *client, XEvent *e) { XEvent ce; @@ -581,7 +566,9 @@ static void event_handle_client(ObClient *client, XEvent *e) /* Wheel buttons don't draw because they are an instant click, so it is a waste of resources to go drawing it. */ if (!(e->xbutton.button == 4 || e->xbutton.button == 5)) { - switch (frame_context(client, e->xbutton.window)) { + con = frame_context(client, e->xbutton.window); + con = mouse_button_frame_context(con, e->xbutton.button); + switch (con) { case OB_FRAME_CONTEXT_MAXIMIZE: client->frame->max_press = (e->type == ButtonPress); framerender_frame(client->frame); @@ -610,27 +597,22 @@ static void event_handle_client(ObClient *client, XEvent *e) break; case FocusIn: #ifdef DEBUG_FOCUS - ob_debug("FocusIn on client for %lx\n", client->window); + ob_debug("Focus%s on client for %lx\n", (e->type==FocusIn?"In":"Out"), + client->window); #endif - if (client != focus_client) { + if (client != focus_client) focus_set_client(client); - frame_adjust_focus(client->frame, TRUE); - } + frame_adjust_focus(client->frame, e->type == FocusIn); break; case FocusOut: #ifdef DEBUG_FOCUS - ob_debug("FocusOut on client for %lx\n", client->window); + ob_debug("Focus%s on client for %lx\n", (e->type==FocusIn?"In":"Out"), + 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; + if (client == focus_client) + focus_client = NULL; + frame_adjust_focus(client->frame, e->type == FocusIn); + break; case LeaveNotify: con = frame_context(client, e->xcrossing.window); switch (con) { @@ -657,8 +639,12 @@ static void event_handle_client(ObClient *client, XEvent *e) case OB_FRAME_CONTEXT_FRAME: /* XXX if doing a 'reconfigure' make sure you kill this timer, maybe all timers.. */ - if (config_focus_delay) - ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func); + if (config_focus_delay && client == focus_delay_client) { + ob_main_loop_timeout_remove_data(ob_main_loop, + focus_delay_func, + focus_delay_client); + focus_delay_client = NULL; + } default: break; } @@ -688,16 +674,8 @@ static void event_handle_client(ObClient *client, XEvent *e) break; case OB_FRAME_CONTEXT_FRAME: if (client_normal(client)) { - if (ob_state() == OB_STATE_STARTING) { - /* move it to the top of the focus order */ - guint desktop = client->desktop; - if (desktop == DESKTOP_ALL) desktop = screen_desktop; - focus_order[desktop] = g_list_remove(focus_order[desktop], - client); - focus_order[desktop] = g_list_prepend(focus_order[desktop], - client); - } else if (config_focus_follow) { -#ifdef DEBUG_FOCUS + if (config_focus_follow) { +#ifdef aDEBUG_FOCUS ob_debug("EnterNotify on %lx, focusing window\n", client->window); #endif @@ -705,8 +683,8 @@ static void event_handle_client(ObClient *client, XEvent *e) ob_main_loop_timeout_add(ob_main_loop, config_focus_delay, focus_delay_func, - client, - NULL); + client, NULL); + focus_delay_client = client; } else client_focus(client); } @@ -1057,6 +1035,9 @@ static void event_handle_client(ObClient *client, XEvent *e) msgtype == prop_atoms.kwm_win_icon) { client_update_icons(client); } + else if (msgtype == prop_atoms.sm_client_id) { + client_update_sm_client_id(client); + } default: ; #ifdef SHAPE @@ -1128,15 +1109,11 @@ static void event_handle_menu(XEvent *ev) switch (ev->type) { case ButtonRelease: - if (!(f = menu_frame_under(ev->xbutton.x_root, - ev->xbutton.y_root))) + 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(); - else { - if ((e = menu_entry_frame_under(ev->xbutton.x_root, - ev->xbutton.y_root))) - menu_entry_frame_execute(e, - !(ev->xbutton.state & ControlMask)); - } break; case MotionNotify: if ((f = menu_frame_under(ev->xmotion.x_root, @@ -1146,6 +1123,16 @@ static void event_handle_menu(XEvent *ev) ev->xmotion.y_root))) menu_frame_select(f, e); } + { + ObMenuFrame *a; + + a = find_active_menu(); + if (a && a != f && + a->selected->entry->type != OB_MENU_ENTRY_TYPE_SUBMENU) + { + menu_frame_select(a, NULL); + } + } break; case KeyPress: if (ev->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) @@ -1153,8 +1140,7 @@ 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 & ControlMask)); + 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) @@ -1176,14 +1162,24 @@ static void event_handle_menu(XEvent *ev) } } +static gboolean menu_hide_delay_func(gpointer data) +{ + menu_can_hide = TRUE; + return FALSE; /* no repeat */ +} + static gboolean focus_delay_func(gpointer data) { - ObClient *c = data; - client_focus(c); + client_focus(focus_delay_client); return FALSE; /* no repeat */ } static void focus_delay_client_dest(gpointer data) { - ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func); + 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; + } }