]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkwindow-x11.c
Change FSF Address
[~andy/gtk] / gdk / x11 / gdkwindow-x11.c
index 1ff816efdd025f45dca35ab947225d61311f8f93..a1c3f97d2af1e3d2f5b95f088b44f1a453479607 100644 (file)
@@ -13,9 +13,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser 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/>.
  */
 
 /*
@@ -1765,7 +1763,7 @@ move_to_current_desktop (GdkWindow *window)
           xclient.format = 32;
 
           xclient.data.l[0] = *current_desktop;
-          xclient.data.l[1] = 0;
+          xclient.data.l[1] = 1; /* source indication */
           xclient.data.l[2] = 0;
           xclient.data.l[3] = 0;
           xclient.data.l[4] = 0;
@@ -1804,7 +1802,7 @@ gdk_x11_window_focus (GdkWindow *window,
       xclient.type = ClientMessage;
       xclient.window = GDK_WINDOW_XID (window);
       xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
-                                                                       "_NET_ACTIVE_WINDOW");
+                                                                    "_NET_ACTIVE_WINDOW");
       xclient.format = 32;
       xclient.data.l[0] = 1; /* requestor type; we're an app */
       xclient.data.l[1] = timestamp;
@@ -1988,7 +1986,7 @@ gdk_wmspec_change_state (gboolean   add,
   xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
   xclient.data.l[1] = gdk_x11_atom_to_xatom_for_display (display, state1);
   xclient.data.l[2] = gdk_x11_atom_to_xatom_for_display (display, state2);
-  xclient.data.l[3] = 0;
+  xclient.data.l[3] = 1; /* source indication */
   xclient.data.l[4] = 0;
   
   XSendEvent (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XROOTWIN (window), False,
@@ -3087,25 +3085,63 @@ gdk_x11_window_set_user_time (GdkWindow *window,
 }
 
 /**
- * gdk_x11_window_set_theme_variant:
+ * gdk_x11_window_set_utf8_property:
  * @window: (type GdkX11Window): a #GdkWindow
- * @variant: the theme variant to export
+ * @name: Property name, will be interned as an X atom
+ * @value: (allow-none): Property value, or %NULL to delete
  *
- * GTK+ applications can request a dark theme variant. In order to
- * make other applications - namely window managers using GTK+ for
- * themeing - aware of this choice, GTK+ uses this function to
- * export the requested theme variant as _GTK_THEME_VARIANT property
- * on toplevel windows.
+ * This function modifies or removes an arbitrary X11 window
+ * property of type UTF8_STRING.  If the given @window is
+ * not a toplevel window, it is ignored.
+ *
+ * Since: 3.4
+ */
+void
+gdk_x11_window_set_utf8_property  (GdkWindow *window,
+                                  const gchar *name,
+                                  const gchar *value)
+{
+  GdkDisplay *display;
+
+  if (!WINDOW_IS_TOPLEVEL (window))
+    return;
+
+  display = gdk_window_get_display (window);
+
+  if (value != NULL)
+    {
+      XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+                       GDK_WINDOW_XID (window),
+                       gdk_x11_get_xatom_by_name_for_display (display, name),
+                       gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+                       PropModeReplace, (guchar *)value, strlen (value));
+    }
+  else
+    {
+      XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
+                       GDK_WINDOW_XID (window),
+                       gdk_x11_get_xatom_by_name_for_display (display, name));
+    }
+}
+
+/**
+ * gdk_x11_window_set_hide_titlebar_when_maximized:
+ * @window: (type GdkX11Window): a #GdkWindow
+ * @hide_titlebar_when_maximized: whether to hide the titlebar when
+ *                                maximized
+ *
+ * Set a hint for the window manager, requesting that the titlebar
+ * should be hidden when the window is maximized.
  *
  * Note that this property is automatically updated by GTK+, so this
  * function should only be used by applications which do not use GTK+
  * to create toplevel windows.
  *
- * Since: 3.2
+ * Since: 3.4
  */
 void
