]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkdisplay-x11.c
Add GdkFrameHistory and GdkFrameTimings, handle _NET_WM_FRAME_TIMINGS
[~andy/gtk] / gdk / x11 / gdkdisplay-x11.c
index ae6896c7abc5da673a76b7051d832d94173cfd27..ae4aaafb0f5cc47c79b1f2b9e14052b42994ed06 100644 (file)
@@ -17,9 +17,7 @@
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -98,13 +96,11 @@ static gboolean gdk_x11_display_translate_event (GdkEventTranslator *translator,
                                                  GdkEvent           *event,
                                                  XEvent             *xevent);
 
-#ifdef HAVE_X11R6
 static void gdk_internal_connection_watch (Display  *display,
                                           XPointer  arg,
                                           gint      fd,
                                           gboolean  opening,
                                           XPointer *watch_data);
-#endif /* HAVE_X11R6 */
 
 typedef struct _GdkEventTypeX11 GdkEventTypeX11;
 
@@ -256,6 +252,21 @@ do_net_wm_state_changes (GdkWindow *window)
                                      0,
                                      GDK_WINDOW_STATE_FOCUSED);
     }
+
+  if (old_state & GDK_WINDOW_STATE_ICONIFIED)
+    {
+      if (!toplevel->have_hidden)
+        gdk_synthesize_window_state (window,
+                                     GDK_WINDOW_STATE_ICONIFIED,
+                                     0);
+    }
+  else
+    {
+      if (toplevel->have_hidden)
+        gdk_synthesize_window_state (window,
+                                     0,
+                                     GDK_WINDOW_STATE_ICONIFIED);
+    }
 }
 
 static void
@@ -315,6 +326,7 @@ gdk_check_wm_state_changed (GdkWindow *window)
   toplevel->have_maxhorz = FALSE;
   toplevel->have_fullscreen = FALSE;
   toplevel->have_focused = FALSE;
+  toplevel->have_hidden = FALSE;
 
   type = None;
   gdk_x11_display_error_trap_push (display);
@@ -331,6 +343,7 @@ gdk_check_wm_state_changed (GdkWindow *window)
       Atom maxhorz_atom        = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_MAXIMIZED_HORZ");
       Atom fullscreen_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FULLSCREEN");
       Atom focused_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_FOCUSED");
+      Atom hidden_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_HIDDEN");
 
       atoms = (Atom *)data;
 
@@ -347,6 +360,8 @@ gdk_check_wm_state_changed (GdkWindow *window)
             toplevel->have_fullscreen = TRUE;
           else if (atoms[i] == focused_atom)
             toplevel->have_focused = TRUE;
+          else if (atoms[i] == hidden_atom)
+            toplevel->have_hidden = TRUE;
 
           ++i;
         }
@@ -367,15 +382,11 @@ gdk_check_wm_state_changed (GdkWindow *window)
     do_net_wm_state_changes (window);
 }
 
