]> Dogcows Code - chaz/openbox/blobdiff - openbox/event.c
putting events on the event queue does not send them back to the server. it was...
[chaz/openbox] / openbox / event.c
index 078eaa7f9dfcc7d0d1c50fd4ca08e7abd066a318..5e526d2342ac110f051371f5c6cc96d51b1e9ff5 100644 (file)
@@ -97,10 +97,15 @@ static gboolean focus_delay_func(gpointer data);
 static gboolean unfocus_delay_func(gpointer data);
 static void focus_delay_client_dest(ObClient *client, gpointer data);
 
-Time event_curtime = CurrentTime;
-Time event_last_user_time = CurrentTime;
-/*! The serial of the current X event */
+Time event_last_user_time;
+
+/*! The time of the current X event (if it had a timestamp) */
+static Time event_curtime;
+/*! The source time that started the current X event (user-provided, so not
+  to be trusted) */
+static Time event_sourcetime;
 
+/*! The serial of the current X event */
 static gulong event_curserial;
 static gboolean focus_left_screen = FALSE;
 /*! A list of ObSerialRanges which are to be ignored for mouse enter events */
@@ -139,6 +144,10 @@ void event_startup(gboolean reconfig)
 #endif
 
     client_add_destroy_notify(focus_delay_client_dest, NULL);
+
+    event_curtime = CurrentTime;
+    event_sourcetime = CurrentTime;
+    event_last_user_time = CurrentTime;
 }
 
 void event_shutdown(gboolean reconfig)
@@ -207,7 +216,7 @@ static Window event_get_window(XEvent *e)
     return window;
 }
 
-static void event_set_curtime(XEvent *e)
+static inline Time event_get_timestamp(const XEvent *e)
 {
     Time t = CurrentTime;
 
@@ -238,7 +247,7 @@ static void event_set_curtime(XEvent *e)
         if (obt_display_extension_sync &&
             e->type == obt_display_extension_sync_basep + XSyncAlarmNotify)
         {
-            t = ((XSyncAlarmNotifyEvent*)e)->time;
+            t = ((const XSyncAlarmNotifyEvent*)e)->time;
         }
 #endif
         /* if more event types are anticipated, get their timestamp
@@ -246,12 +255,20 @@ static void event_set_curtime(XEvent *e)
         break;
     }
 
+    return t;
+}
+
+static void event_set_curtime(XEvent *e)
+{
+    Time t = event_get_timestamp(e);
+
     /* watch that if we get an event earlier than the last specified user_time,
        which can happen if the clock goes backwards, we erase the last
        specified user_time */
     if (t && event_last_user_time && event_time_after(event_last_user_time, t))
         event_last_user_time = CurrentTime;
 
+    event_sourcetime = CurrentTime;
     event_curtime = t;
 }
 
@@ -263,18 +280,8 @@ static void event_hack_mods(XEvent *e)
         e->xbutton.state = obt_keyboard_only_modmasks(e->xbutton.state);
         break;
     case KeyPress:
-        e->xkey.state = obt_keyboard_only_modmasks(e->xkey.state);
         break;
     case KeyRelease:
-#ifdef XKB
-        /* keep only the keyboard modifiers.  xkb includes other things here.
-           (see XKBProto.pdf document: section 2.2.2) */
-        e->xkey.state &= 0xf;
-#endif
-        e->xkey.state = obt_keyboard_only_modmasks(e->xkey.state);
-        /* 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 &= ~obt_keyboard_keycode_to_modmask(e->xkey.keycode);
         break;
     case MotionNotify:
         e->xmotion.state = obt_keyboard_only_modmasks(e->xmotion.state);
@@ -739,7 +746,7 @@ static void event_process(const XEvent *ec, gpointer data)
 
     /* if something happens and it's not from an XEvent, then we don't know
        the time */
-    event_curtime = CurrentTime;
+    event_curtime = event_sourcetime = CurrentTime;
     event_curserial = 0;
 }
 
