* 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/>.
*/
/*
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;
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;
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,
}
/**
- * 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;
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 \
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;
rl[i].height = xrl[i].height;
}
XFree (xrl);
-
+
shape = cairo_region_create_rectangles (rl, rn);
g_free (rl);
-
+
return shape;
}
{
#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);
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);
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,
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)
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;
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;
}
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;
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);
}