-static GdkWindow *
-get_event_window (GdkEventTranslator *translator,
-                  XEvent             *xevent)
+static Window
+get_event_xwindow (XEvent             *xevent)
 {
-  GdkDisplay *display;
   Window xwindow;
 
-  display = (GdkDisplay *) translator;
-
   switch (xevent->type)
     {
     case DestroyNotify:
@@ -390,11 +401,20 @@ get_event_window (GdkEventTranslator *translator,
     case ConfigureNotify:
       xwindow = xevent->xconfigure.window;
       break;
+    case ReparentNotify:
+      xwindow = xevent->xreparent.window;
+      break;
+    case GravityNotify:
+      xwindow = xevent->xgravity.window;
+      break;
+    case CirculateNotify:
+      xwindow = xevent->xcirculate.window;
+      break;
     default:
       xwindow = xevent->xany.window;
     }
 
-  return gdk_x11_window_lookup_for_display (display, xwindow);
+  return xwindow;
 }
 
 static gboolean
@@ -403,7 +423,9 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
                                  GdkEvent           *event,
                                  XEvent             *xevent)
 {
+  Window xwindow;
   GdkWindow *window;
+  gboolean is_substructure;
   GdkWindowImplX11 *window_impl = NULL;
   GdkScreen *screen = NULL;
   GdkX11Screen *x11_screen = NULL;
@@ -411,12 +433,20 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
   gboolean return_val;
 
-  /* Find the GdkWindow that this event relates to.
-   * Basically this means substructure events
-   * are reported same as structure events
+  /* Find the GdkWindow that this event relates to. If that's
+   * not the same as the window that the event was sent to,
+   * we are getting an event from SubstructureNotifyMask.
+   * We ignore such events for internal operation, but we
+   * need to report them to the application because of
+   * GDK_SUBSTRUCTURE_MASK (which should be removed at next
+   * opportunity.) The most likely reason for getting these
+   * events is when we are used in the Metacity or Mutter
+   * window managers.
    */
-  window = get_event_window (translator, xevent);
+  xwindow = get_event_xwindow (xevent);
+  is_substructure = xwindow != xevent->xany.window;
 
+  window = gdk_x11_window_lookup_for_display (display, xwindow);
   if (window)
     {
       /* We may receive events such as NoExpose/GraphicsExpose
@@ -445,7 +475,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
        }
     }
 
-  if (xevent->type == DestroyNotify)
+  if (xevent->type == DestroyNotify && !is_substructure)
     {
       int i, n;
 
@@ -607,8 +637,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
                g_message ("destroy notify:\twindow: %ld",
                           xevent->xdestroywindow.window));
 
-      /* Ignore DestroyNotify from SubstructureNotifyMask */
-      if (xevent->xdestroywindow.window == xevent->xdestroywindow.event)
+      if (!is_substructure)
        {
          event->any.type = GDK_DESTROY;
          event->any.window = window;
@@ -631,17 +660,36 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
       event->any.type = GDK_UNMAP;
       event->any.window = window;
 
-      /* If we are shown (not withdrawn) and get an unmap, it means we
-       * were iconified in the X sense. If we are withdrawn, and get
-       * an unmap, it means we hid the window ourselves, so we
-       * will have already flipped the iconified bit off.
-       */
-      if (window)
-        {
-          if (GDK_WINDOW_IS_MAPPED (window))
-            gdk_synthesize_window_state (window,
-                                         0,
-                                         GDK_WINDOW_STATE_ICONIFIED);
+      if (window && !is_substructure)
+       {
+          /* If the WM supports the _NET_WM_STATE_HIDDEN hint, we do not want to
+           * interpret UnmapNotify events as implying iconic state.
+           * http://bugzilla.gnome.org/show_bug.cgi?id=590726.
+           */
+          if (screen &&
+              !gdk_x11_screen_supports_net_wm_hint (screen,
+                                                    gdk_atom_intern_static_string ("_NET_WM_STATE_HIDDEN")))
+            {
+              /* If we are shown (not withdrawn) and get an unmap, it means we were
+               * iconified in the X sense. If we are withdrawn, and get an unmap, it
+               * means we hid the window ourselves, so we will have already flipped
+               * the iconified bit off.
+               */
+              if (GDK_WINDOW_IS_MAPPED (window))
+                gdk_synthesize_window_state (window,
+                                             0,
+                                             GDK_WINDOW_STATE_ICONIFIED);
+            }
+
+          if (window_impl->toplevel &&
+              window_impl->toplevel->frame_pending)
+            {
+              window_impl->toplevel->frame_pending = FALSE;
+              gdk_frame_clock_thaw (gdk_window_get_frame_clock (event->any.window));
+            }
+
+         if (toplevel)
+            gdk_window_freeze_toplevel_updates_libgtk_only (window);
 
           _gdk_x11_window_grab_check_unmap (window, xevent->xany.serial);
         }
@@ -656,11 +704,17 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
       event->any.type = GDK_MAP;
       event->any.window = window;
 
-      /* Unset iconified if it was set */
-      if (window && (window->state & GDK_WINDOW_STATE_ICONIFIED))
-        gdk_synthesize_window_state (window,
-                                     GDK_WINDOW_STATE_ICONIFIED,
-                                     0);
+      if (window && !is_substructure)
+       {
+         /* Unset iconified if it was set */
+         if (window->state & GDK_WINDOW_STATE_ICONIFIED)
+           gdk_synthesize_window_state (window,
+                                        GDK_WINDOW_STATE_ICONIFIED,
+                                        0);
+
+         if (toplevel)
+           gdk_window_thaw_toplevel_updates_libgtk_only (window);
+       }
 
       break;
 
@@ -706,10 +760,10 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
         }
 
 #ifdef HAVE_XSYNC
-      if (toplevel && display_x11->use_sync && !XSyncValueIsZero (toplevel->pending_counter_value))
+      if (!is_substructure && toplevel && display_x11->use_sync && toplevel->pending_counter_value != 0)
        {
-         toplevel->current_counter_value = toplevel->pending_counter_value;
-         XSyncIntToValue (&toplevel->pending_counter_value, 0);
+         toplevel->configure_counter_value = toplevel->pending_counter_value;
+         toplevel->pending_counter_value = 0;
        }
 #endif
 
@@ -751,21 +805,24 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
              event->configure.x = xevent->xconfigure.x;
              event->configure.y = xevent->xconfigure.y;
            }
-         window->x = event->configure.x;
-         window->y = event->configure.y;
-         window->width = xevent->xconfigure.width;
-         window->height = xevent->xconfigure.height;
+         if (!is_substructure)
+           {
+             window->x = event->configure.x;
+             window->y = event->configure.y;
+             window->width = xevent->xconfigure.width;
+             window->height = xevent->xconfigure.height;
 
-         _gdk_window_update_size (window);
-         _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
+             _gdk_window_update_size (window);
+             _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
 
-          if (window->resize_count >= 1)
-            {
-              window->resize_count -= 1;
+             if (window->resize_count >= 1)
+               {
+                 window->resize_count -= 1;
 
-              if (window->resize_count == 0)
-                _gdk_x11_moveresize_configure_done (display, window);
-            }
+                 if (window->resize_count == 0)
+                   _gdk_x11_moveresize_configure_done (display, window);
+               }
+           }
         }
       break;
 
@@ -999,6 +1056,26 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
   return return_val;
 }
 