@@ -760,11 +767,12 @@ static void event_handle_root(XEvent *e)
         if (msgtype == OBT_PROP_ATOM(NET_CURRENT_DESKTOP)) {
             guint d = e->xclient.data.l[0];
             if (d < screen_num_desktops) {
-                event_curtime = e->xclient.data.l[1];
-                if (event_curtime == 0)
+                if (e->xclient.data.l[1] == 0)
                     ob_debug_type(OB_DEBUG_APP_BUGS,
                                   "_NET_CURRENT_DESKTOP message is missing "
                                   "a timestamp");
+                else
+                    event_sourcetime = e->xclient.data.l[1];
                 screen_set_desktop(d, TRUE);
             }
         } else if (msgtype == OBT_PROP_ATOM(NET_NUMBER_OF_DESKTOPS)) {
@@ -821,9 +829,9 @@ void event_enter_client(ObClient *client)
 
             obt_main_loop_timeout_remove(ob_main_loop, focus_delay_func);
 
-            data = g_new(ObFocusDelayData, 1);
+            data = g_slice_new(ObFocusDelayData);
             data->client = client;
-            data->time = event_curtime;
+            data->time = event_time();
             data->serial = event_curserial;
 
             obt_main_loop_timeout_add(ob_main_loop,
@@ -833,7 +841,7 @@ void event_enter_client(ObClient *client)
         } else {
             ObFocusDelayData data;
             data.client = client;
-            data.time = event_curtime;
+            data.time = event_time();
             data.serial = event_curserial;
             focus_delay_func(&data);
         }
@@ -856,9 +864,9 @@ void event_leave_client(ObClient *client)
 
             obt_main_loop_timeout_remove(ob_main_loop, unfocus_delay_func);
 
-            data = g_new(ObFocusDelayData, 1);
+            data = g_slice_new(ObFocusDelayData);
             data->client = client;
-            data->time = event_curtime;
+            data->time = event_time();
             data->serial = event_curserial;
 
             obt_main_loop_timeout_add(ob_main_loop,
@@ -868,7 +876,7 @@ void event_leave_client(ObClient *client)
         } else {
             ObFocusDelayData data;
             data.client = client;
-            data.time = event_curtime;
+            data.time = event_time();
             data.serial = event_curserial;
             unfocus_delay_func(&data);
         }
@@ -1257,6 +1265,44 @@ static void event_handle_client(ObClient *client, XEvent *e)
                notify is sent or not */
         }
 
