X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fevent.c;h=9d6ff5fd86f09d8ee9ac24326d84411c10a98347;hb=5d5be2ba2a6e0b3886e0076475ed9d7a2d4ac9ab;hp=9a1e13dc831becd6c2baf1282d2033a7a32d93b7;hpb=939fbcfd31e07a6e0f1cdbfcef9b04f63e6af700;p=chaz%2Fopenbox diff --git a/openbox/event.c b/openbox/event.c index 9a1e13dc..9d6ff5fd 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -2,7 +2,7 @@ event.c for the Openbox window manager Copyright (c) 2006 Mikael Magnusson - Copyright (c) 2003 Ben Jansens + Copyright (c) 2003-2007 Dana 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 @@ -39,6 +39,7 @@ #include "group.h" #include "stacking.h" #include "extensions.h" +#include "translate.h" #include #include @@ -71,8 +72,8 @@ typedef struct } ObFocusDelayData; static void event_process(const XEvent *e, gpointer data); -static void event_client_dest(ObClient *client, gpointer data); static void event_handle_root(XEvent *e); +static void event_handle_menu_shortcut(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); @@ -164,7 +165,6 @@ void event_startup(gboolean reconfig) #endif client_add_destructor(focus_delay_client_dest, NULL); - client_add_destructor(event_client_dest, NULL); } void event_shutdown(gboolean reconfig) @@ -176,7 +176,6 @@ void event_shutdown(gboolean reconfig) #endif client_remove_destructor(focus_delay_client_dest); - client_remove_destructor(event_client_dest); XFreeModifiermap(modmap); } @@ -214,6 +213,13 @@ static Window event_get_window(XEvent *e) window = None; } } else +#endif +#ifdef SYNC + if (extensions_sync && + e->type == extensions_sync_event_basep + XSyncAlarmNotify) + { + window = None; + } else #endif window = e->xany.window; } @@ -247,6 +253,13 @@ static void event_set_curtime(XEvent *e) t = e->xcrossing.time; break; default: +#ifdef SYNC + if (extensions_sync && + e->type == extensions_sync_event_basep + XSyncAlarmNotify) + { + t = ((XSyncAlarmNotifyEvent*)e)->time; + } +#endif /* if more event types are anticipated, get their timestamp explicitly */ break; @@ -351,10 +364,6 @@ static gboolean wanted_focusevent(XEvent *e) if (detail == NotifyNonlinearVirtual) return TRUE; - /* This means focus reverted off of a client */ - if (detail == NotifyInferior) - return TRUE; - /* Otherwise.. */ return FALSE; } else { @@ -379,6 +388,9 @@ static gboolean wanted_focusevent(XEvent *e) /* This means focus moved from one client to another */ if (detail == NotifyNonlinearVirtual) return TRUE; + /* This means focus had moved to our frame window and now moved off */ + if (detail == NotifyNonlinear) + return TRUE; /* Otherwise.. */ return FALSE; @@ -393,15 +405,11 @@ static Bool look_for_focusin(Display *d, XEvent *e, XPointer arg) static gboolean event_ignore(XEvent *e, ObClient *client) { switch(e->type) { - case EnterNotify: - case LeaveNotify: - return keyboard_interactively_grabbed(); 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) + if (!wanted_focusevent(e)) return TRUE; + break; + case FocusOut: if (!wanted_focusevent(e)) return TRUE; break; @@ -446,29 +454,6 @@ static void event_process(const XEvent *ec, gpointer data) } } - 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_type(OB_DEBUG_FOCUS, - "FOCUS %s NOTIFY VIRTUAL window 0x%x\n", - (e->type == FocusIn ? "IN" : "OUT"), window); - } - - else if (detail == NotifyNonlinearVirtual) { - ob_debug_type(OB_DEBUG_FOCUS, - "FOCUS %s NOTIFY NONLINVIRTUAL window 0x%x\n", - (e->type == FocusIn ? "IN" : "OUT"), window); - } - - else - ob_debug_type(OB_DEBUG_FOCUS, - "UNKNOWN FOCUS %s (d %d, m %d) window 0x%x\n", - (e->type == FocusIn ? "IN" : "OUT"), - detail, mode, window); - } - event_set_curtime(e); event_hack_mods(e); if (event_ignore(e, client)) { @@ -485,6 +470,57 @@ static void event_process(const XEvent *ec, gpointer data) { /* crossing events for menu */ event_handle_menu(e); + } else if (e->type == FocusIn) { + if (client && client != focus_client) { + frame_adjust_focus(client->frame, TRUE); + focus_set_client(client); + client_calc_layer(client); + } + } else if (e->type == FocusOut) { + gboolean nomove = FALSE; + XEvent ce; + + ob_debug_type(OB_DEBUG_FOCUS, "FocusOut Event\n"); + + /* 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_type(OB_DEBUG_FOCUS, "Focus went to a black hole !\n"); + /* nothing is focused */ + focus_set_client(NULL); + } else if (ce.xany.window == e->xany.window) { + ob_debug_type(OB_DEBUG_FOCUS, "Focus didn't go anywhere\n"); + /* If focus didn't actually move anywhere, there is nothing to do*/ + nomove = TRUE; + } else if (ce.xfocus.detail == NotifyPointerRoot || + ce.xfocus.detail == NotifyDetailNone || + ce.xfocus.detail == NotifyInferior) { + ob_debug_type(OB_DEBUG_FOCUS, "Focus went to root\n"); + /* Focus has been reverted to the root window or nothing + FocusOut events come after UnmapNotify, so we don't need to + worry about focusing an invalid window + */ + focus_fallback(TRUE); + } 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_type(OB_DEBUG_FOCUS, + "Focus went to an unmanaged window 0x%x !\n", + ce.xfocus.window); + focus_fallback(TRUE); + } + } + + if (client && !nomove) { + frame_adjust_focus(client->frame, FALSE); + /* focus_set_client has already been called for sure */ + client_calc_layer(client); + } } else if (group) event_handle_group(group, e); else if (client) @@ -517,6 +553,15 @@ static void event_process(const XEvent *ec, gpointer data) e->xconfigurerequest.value_mask, &xwc); xerror_set_ignore(FALSE); } +#ifdef SYNC + else if (extensions_sync && + e->type == extensions_sync_event_basep + XSyncAlarmNotify) + { + XSyncAlarmNotifyEvent *se = (XSyncAlarmNotifyEvent*)e; + if (se->alarm == moveresize_alarm && moveresize_in_progress) + moveresize_event(e); + } +#endif /* user input (action-bound) events */ if (e->type == ButtonPress || e->type == ButtonRelease || @@ -542,12 +587,11 @@ static void event_process(const XEvent *ec, gpointer data) NULL, g_direct_equal, NULL); if (e->type == ButtonPress || e->type == ButtonRelease || - e->type == MotionNotify) + 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); + (client ? client : focus_client)), e); } } } @@ -653,9 +697,6 @@ static void event_handle_client(ObClient *client, XEvent *e) ObFrameContext con; switch (e->type) { - case VisibilityNotify: - client->frame->obscured = e->xvisibility.state != VisibilityUnobscured; - break; case ButtonPress: case ButtonRelease: /* Wheel buttons don't draw because they are an instant click, so it @@ -690,53 +731,6 @@ static void event_handle_client(ObClient *client, XEvent *e) } } break; - case FocusIn: - if (client != focus_client) { - focus_set_client(client); - frame_adjust_focus(client->frame, TRUE); - client_calc_layer(client); - } - break; - case FocusOut: - /* 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_type(OB_DEBUG_FOCUS, "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_type(OB_DEBUG_FOCUS, "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_type(OB_DEBUG_FOCUS, "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_type(OB_DEBUG_FOCUS, - "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); switch (con) { @@ -761,10 +755,23 @@ static void event_handle_client(ObClient *client, XEvent *e) frame_adjust_state(client->frame); break; case OB_FRAME_CONTEXT_FRAME: - if (config_focus_follow && config_focus_delay) + ob_debug_type(OB_DEBUG_FOCUS, + "%sNotify mode %d detail %d on %lx\n", + (e->type == EnterNotify ? "Enter" : "Leave"), + e->xcrossing.mode, + e->xcrossing.detail, (client?client->window:0)); + if (keyboard_interactively_grabbed()) + break; + if (config_focus_follow && config_focus_delay && + /* leave inferior events can happen when the mouse goes onto + the window's border and then into the window before the + delay is up */ + e->xcrossing.detail != NotifyInferior) + { ob_main_loop_timeout_remove_data(ob_main_loop, focus_delay_func, client, FALSE); + } break; default: break; @@ -802,8 +809,12 @@ static void event_handle_client(ObClient *client, XEvent *e) frame_adjust_state(client->frame); break; case OB_FRAME_CONTEXT_FRAME: + if (keyboard_interactively_grabbed()) + break; if (e->xcrossing.mode == NotifyGrab || - e->xcrossing.mode == NotifyUngrab) + e->xcrossing.mode == NotifyUngrab || + /*ignore enters when we're already in the window */ + e->xcrossing.detail == NotifyInferior) { ob_debug_type(OB_DEBUG_FOCUS, "%sNotify mode %d detail %d on %lx IGNORED\n", @@ -1188,9 +1199,17 @@ static void event_handle_client(ObClient *client, XEvent *e) else if (msgtype == prop_atoms.net_wm_user_time) { client_update_user_time(client); } +#ifdef SYNC + else if (msgtype == prop_atoms.net_wm_sync_request_counter) { + client_update_sync_request_counter(client); + } +#endif else if (msgtype == prop_atoms.sm_client_id) { client_update_sm_client_id(client); } + case ColormapNotify: + client_update_colormap(client, e->xcolormap.colormap); + break; default: ; #ifdef SHAPE @@ -1245,7 +1264,7 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e) } } -ObMenuFrame* find_active_menu() +static ObMenuFrame* find_active_menu() { GList *it; ObMenuFrame *ret = NULL; @@ -1259,7 +1278,7 @@ ObMenuFrame* find_active_menu() return ret; } -ObMenuFrame* find_active_or_last_menu() +static ObMenuFrame* find_active_or_last_menu() { ObMenuFrame *ret = NULL; @@ -1269,6 +1288,77 @@ ObMenuFrame* find_active_or_last_menu() return ret; } +static void event_handle_menu_shortcut(XEvent *ev) +{ + gunichar unikey = 0; + ObMenuFrame *frame; + GList *start; + GList *it; + ObMenuEntryFrame *found = NULL; + guint num_found = 0; + + { + const char *key; + if ((key = translate_keycode(ev->xkey.keycode)) == NULL) + return; + unikey = g_utf8_get_char_validated(key, -1); + if (unikey == (gunichar)-1 || unikey == (gunichar)-2 || unikey == 0) + return; + } + + if ((frame = find_active_or_last_menu()) == NULL) + return; + + + if (!frame->entries) + return; /* nothing in the menu anyways */ + + /* 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; + } + + it = start; + do { + ObMenuEntryFrame *e = it->data; + gunichar entrykey = 0; + + 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; + + 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); + menu_entry_frame_execute(found, ev->xkey.state, + ev->xkey.time); + } else { + menu_frame_select(frame, found, TRUE); + if (num_found == 1) + menu_frame_select_next(frame->child); + } + } +} + static void event_handle_menu(XEvent *ev) { ObMenuFrame *f; @@ -1290,7 +1380,7 @@ static void event_handle_menu(XEvent *ev) if (e->ignore_enters) --e->ignore_enters; else - menu_frame_select(e->frame, e); + menu_frame_select(e->frame, e, FALSE); } break; case LeaveNotify: @@ -1298,28 +1388,35 @@ static void event_handle_menu(XEvent *ev) (f = find_active_menu()) && f->selected == e && e->entry->type != OB_MENU_ENTRY_TYPE_SUBMENU) { - menu_frame_select(e->frame, NULL); + menu_frame_select(e->frame, NULL, FALSE); } case MotionNotify: if ((e = menu_entry_frame_under(ev->xmotion.x_root, ev->xmotion.y_root))) - menu_frame_select(e->frame, e); + menu_frame_select(e->frame, e, FALSE); break; case KeyPress: if (ev->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) - menu_frame_hide_all(); + if ((f = find_active_or_last_menu()) && f->parent) + menu_frame_select(f, NULL, TRUE); + else + menu_frame_hide_all(); 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, - ev->xkey.time); + if ((f = find_active_menu())) { + if (f->child) + menu_frame_select_next(f->child); + else + 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) - menu_frame_select(f, NULL); + if ((f = find_active_or_last_menu())) + menu_frame_select(f, NULL, TRUE); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) { ObMenuFrame *f; - if ((f = find_active_or_last_menu()) && f->child) + if ((f = find_active_menu()) && f->child) menu_frame_select_next(f->child); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_UP)) { ObMenuFrame *f; @@ -1329,7 +1426,8 @@ static void event_handle_menu(XEvent *ev) ObMenuFrame *f; if ((f = find_active_or_last_menu())) menu_frame_select_next(f); - } + } else + event_handle_menu_shortcut(ev); break; } } @@ -1347,8 +1445,8 @@ static void focus_delay_dest(gpointer data) static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2) { - const ObFocusDelayData *f1 = d1, *f2 = d2; - return f1->client == f2->client; + const ObFocusDelayData *f1 = d1; + return f1->client == d2; } static gboolean focus_delay_func(gpointer data) @@ -1371,12 +1469,6 @@ static void focus_delay_client_dest(ObClient *client, gpointer data) client, FALSE); } -static void event_client_dest(ObClient *client, gpointer data) -{ - if (client == focus_hilite) - focus_hilite = NULL; -} - void event_halt_focus_delay() { ob_main_loop_timeout_remove(ob_main_loop, focus_delay_func);