+static GdkFrameTimings *
+find_frame_timings (GdkFrameClock *clock,
+                    guint64        serial)
+{
+  GdkFrameHistory *history = gdk_frame_clock_get_history (clock);
+  gint64 start_frame, end_frame, i;
+
+  start_frame = gdk_frame_history_get_start (history);
+  end_frame = gdk_frame_history_get_frame_counter (history);
+  for (i = end_frame; i >= start_frame; i--)
+    {
+      GdkFrameTimings *timings = gdk_frame_history_get_timings (history, i);
+
+      if (gdk_frame_timings_get_cookie (timings) == serial)
+        return timings;
+    }
+
+  return NULL;
+}
+
 GdkFilterReturn
 _gdk_wm_protocols_filter (GdkXEvent *xev,
                          GdkEvent  *event,
@@ -1017,6 +1094,71 @@ _gdk_wm_protocols_filter (GdkXEvent *xev,
 
   display = GDK_WINDOW_DISPLAY (win);
 
+  /* This isn't actually WM_PROTOCOLS because that wouldn't leave enough space
+   * in the message for everything that gets stuffed in */
+  if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_DRAWN"))
+    {
+      GdkWindowImplX11 *window_impl;
+      window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl);
+      if (window_impl->toplevel)
+        {
+          guint32 d0 = xevent->xclient.data.l[0];
+          guint32 d1 = xevent->xclient.data.l[1];
+          guint32 d2 = xevent->xclient.data.l[2];
+          guint32 d3 = xevent->xclient.data.l[3];
+
+          guint64 serial = ((guint64)d0 << 32) | d1;
+
+          GdkFrameClock *clock = gdk_window_get_frame_clock (event->any.window);
+          GdkFrameTimings *timings = find_frame_timings (clock, serial);
+
+          if (timings)
+            gdk_frame_timings_set_drawn_time (timings, ((guint64)d2 << 32) | d3);
+
+          if (window_impl->toplevel->frame_pending)
+            {
+              window_impl->toplevel->frame_pending = FALSE;
+              gdk_frame_clock_thaw (clock);
+            }
+        }
+
+      return GDK_FILTER_REMOVE;
+    }
+
+  if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_TIMINGS"))
+    {
+      GdkWindowImplX11 *window_impl;
+      window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl);
+      if (window_impl->toplevel)
+        {
+          guint32 d0 = xevent->xclient.data.l[0];
+          guint32 d1 = xevent->xclient.data.l[1];
+          guint32 d2 = xevent->xclient.data.l[2];
+          guint32 d3 = xevent->xclient.data.l[3];
+
+          guint64 serial = ((guint64)d0 << 32) | d1;
+
+          GdkFrameClock *clock = gdk_window_get_frame_clock (event->any.window);
+          GdkFrameTimings *timings = find_frame_timings (clock, serial);
+
+          if (timings)
+            {
+              gint64 drawn_time = gdk_frame_timings_get_drawn_time (timings);
+              gint32 presentation_time_offset = (gint32)d2;
+              gint32 refresh_interval = d3;
+
+              if (drawn_time && presentation_time_offset)
+                gdk_frame_timings_set_presentation_time (timings,
+                                                         drawn_time + presentation_time_offset);
+
+              if (refresh_interval)
+                gdk_frame_timings_set_refresh_interval (timings, refresh_interval);
+
+              gdk_frame_timings_set_complete (timings, TRUE);
+            }
+        }
+    }
+
   if (xevent->xclient.message_type != gdk_x11_get_xatom_by_name_for_display (display, "WM_PROTOCOLS"))
     return GDK_FILTER_CONTINUE;
 