+        /* check for broken apps (java swing) moving to 0,0 when there is a
+           strut there.
+
+           XXX remove this some day...that would be nice. but really unexpected
+           from Sun Microsystems.
+        */
+        if (x == 0 && y == 0 && client->gravity == NorthWestGravity &&
+            client_normal(client))
+        {
+            const Rect to = { x, y, w, h };
+
+            /* oldschool fullscreen windows are allowed */
+            if (!client_is_oldfullscreen(client, &to)) {
+                Rect *r;
+
+                r = screen_area(client->desktop, SCREEN_AREA_ALL_MONITORS,
+                                NULL);
+                if (r->x || r->y) {
+                    /* move the window only to the corner outside struts */
+                    x = r->x;
+                    y = r->y;
+
+                    ob_debug_type(OB_DEBUG_APP_BUGS,
+                                  "Application %s is trying to move via "
+                                  "ConfigureRequest to 0,0 using "
+                                  "NorthWestGravity, while there is a "
+                                  "strut there. "
+                                  "Moving buggy app from (0,0) to (%d,%d)",
+                                  client->title, r->x, r->y);
+                }
+
+                g_slice_free(Rect, r);
+
+                /* they still requested a move, so don't change whether a
+                   notify is sent or not */
+            }
+        }
+
         {
             gint lw, lh;
 
@@ -1306,10 +1352,6 @@ static void event_handle_client(ObClient *client, XEvent *e)
           to an already unmapped window.
         */
 
-        /* we don't want the reparent event, put it back on the stack for the
-           X server to deal with after we unmanage the window */
-        XPutBackEvent(obt_display, e);
-
         ob_debug("ReparentNotify for window 0x%x", client->window);
         client_unmanage(client);
         break;
@@ -1367,7 +1409,17 @@ static void event_handle_client(ObClient *client, XEvent *e)
                        (e->xclient.data.l[0] == 2 ? "user" : "INVALID"))));
             /* XXX make use of data.l[2] !? */
             if (e->xclient.data.l[0] == 1 || e->xclient.data.l[0] == 2) {
-                event_curtime = e->xclient.data.l[1];
+                /* we can not trust the timestamp from applications.
+                   e.g. chromium passes a very old timestamp.  openbox thinks
+                   the window will get focus and calls XSetInputFocus with the
+                   (old) timestamp, which doesn't end up moving focus at all.
+                   but the window is raised, not hilited, etc, as if it was
+                   really going to get focus.
+
+                   so do not use this timestamp in event_curtime, as this would
+                   be used in XSetInputFocus.
+                */
+                event_sourcetime = e->xclient.data.l[1];
                 if (e->xclient.data.l[1] == 0)
                     ob_debug_type(OB_DEBUG_APP_BUGS,
                                   "_NET_ACTIVE_WINDOW message for window %s is"
@@ -1582,8 +1634,11 @@ static void event_handle_client(ObClient *client, XEvent *e)
         } else if (msgtype == XA_WM_HINTS) {
             client_update_wmhints(client);
         } else if (msgtype == XA_WM_TRANSIENT_FOR) {
-            client_update_transient_for(client);
+            /* get the transient-ness first, as this affects if the client
+               decides to be transient for the group or not in
+               client_update_transient_for() */
             client_get_type_and_transientness(client);
+            client_update_transient_for(client);
             /* type may have changed, so update the layer */
             client_calc_layer(client);
             client_setup_decor_and_functions(client, TRUE);
@@ -1773,28 +1828,33 @@ static gboolean event_handle_menu_input(XEvent *ev)
                 menu_frame_select(e->frame, e, FALSE);
     }
     else if (ev->type == KeyPress || ev->type == KeyRelease) {
-        guint keycode, state;
-        gunichar unikey;
+        guint mods;
         ObMenuFrame *frame;
 
-        keycode = ev->xkey.keycode;
-        state = ev->xkey.state;
-        unikey = obt_keyboard_keycode_to_unichar(keycode);
+        /* get the modifiers */
+        mods = obt_keyboard_only_modmasks(ev->xkey.state);
 
         frame = find_active_or_last_menu();
         if (frame == NULL)
             g_assert_not_reached(); /* there is no active menu */
 
         /* Allow control while going thru the menu */
-        else if (ev->type == KeyPress && (state & ~ControlMask) == 0) {
+        else if (ev->type == KeyPress && (mods & ~ControlMask) == 0) {
+            gunichar unikey;
+            KeySym sym;
+
             frame->got_press = TRUE;
+            frame->press_keycode = ev->xkey.keycode;
+            frame->press_doexec = FALSE;
+
+            sym = obt_keyboard_keypress_to_keysym(ev);
 
-            if (ob_keycode_match(keycode, OB_KEY_ESCAPE)) {
+            if (sym == XK_Escape) {
                 menu_frame_hide_all();
                 ret = TRUE;
             }
 
-            else if (ob_keycode_match(keycode, OB_KEY_LEFT)) {
+            else if (sym == XK_Left) {
                 /* Left goes to the parent menu */
                 if (frame->parent) {
                     /* remove focus from the child */
@@ -1806,7 +1866,7 @@ static gboolean event_handle_menu_input(XEvent *ev)
                 ret = TRUE;
             }
 
-            else if (ob_keycode_match(keycode, OB_KEY_RIGHT)) {
+            else if (sym == XK_Right) {
                 /* Right goes to the selected submenu */
                 if (frame->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
                 {
@@ -1817,47 +1877,37 @@ static gboolean event_handle_menu_input(XEvent *ev)
                 ret = TRUE;
             }
 
-            else if (ob_keycode_match(keycode, OB_KEY_UP)) {
+            else if (sym == XK_Up) {
                 menu_frame_select_previous(frame);
                 ret = TRUE;
             }
 
-            else if (ob_keycode_match(keycode, OB_KEY_DOWN)) {
+            else if (sym == XK_Down) {
                 menu_frame_select_next(frame);
                 ret = TRUE;
             }
 
-            else if (ob_keycode_match(keycode, OB_KEY_HOME)) {
+            else if (sym == XK_Home) {
                 menu_frame_select_first(frame);
                 ret = TRUE;
             }
 
-            else if (ob_keycode_match(keycode, OB_KEY_END)) {
+            else if (sym == XK_End) {
                 menu_frame_select_last(frame);
                 ret = TRUE;
             }
-        }
-
-        /* Use KeyRelease events for running things so that the key release
-           doesn't get sent to the focused application.
-
-           Allow ControlMask only, and don't bother if the menu is empty */
-        else if (ev->type == KeyRelease && (state & ~ControlMask) == 0 &&
-                 frame->entries && frame->got_press)
-        {
-            if (ob_keycode_match(keycode, OB_KEY_RETURN)) {
-                /* 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 if (frame->selected)
-                    menu_entry_frame_execute(frame->selected, state);
 
+            else if (sym == XK_Return || sym == XK_KP_Enter) {
+                frame->press_doexec = TRUE;
                 ret = TRUE;
             }
 
             /* keyboard accelerator shortcuts. (if it was a valid key) */
-            else if (unikey != 0) {
+            else if (frame->entries &&
+                     (unikey =
+                      obt_keyboard_keypress_to_unichar(menu_frame_ic(frame),
+                                                       ev)))
+            {
                 GList *start;
                 GList *it;
                 ObMenuEntryFrame *found = NULL;
@@ -1895,23 +1945,30 @@ static gboolean event_handle_menu_input(XEvent *ev)
                 } 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); /* highlight the item for a short bit so
-                                          the user can see what happened */
-                        menu_entry_frame_execute(found, state);
-                    } else {
-                        menu_frame_select(frame, found, TRUE);
-                        if (num_found == 1)
-                            menu_frame_select_next(frame->child);
-                    }
+                    menu_frame_select(frame, found, TRUE);
 
+                    if (num_found == 1)
+                        frame->press_doexec = TRUE;
                     ret = TRUE;
                 }
             }
         }
+
+        /* Use KeyRelease events for running things so that the key release
+           doesn't get sent to the focused application.
+
+           Allow ControlMask only, and don't bother if the menu is empty */
+        else if (ev->type == KeyRelease && (mods & ~ControlMask) == 0) {
+            if (frame->press_keycode == ev->xkey.keycode &&
+                frame->got_press &&
+                frame->press_doexec)
+            {
+                if (frame->child)
+                    menu_frame_select_next(frame->child);
+                else if (frame->selected)
+                    menu_entry_frame_execute(frame->selected, ev->xkey.state);
+            }
+        }
     }
 
     return ret;
@@ -2005,7 +2062,7 @@ static gboolean event_handle_user_input(ObClient *client, XEvent *e)
 
 static void focus_delay_dest(gpointer data)
 {
-    g_free(data);
+    g_slice_free(ObFocusDelayData, data);
 }
 
 static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2)
@@ -2017,7 +2074,7 @@ static gboolean focus_delay_cmp(gconstpointer d1, gconstpointer d2)
 static gboolean focus_delay_func(gpointer data)
 {
     ObFocusDelayData *d = data;
-    Time old = event_curtime;
+    Time old = event_curtime; /* save the curtime */
 
     event_curtime = d->time;
     event_curserial = d->serial;
@@ -2030,7 +2087,7 @@ static gboolean focus_delay_func(gpointer data)
 static gboolean unfocus_delay_func(gpointer data)
 {
     ObFocusDelayData *d = data;
-    Time old = event_curtime;
+    Time old = event_curtime; /* save the curtime */
 
     event_curtime = d->time;
     event_curserial = d->serial;
@@ -2067,7 +2124,7 @@ static void event_ignore_enter_range(gulong start, gulong end)
     g_assert(start != 0);
     g_assert(end != 0);
 
-    r = g_new(ObSerialRange, 1);
+    r = g_slice_new(ObSerialRange);
     r->start = start;
     r->end = end;
     ignore_serials = g_slist_prepend(ignore_serials, r);
@@ -2102,7 +2159,7 @@ static gboolean is_enter_focus_event_ignored(gulong serial)
         if ((glong)(serial - r->end) > 0) {
             /* past the end */
             ignore_serials = g_slist_delete_link(ignore_serials, it);
-            g_free(r);
+            g_slice_free(ObSerialRange, r);
         }
         else if ((glong)(serial - r->start) >= 0)
             return TRUE;
@@ -2161,14 +2218,35 @@ gboolean event_time_after(guint32 t1, guint32 t2)
         return t1 >= t2 && t1 < (t2 + TIME_HALF);
 }
 
-Time event_get_server_time(void)
+Bool find_timestamp(Display *d, XEvent *e, XPointer a)
+{
+    const Time t = event_get_timestamp(e);
+    return t != CurrentTime;
+}
+
+Time event_time(void)
 {
-    /* Generate a timestamp */
     XEvent event;
 
+    if (event_curtime) return event_curtime;
+
+    /* Some events don't come with timestamps :(
+       ...but we can get one anyways >:) */
+
+    /* Generate a timestamp so there is guaranteed at least one in the queue
+       eventually */
     XChangeProperty(obt_display, screen_support_win,
                     OBT_PROP_ATOM(WM_CLASS), OBT_PROP_ATOM(STRING),
                     8, PropModeAppend, NULL, 0);
-    XWindowEvent(obt_display, screen_support_win, PropertyChangeMask, &event);
-    return event.xproperty.time;
+
+    /* Grab the first timestamp available */
+    XPeekIfEvent(obt_display, &event, find_timestamp, NULL);
+
+    /* Save the time so we don't have to do this again for this event */
+    return event_curtime = event.xproperty.time;
+}
+
+Time event_source_time(void)
+{
+    return event_sourcetime;
 }
This page took 0.035464 seconds and 4 git commands to generate.