X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fevent.c;h=efef0faa3e1f7c97c5f45f65f436aab9474d0932;hb=9a9e3f6bf6be75094636e37d54fb16e4456b43be;hp=2d807aae23fc7c755431b306882a50a76b910a7a;hpb=ad852b6b56e43bdd7dda1389f54051cf92c0fad9;p=chaz%2Fopenbox diff --git a/openbox/event.c b/openbox/event.c index 2d807aae..efef0faa 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -31,6 +31,7 @@ #include "menu.h" #include "menuframe.h" #include "keyboard.h" +#include "modkeys.h" #include "mouse.h" #include "mainloop.h" #include "framerender.h" @@ -39,6 +40,7 @@ #include "group.h" #include "stacking.h" #include "extensions.h" +#include "translate.h" #include #include @@ -51,6 +53,9 @@ #ifdef HAVE_SIGNAL_H # include #endif +#ifdef HAVE_UNISTD_H +# include /* for usleep() */ +#endif #ifdef XKB # include #endif @@ -72,7 +77,8 @@ typedef struct static void event_process(const XEvent *e, gpointer data); static void event_handle_root(XEvent *e); -static void event_handle_menu(XEvent *e); +static gboolean event_handle_menu_keyboard(XEvent *e); +static gboolean 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); @@ -88,22 +94,9 @@ static gboolean menu_hide_delay_func(gpointer data); /* The time for the current event being processed */ Time event_curtime = CurrentTime; -/*! The value of the mask for the NumLock modifier */ -guint NumLockMask; -/*! The value of the mask for the ScrollLock modifier */ -guint ScrollLockMask; -/*! The key codes for the modifier keys */ -static XModifierKeymap *modmap; -/*! Table of the constant modifier masks */ -static const gint mask_table[] = { - ShiftMask, LockMask, ControlMask, Mod1Mask, - Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask -}; -static gint mask_table_size; - static guint ignore_enter_focus = 0; - static gboolean menu_can_hide; +static gboolean focus_left_screen = FALSE; #ifdef USE_SM static void ice_handler(gint fd, gpointer conn) @@ -131,31 +124,6 @@ void event_startup(gboolean reconfig) { if (reconfig) return; - mask_table_size = sizeof(mask_table) / sizeof(mask_table[0]); - - /* get lock masks that are defined by the display (not constant) */ - modmap = XGetModifierMapping(ob_display); - g_assert(modmap); - if (modmap && modmap->max_keypermod > 0) { - size_t cnt; - const size_t size = mask_table_size * modmap->max_keypermod; - /* get the values of the keyboard lock modifiers - Note: Caps lock is not retrieved the same way as Scroll and Num - lock since it doesn't need to be. */ - 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]) - ScrollLockMask = mask_table[cnt / modmap->max_keypermod]; - } - } - ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL); #ifdef USE_SM @@ -174,7 +142,6 @@ void event_shutdown(gboolean reconfig) #endif client_remove_destructor(focus_delay_client_dest); - XFreeModifiermap(modmap); } static Window event_get_window(XEvent *e) @@ -266,54 +233,34 @@ static void event_set_curtime(XEvent *e) event_curtime = t; } -#define STRIP_MODS(s) \ - 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; switch (e->type) { case ButtonPress: case ButtonRelease: - STRIP_MODS(e->xbutton.state); + e->xbutton.state = modkeys_only_modifier_masks(e->xbutton.state); break; case KeyPress: - STRIP_MODS(e->xkey.state); + e->xkey.state = modkeys_only_modifier_masks(e->xkey.state); break; case KeyRelease: - 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..) */ + e->xkey.state = modkeys_only_modifier_masks(e->xkey.state); #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) { - if (*kp == e->xkey.keycode) { /* found the keycode */ - /* remove the mask for it */ - e->xkey.state &= ~mask_table[i]; - /* cause the first loop to break; */ - i = mask_table_size; - break; /* get outta here! */ - } - ++kp; - } - } + /* 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: - STRIP_MODS(e->xmotion.state); + e->xmotion.state = modkeys_only_modifier_masks(e->xmotion.state); /* compress events */ { XEvent ce; @@ -469,7 +416,23 @@ 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) { + if (e->xfocus.detail == NotifyPointerRoot || + e->xfocus.detail == NotifyDetailNone) + { + ob_debug_type(OB_DEBUG_FOCUS, "Focus went to pointer root/none\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 + */ + if (!focus_left_screen) + focus_fallback(TRUE); + } else if (e->xfocus.detail == NotifyInferior) { + ob_debug_type(OB_DEBUG_FOCUS, + "Focus went to root or our frame window"); + /* Focus has been given to the root window. */ + focus_fallback(TRUE); + } else if (client && client != focus_client) { + focus_left_screen = FALSE; frame_adjust_focus(client->frame, TRUE); focus_set_client(client); client_calc_layer(client); @@ -484,22 +447,28 @@ static void event_process(const XEvent *ec, gpointer data) 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"); + Window win, root; + gint i; + guint u; + xerror_set_ignore(TRUE); + if (XGetInputFocus(ob_display, &win, &i) != 0 && + XGetGeometry(ob_display, win, &root, &i,&i,&u,&u,&u,&u) != 0 && + root != RootWindow(ob_display, ob_screen)) + { + ob_debug_type(OB_DEBUG_FOCUS, + "Focus went to another screen !\n"); + focus_left_screen = TRUE; + } + else + ob_debug_type(OB_DEBUG_FOCUS, + "Focus went to a black hole !\n"); + xerror_set_ignore(FALSE); /* 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 }; @@ -566,17 +535,27 @@ static void event_process(const XEvent *ec, gpointer data) e->type == MotionNotify || e->type == KeyPress || e->type == KeyRelease) { - if (menu_frame_visible) - event_handle_menu(e); - else { - if (!keyboard_process_interactive_grab(e, &client)) { - if (moveresize_in_progress) { - moveresize_event(e); + gboolean useevent = TRUE; + + if (menu_frame_visible) { + if (event_handle_menu(e)) + /* don't use the event if the menu used it, but if the menu + didn't use it and it's a keypress that is bound, it will + close the menu and be used */ + useevent = FALSE; + } + if (useevent) { + /* if the keyboard interactive action uses the event then dont + use it for bindings. likewise is moveresize uses the event. */ + if (!keyboard_process_interactive_grab(e, &client) && + !(moveresize_in_progress && moveresize_event(e))) + { + if (moveresize_in_progress) /* 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, @@ -589,7 +568,7 @@ static void event_process(const XEvent *ec, gpointer data) mouse_event(client, e); } else if (e->type == KeyPress) { keyboard_event((focus_cycle_target ? focus_cycle_target : - client), e); + (client ? client : focus_client)), e); } } } @@ -761,9 +740,9 @@ static void event_handle_client(ObClient *client, XEvent *e) if (keyboard_interactively_grabbed()) break; if (config_focus_follow && config_focus_delay && - /* leaveinferior events can happen when the mouse goes onto the - window's border and then into the window before the delay - is up */ + /* 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, @@ -810,7 +789,9 @@ static void event_handle_client(ObClient *client, XEvent *e) 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", @@ -866,7 +847,6 @@ static void event_handle_client(ObClient *client, XEvent *e) CWX | CWY | CWBorderWidth)) { gint x, y, w, h; - ObCorner corner; if (e->xconfigurerequest.value_mask & CWBorderWidth) client->border_width = e->xconfigurerequest.border_width; @@ -880,44 +860,12 @@ static void event_handle_client(ObClient *client, XEvent *e) h = (e->xconfigurerequest.value_mask & CWHeight) ? e->xconfigurerequest.height : client->area.height; - { - gint newx = x; - gint newy = y; - gint fw = w + - 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, - !moving); - if (e->xconfigurerequest.value_mask & CWX) - x = newx; - if (e->xconfigurerequest.value_mask & CWY) - y = newy; - } + ob_debug("ConfigureRequest x %d %d y %d %d\n", + e->xconfigurerequest.value_mask & CWX, x, + e->xconfigurerequest.value_mask & CWY, y); - switch (client->gravity) { - case NorthEastGravity: - case EastGravity: - corner = OB_CORNER_TOPRIGHT; - break; - case SouthWestGravity: - case SouthGravity: - corner = OB_CORNER_BOTTOMLEFT; - break; - case SouthEastGravity: - corner = OB_CORNER_BOTTOMRIGHT; - break; - default: /* NorthWest, Static, etc */ - corner = OB_CORNER_TOPLEFT; - } - - client_configure_full(client, corner, x, y, w, h, FALSE, TRUE, - TRUE); + client_find_onscreen(client, &x, &y, w, h, FALSE); + client_configure_full(client, x, y, w, h, FALSE, TRUE, TRUE); } if (e->xconfigurerequest.value_mask & CWStackMode) { @@ -1079,13 +1027,12 @@ static void event_handle_client(ObClient *client, XEvent *e) 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; + gint grav, x, y, w, h; if (e->xclient.data.l[0] & 0xff) - tmpg = e->xclient.data.l[0] & 0xff; - else - tmpg = oldg; + grav = e->xclient.data.l[0] & 0xff; + else + grav = client->gravity; if (e->xclient.data.l[0] & 1 << 8) x = e->xclient.data.l[1]; @@ -1103,27 +1050,13 @@ static void event_handle_client(ObClient *client, XEvent *e) h = e->xclient.data.l[4]; else h = client->area.height; - client->gravity = tmpg; - { - gint newx = x; - gint newy = y; - gint fw = w + - client->frame->size.left + client->frame->size.right; - gint fh = h + - client->frame->size.top + client->frame->size.bottom; - client_find_onscreen(client, &newx, &newy, fw, fh, - client_normal(client)); - if (e->xclient.data.l[0] & 1 << 8) - x = newx; - if (e->xclient.data.l[0] & 1 << 9) - y = newy; - } - - client_configure(client, OB_CORNER_TOPLEFT, - x, y, w, h, FALSE, TRUE); - - client->gravity = oldg; + ob_debug("MOVERESIZE x %d %d y %d %d\n", + e->xclient.data.l[0] & 1 << 8, x, + e->xclient.data.l[0] & 1 << 9, y); + client_convert_gravity(client, grav, &x, &y, w, h); + client_find_onscreen(client, &x, &y, w, h, FALSE); + client_configure(client, x, y, w, h, FALSE, TRUE); } break; case PropertyNotify: @@ -1260,7 +1193,7 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e) } } -ObMenuFrame* find_active_menu() +static ObMenuFrame* find_active_menu() { GList *it; ObMenuFrame *ret = NULL; @@ -1274,7 +1207,7 @@ ObMenuFrame* find_active_menu() return ret; } -ObMenuFrame* find_active_or_last_menu() +static ObMenuFrame* find_active_or_last_menu() { ObMenuFrame *ret = NULL; @@ -1284,14 +1217,130 @@ ObMenuFrame* find_active_or_last_menu() return ret; } -static void event_handle_menu(XEvent *ev) +static gboolean event_handle_menu_keyboard(XEvent *ev) +{ + guint keycode, state; + gunichar unikey; + ObMenuFrame *frame; + gboolean ret = TRUE; + + keycode = ev->xkey.keycode; + state = ev->xkey.state; + unikey = translate_unichar(keycode); + + frame = find_active_or_last_menu(); + if (frame == NULL) + ret = FALSE; + + else if (keycode == ob_keycode(OB_KEY_ESCAPE) && state == 0) { + /* Escape closes the active menu */ + menu_frame_hide(frame); + } + + else if (keycode == ob_keycode(OB_KEY_RETURN) && (state == 0 || + state == ControlMask)) + { + /* Enter runs the active item or goes into the submenu. + Control-Enter runs it without closing the menu. */ + if (frame->child) + menu_frame_select_next(frame->child); + else + menu_entry_frame_execute(frame->selected, state, ev->xkey.time); + } + + else if (keycode == ob_keycode(OB_KEY_LEFT) && ev->xkey.state == 0) { + /* Left goes to the parent menu */ + menu_frame_select(frame, NULL, TRUE); + } + + else if (keycode == ob_keycode(OB_KEY_RIGHT) && ev->xkey.state == 0) { + /* Right goes to the selected submenu */ + if (frame->child) menu_frame_select_next(frame->child); + } + + else if (keycode == ob_keycode(OB_KEY_UP) && state == 0) { + menu_frame_select_previous(frame); + } + + else if (keycode == ob_keycode(OB_KEY_DOWN) && state == 0) { + menu_frame_select_next(frame); + } + + /* keyboard accelerator shortcuts. */ + else if (ev->xkey.state == 0 && + /* was it a valid key? */ + unikey != 0 && + /* don't bother if the menu is empty. */ + frame->entries) + { + GList *start; + GList *it; + ObMenuEntryFrame *found = NULL; + guint num_found = 0; + + /* 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 && + e->entry->data.normal.enabled) + 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, state, ev->xkey.time); + } else { + menu_frame_select(frame, found, TRUE); + if (num_found == 1) + menu_frame_select_next(frame->child); + } + } else + ret = FALSE; + } + else + ret = FALSE; + + return ret; +} + +static gboolean event_handle_menu(XEvent *ev) { ObMenuFrame *f; ObMenuEntryFrame *e; + gboolean ret = TRUE; switch (ev->type) { case ButtonRelease: - if (menu_can_hide) { + if ((ev->xbutton.button < 4 || ev->xbutton.button > 5) + && 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, @@ -1305,7 +1354,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: @@ -1313,40 +1362,18 @@ 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(); - 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); - } 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); - } else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) { - ObMenuFrame *f; - 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_or_last_menu())) - menu_frame_select_previous(f); - } else if (ev->xkey.keycode == ob_keycode(OB_KEY_DOWN)) { - ObMenuFrame *f; - if ((f = find_active_or_last_menu())) - menu_frame_select_next(f); - } + ret = event_handle_menu_keyboard(ev); break; } + return ret; } static gboolean menu_hide_delay_func(gpointer data)