@@ -1082,9 +1224,7 @@ _gdk_wm_protocols_filter (GdkXEvent *xev,
       if (toplevel)
        {
 #ifdef HAVE_XSYNC
-         XSyncIntsToValue (&toplevel->pending_counter_value,
-                           xevent->xclient.data.l[2],
-                           xevent->xclient.data.l[3]);
+         toplevel->pending_counter_value = xevent->xclient.data.l[2] + ((gint64)xevent->xclient.data.l[3] << 32);
 #endif
        }
       return GDK_FILTER_REMOVE;
@@ -1200,17 +1340,15 @@ _gdk_x11_display_open (const gchar *display_name)
   xdisplay = XOpenDisplay (display_name);
   if (!xdisplay)
     return NULL;
-  
+
   display = g_object_new (GDK_TYPE_X11_DISPLAY, NULL);
   display_x11 = GDK_X11_DISPLAY (display);
 
   display_x11->xdisplay = xdisplay;
 
-#ifdef HAVE_X11R6  
   /* Set up handlers for Xlib internal connections */
   XAddConnectionWatch (xdisplay, gdk_internal_connection_watch, NULL);
-#endif /* HAVE_X11R6 */
-  
+
   _gdk_x11_precache_atoms (display, precache_atoms, G_N_ELEMENTS (precache_atoms));
 
   /* RandR must be initialized before we initialize the screens */
@@ -1349,15 +1487,14 @@ _gdk_x11_display_open (const gchar *display_name)
     XSynchronize (display_x11->xdisplay, True);
 
   class_hint = XAllocClassHint();
-  class_hint->res_name = g_get_prgname ();
-
+  class_hint->res_name = (char *) g_get_prgname ();
   class_hint->res_class = (char *)gdk_get_program_class ();
 
   /* XmbSetWMProperties sets the RESOURCE_NAME environment variable
    * from argv[0], so we just synthesize an argument array here.
    */
   argc = 1;
-  argv[0] = g_get_prgname ();
+  argv[0] = (char *) g_get_prgname ();
 
   XmbSetWMProperties (display_x11->xdisplay,
                      display_x11->leader_window,
@@ -1439,12 +1576,10 @@ _gdk_x11_display_open (const gchar *display_name)
     _gdk_x11_screen_setup (display_x11->screens[i]);
 
   g_signal_emit_by_name (display, "opened");
-  g_signal_emit_by_name (gdk_display_manager_get (), "display-opened", display);
 
   return display;
 }
 
-#ifdef HAVE_X11R6
 /*
  * XLib internal connection handling
  */
@@ -1464,11 +1599,11 @@ process_internal_connection (GIOChannel  *gioc,
 {
   GdkInternalConnection *connection = (GdkInternalConnection *)data;
 
-  GDK_THREADS_ENTER ();
+  gdk_threads_enter ();
 
   XProcessInternalConnection ((Display*)connection->display, connection->fd);
 
-  GDK_THREADS_LEAVE ();
+  gdk_threads_leave ();
 
   return TRUE;
 }
@@ -1523,7 +1658,6 @@ gdk_internal_connection_watch (Display  *display,
   else
     gdk_remove_connection_handler ((GdkInternalConnection *)*watch_data);
 }
-#endif /* HAVE_X11R6 */
 
 static const gchar *
 gdk_x11_display_get_name (GdkDisplay *display)