-gdk_x11_window_set_theme_variant (GdkWindow *window,
-                                  char      *variant)
+gdk_x11_window_set_hide_titlebar_when_maximized (GdkWindow *window,
+                                                 gboolean   hide_titlebar_when_maximized)
 {
   GdkDisplay *display;
 
@@ -3114,22 +3150,47 @@ gdk_x11_window_set_theme_variant (GdkWindow *window,
 
   display = gdk_window_get_display (window);
 
-  if (variant != NULL)
+  if (hide_titlebar_when_maximized)
     {
+      guint32 hide = 1;
       XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
                        GDK_WINDOW_XID (window),
-                       gdk_x11_get_xatom_by_name_for_display (display, "_GTK_THEME_VARIANT"),
-                       gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
-                       PropModeReplace, (guchar *)variant, strlen (variant));
+                       gdk_x11_get_xatom_by_name_for_display (display, "_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED"),
+                       XA_CARDINAL, 32,
+                       PropModeReplace, (guchar *)&hide, 1);
     }
   else
     {
       XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
                        GDK_WINDOW_XID (window),
-                       gdk_x11_get_xatom_by_name_for_display (display, "_GTK_THEME_VARIANT"));
+                       gdk_x11_get_xatom_by_name_for_display (display, "_GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED"));
     }
 }
 
+/**
+ * gdk_x11_window_set_theme_variant:
+ * @window: (type GdkX11Window): a #GdkWindow
+ * @variant: the theme variant to export
+ *
+ * GTK+ applications can request a dark theme variant. In order to
+ * make other applications - namely window managers using GTK+ for
+ * themeing - aware of this choice, GTK+ uses this function to
+ * export the requested theme variant as _GTK_THEME_VARIANT property
+ * on toplevel windows.
+ *
+ * Note that this property is automatically updated by GTK+, so this
+ * function should only be used by applications which do not use GTK+
+ * to create toplevel windows.
+ *
+ * Since: 3.2
+ */
+void
+gdk_x11_window_set_theme_variant (GdkWindow *window,
+                                  char      *variant)
+{
+  return gdk_x11_window_set_utf8_property (window, "_GTK_THEME_VARIANT", variant);
+}
+
 #define GDK_SELECTION_MAX_SIZE(display)                                 \
   MIN(262144,                                                           \
       XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0     \
@@ -3829,17 +3890,24 @@ _gdk_x11_xwindow_get_shape (Display *xdisplay,
   shape = NULL;
   rn = 0;
 
-  xrl = XShapeGetRectangles (xdisplay,
-                            window,
-                            shape_type, &rn, &ord);
+  /* Note that XShapeGetRectangles returns NULL in two situations:
+   * - the server doesn't support the SHAPE extension
+   * - the shape is empty
+   *
+   * Since we can't discriminate these here, we always return
+   * an empty shape. It is the callers responsibility to check
+   * whether the server supports the SHAPE extensions beforehand.
+   */
+  xrl = XShapeGetRectangles (xdisplay, window, shape_type, &rn, &ord);
 
-  if (xrl == NULL || rn == 0)
+  if (rn == 0)
     return cairo_region_create (); /* Empty */
 
   if (ord != YXBanded)
     {
       /* This really shouldn't happen with any xserver, as they
-        generally convert regions to YXBanded internally */
+       * generally convert regions to YXBanded internally
+       */
       g_warning ("non YXBanded shape masks not supported");
       XFree (xrl);
       return NULL;
@@ -3854,10 +3922,10 @@ _gdk_x11_xwindow_get_shape (Display *xdisplay,
       rl[i].height = xrl[i].height;
     }
   XFree (xrl);
-  
+
   shape = cairo_region_create_rectangles (rl, rn);
   g_free (rl);
-  
+
   return shape;
 }
 
@@ -3879,7 +3947,7 @@ gdk_x11_window_get_input_shape (GdkWindow *window)
 {
 #if defined(ShapeInput)
   if (!GDK_WINDOW_DESTROYED (window) &&
-      gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
+      gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window)))
     return _gdk_x11_xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
                                        GDK_WINDOW_XID (window),
                                        ShapeInput);
@@ -3950,21 +4018,30 @@ gdk_window_x11_set_static_gravities (GdkWindow *window,
   return TRUE;
 }
 
