]> Dogcows Code - chaz/openbox/blobdiff - openbox/event.c
make keeping windows on screen much more clever
[chaz/openbox] / openbox / event.c
index 759c2e22695412926f9b5eeffa45f0acb9ec585b..6b7f4c532c77eff1f624e8a7f69429b2715abe0f 100644 (file)
@@ -39,6 +39,7 @@
 #include "group.h"
 #include "stacking.h"
 #include "extensions.h"
+#include "translate.h"
 
 #include <X11/Xlib.h>
 #include <X11/keysym.h>
@@ -51,6 +52,9 @@
 #ifdef HAVE_SIGNAL_H
 #  include <signal.h>
 #endif
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h> /* for usleep() */
+#endif
 #ifdef XKB
 #  include <X11/XKBlib.h>
 #endif
@@ -72,6 +76,7 @@ typedef struct
 
 static void event_process(const XEvent *e, 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);
@@ -211,6 +216,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;
     }
@@ -244,6 +256,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;
@@ -537,6 +556,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 ||
@@ -566,7 +594,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);
                 }
             }
         }
@@ -738,9 +766,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,
@@ -787,7 +815,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",
@@ -843,7 +873,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;
@@ -857,44 +886,8 @@ 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;
-            }
-
-            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) {
@@ -1056,13 +1049,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];
@@ -1080,27 +1072,10 @@ 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;
+            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:
@@ -1172,9 +1147,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
@@ -1229,7 +1212,7 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e)
     }
 }
 
-ObMenuFrame* find_active_menu()
+static ObMenuFrame* find_active_menu()
 {
     GList *it;
     ObMenuFrame *ret = NULL;
@@ -1243,7 +1226,7 @@ ObMenuFrame* find_active_menu()
     return ret;
 }
 
-ObMenuFrame* find_active_or_last_menu()
+static ObMenuFrame* find_active_or_last_menu()
 {
     ObMenuFrame *ret = NULL;
 
@@ -1253,6 +1236,81 @@ 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;
+        /* don't accept keys that aren't a single letter, like "space" */
+        if (key[1] != '\0')
+            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 &&
+            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, 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;
@@ -1274,7 +1332,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:
@@ -1282,28 +1340,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;
@@ -1313,7 +1378,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;
     }
 }
This page took 0.03437 seconds and 4 git commands to generate.