+/* From the WM spec */
+#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
+#define _NET_WM_MOVERESIZE_SIZE_TOP          1
+#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
+#define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
+#define _NET_WM_MOVERESIZE_SIZE_LEFT         7
+#define _NET_WM_MOVERESIZE_MOVE              8   /* movement only */
+#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD     9   /* size via keyboard */
+#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD    10   /* move via keyboard */
+#define _NET_WM_MOVERESIZE_CANCEL           11   /* cancel operation */
+
 static void
-wmspec_moveresize (GdkWindow *window,
-                   gint       direction,
-                   GdkDevice *device,
-                   gint       root_x,
-                   gint       root_y,
-                   guint32    timestamp)     
+wmspec_send_message (GdkDisplay *display,
+                     GdkWindow  *window,
+                     gint        root_x,
+                     gint        root_y,
+                     gint        action,
+                     gint        button)
 {
-  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
-  
   XClientMessageEvent xclient;
 
-  /* Release passive grab */
-  gdk_device_ungrab (device, timestamp);
-
   memset (&xclient, 0, sizeof (xclient));
   xclient.type = ClientMessage;
   xclient.window = GDK_WINDOW_XID (window);
@@ -3973,49 +4050,70 @@ wmspec_moveresize (GdkWindow *window,
   xclient.format = 32;
   xclient.data.l[0] = root_x;
   xclient.data.l[1] = root_y;
-  xclient.data.l[2] = direction;
-  xclient.data.l[3] = 0;
-  xclient.data.l[4] = 0;
-  
+  xclient.data.l[2] = action;
+  xclient.data.l[3] = button;
+  xclient.data.l[4] = 1;  /* source indication */
+
   XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False,
-             SubstructureRedirectMask | SubstructureNotifyMask,
-             (XEvent *)&xclient);
+              SubstructureRedirectMask | SubstructureNotifyMask,
+              (XEvent *)&xclient);
 }
 
-typedef struct _MoveResizeData MoveResizeData;
+static gboolean
+handle_wmspec_button_release (GdkDisplay *display,
+                              XEvent     *xevent)
+{
+  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+  GdkWindow *window;
 
-struct _MoveResizeData
+#if defined (HAVE_XGENERICEVENTS) && defined (XINPUT_2)
+  XIEvent *xiev = (XIEvent *) xevent->xcookie.data;
+  XIDeviceEvent *xidev = (XIDeviceEvent *) xiev;
+
+  if (xevent->xany.type == GenericEvent)
+    window = gdk_x11_window_lookup_for_display (display, xidev->event);
+  else
+#endif
+    window = gdk_x11_window_lookup_for_display (display, xevent->xany.window);
+
+  if (display_x11->wm_moveresize_button != 0 && window != NULL)
+    {
+      if ((xevent->xany.type == ButtonRelease &&
+           xevent->xbutton.button == display_x11->wm_moveresize_button)
+#if defined (HAVE_XGENERICEVENTS) && defined (XINPUT_2)
+          ||
+          (xevent->xany.type == GenericEvent &&
+           xiev->evtype == XI_ButtonRelease &&
+           xidev->detail == display_x11->wm_moveresize_button)
+#endif
+          )
+        {
+          display_x11->wm_moveresize_button = 0;
+          wmspec_send_message (display, window, 0, 0, _NET_WM_MOVERESIZE_CANCEL, 0);
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+wmspec_moveresize (GdkWindow *window,
+                   gint       direction,
+                   GdkDevice *device,
+                   gint       button,
+                   gint       root_x,
+                   gint       root_y,
+                   guint32    timestamp)
 {
-  GdkDisplay *display;
-  
-  GdkWindow *moveresize_window;
-  GdkWindow *moveresize_emulation_window;
-  gboolean is_resize;
-  GdkWindowEdge resize_edge;
-  GdkDevice *device;
-  gint moveresize_button;
-  gint moveresize_x;
-  gint moveresize_y;
-  gint moveresize_orig_x;
-  gint moveresize_orig_y;
-  gint moveresize_orig_width;
-  gint moveresize_orig_height;
-  GdkWindowHints moveresize_geom_mask;
-  GdkGeometry moveresize_geometry;
-  Time moveresize_process_time;
-  XEvent *moveresize_pending_event;
-};
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
 
-/* From the WM spec */
-#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
-#define _NET_WM_MOVERESIZE_SIZE_TOP          1
-#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
-#define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
-#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
-#define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
-#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
-#define _NET_WM_MOVERESIZE_SIZE_LEFT         7
-#define _NET_WM_MOVERESIZE_MOVE              8
+  /* Release passive grab */
+  gdk_device_ungrab (device, timestamp);
+  GDK_X11_DISPLAY (display)->wm_moveresize_button = button;
+
+  wmspec_send_message (display, window, root_x, root_y, direction, button);
+}
 
 static void
 wmspec_resize_drag (GdkWindow     *window,
@@ -4071,9 +4169,33 @@ wmspec_resize_drag (GdkWindow     *window,
       return;
     }
   
-  wmspec_moveresize (window, direction, device, root_x, root_y, timestamp);
+  wmspec_moveresize (window, direction, device, button, root_x, root_y, timestamp);
 }
 
+typedef struct _MoveResizeData MoveResizeData;
+
+struct _MoveResizeData
+{
+  GdkDisplay *display;
+
+  GdkWindow *moveresize_window;
+  GdkWindow *moveresize_emulation_window;
+  gboolean is_resize;
+  GdkWindowEdge resize_edge;
+  GdkDevice *device;
+  gint moveresize_button;
+  gint moveresize_x;
+  gint moveresize_y;
+  gint moveresize_orig_x;
+  gint moveresize_orig_y;
+  gint moveresize_orig_width;
+  gint moveresize_orig_height;
+  GdkWindowHints moveresize_geom_mask;
+  GdkGeometry moveresize_geometry;
+  Time moveresize_process_time;
+  XEvent *moveresize_pending_event;
+};
+
 static MoveResizeData *
 get_move_resize_data (GdkDisplay *display,
                      gboolean    create)
@@ -4253,6 +4375,9 @@ _gdk_x11_moveresize_handle_event (XEvent *event)
   GdkDisplay *display = gdk_x11_lookup_xdisplay (event->xany.display);
   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
 
+  if (handle_wmspec_button_release (display, event))
+    return TRUE;
+
   if (!mv_resize || !mv_resize->moveresize_window)
     return FALSE;
 
@@ -4296,6 +4421,33 @@ _gdk_x11_moveresize_handle_event (XEvent *event)
       if (event->xbutton.button == mv_resize->moveresize_button)
         finish_drag (mv_resize);
       break;
+
+#if defined (HAVE_XGENERICEVENTS) && defined (XINPUT_2)
+    case GenericEvent:
+      {
+        /* we just assume this is an XI2 event */
+        XIEvent *ev = (XIEvent *) event->xcookie.data;
+        XIDeviceEvent *xev = (XIDeviceEvent *)ev;
+        gint state;
+        switch (ev->evtype)
+          {
+          case XI_Motion:
+            update_pos (mv_resize, xev->root_x, xev->root_y);
+            state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
+            if ((state & button_mask) == 0)
+            finish_drag (mv_resize);
+            break;
+
+          case XI_ButtonRelease:
+            update_pos (mv_resize, xev->root_x, xev->root_y);
+            if (xev->detail == mv_resize->moveresize_button)
+              finish_drag (mv_resize);
+            break;
+          }
+      }
+      break;
+#endif
+
     }
   return TRUE;
 }
@@ -4307,6 +4459,8 @@ _gdk_x11_moveresize_configure_done (GdkDisplay *display,
   XEvent *tmp_event;
   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
 
+  GDK_X11_DISPLAY (display)->wm_moveresize_button = 0;
+
   if (!mv_resize || window != mv_resize->moveresize_window)
     return FALSE;
 
@@ -4529,8 +4683,8 @@ gdk_x11_window_begin_move_drag (GdkWindow *window,
 
   if (gdk_x11_screen_supports_net_wm_hint (GDK_WINDOW_SCREEN (window),
                                           gdk_atom_intern_static_string ("_NET_WM_MOVERESIZE")))
-    wmspec_moveresize (window, _NET_WM_MOVERESIZE_MOVE, device, root_x, root_y,
-                      timestamp);
+    wmspec_moveresize (window, _NET_WM_MOVERESIZE_MOVE,
+                       device, button, root_x, root_y, timestamp);
   else
     emulate_move_drag (window, device, button, root_x, root_y, timestamp);
 }