Rename all *window.[ch] source files.
This is an automatic operation, done by the following commands:
for i in $(git ls-files gdk | grep window); do
git mv $i $(echo $i | sed s/window/surface/);
git sed -f g $(basename $i) $(basename $i | sed s/window/surface/) ;
done
git checkout NEWS* po-properties po
static Bug data[] =
{
{ FALSE, 60482, "Normal", "scrollable notebooks and hidden tabs" },
- { FALSE, 60620, "Critical", "gdk_surface_clear_area (gdkwindow-win32.c) is not thread-safe" },
+ { FALSE, 60620, "Critical", "gdk_surface_clear_area (gdksurface-win32.c) is not thread-safe" },
{ FALSE, 50214, "Major", "Xft support does not clean up correctly" },
{ TRUE, 52877, "Major", "GtkFileSelection needs a refresh method. " },
{ FALSE, 56070, "Normal", "Can't click button after setting in sensitive" },
#define __GDKBROADWAY_H_INSIDE__
#include <gdk/broadway/gdkbroadwaydisplay.h>
-#include <gdk/broadway/gdkbroadwaywindow.h>
+#include <gdk/broadway/gdkbroadwaysurface.h>
#include <gdk/broadway/gdkbroadwaycursor.h>
#include <gdk/broadway/gdkbroadwaymonitor.h>
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GDK_BROADWAY_SURFACE_H__
+#define __GDK_BROADWAY_SURFACE_H__
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_BROADWAY_SURFACE (gdk_broadway_surface_get_type ())
+#define GDK_BROADWAY_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_BROADWAY_SURFACE, GdkBroadwaySurface))
+#define GDK_BROADWAY_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_BROADWAY_SURFACE, GdkBroadwaySurfaceClass))
+#define GDK_IS_BROADWAY_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_BROADWAY_SURFACE))
+#define GDK_IS_BROADWAY_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_BROADWAY_SURFACE))
+#define GDK_BROADWAY_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_BROADWAY_SURFACE, GdkBroadwaySurfaceClass))
+
+#ifdef GDK_COMPILATION
+typedef struct _GdkBroadwaySurface GdkBroadwaySurface;
+#else
+typedef GdkSurface GdkBroadwaySurface;
+#endif
+typedef struct _GdkBroadwaySurfaceClass GdkBroadwaySurfaceClass;
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_broadway_surface_get_type (void);
+
+GDK_AVAILABLE_IN_ALL
+guint32 gdk_broadway_get_last_seen_time (GdkSurface *window);
+
+G_END_DECLS
+
+#endif /* __GDK_BROADWAY_SURFACE_H__ */
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#ifndef __GDK_BROADWAY_SURFACE_H__
-#define __GDK_BROADWAY_SURFACE_H__
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_BROADWAY_SURFACE (gdk_broadway_surface_get_type ())
-#define GDK_BROADWAY_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_BROADWAY_SURFACE, GdkBroadwaySurface))
-#define GDK_BROADWAY_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_BROADWAY_SURFACE, GdkBroadwaySurfaceClass))
-#define GDK_IS_BROADWAY_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_BROADWAY_SURFACE))
-#define GDK_IS_BROADWAY_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_BROADWAY_SURFACE))
-#define GDK_BROADWAY_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_BROADWAY_SURFACE, GdkBroadwaySurfaceClass))
-
-#ifdef GDK_COMPILATION
-typedef struct _GdkBroadwaySurface GdkBroadwaySurface;
-#else
-typedef GdkSurface GdkBroadwaySurface;
-#endif
-typedef struct _GdkBroadwaySurfaceClass GdkBroadwaySurfaceClass;
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_broadway_surface_get_type (void);
-
-GDK_AVAILABLE_IN_ALL
-guint32 gdk_broadway_get_last_seen_time (GdkSurface *window);
-
-G_END_DECLS
-
-#endif /* __GDK_BROADWAY_SURFACE_H__ */
#include "gdkdevice-broadway.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkprivate-broadway.h"
static gboolean gdk_broadway_device_get_history (GdkDevice *device,
#include "gdkdisplayprivate.h"
#include "gdkkeys.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkinternals.h"
#include "gdkbroadway-server.h"
#include "gdkmonitorprivate.h"
#include <gdk/gdkcursor.h>
#include <gdk/gdkinternals.h>
-#include "gdkwindow-broadway.h"
+#include "gdksurface-broadway.h"
#include "gdkdisplay-broadway.h"
#include "gdkbroadwaycursor.h"
-#include "gdkbroadwaywindow.h"
+#include "gdkbroadwaysurface.h"
void _gdk_broadway_resync_windows (void);
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
+ * Josh MacDonald, Ryan Lortie
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gdksurface-broadway.h"
+
+#include "gdkbroadwaydisplay.h"
+#include "gdkdisplay.h"
+#include "gdksurface.h"
+#include "gdksurfaceimpl.h"
+#include "gdkdisplay-broadway.h"
+#include "gdkprivate-broadway.h"
+#include "gdkinternals.h"
+#include "gdkdeviceprivate.h"
+#include "gdkeventsource.h"
+#include <gdk/gdktextureprivate.h>
+#include <gdk/gdkframeclockprivate.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Forward declarations */
+static void gdk_surface_impl_broadway_finalize (GObject *object);
+
+#define WINDOW_IS_TOPLEVEL(window) \
+ (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD)
+
+struct _GdkBroadwaySurface {
+ GdkSurface parent;
+};
+
+struct _GdkBroadwaySurfaceClass {
+ GdkSurfaceClass parent_class;
+};
+
+G_DEFINE_TYPE (GdkBroadwaySurface, gdk_broadway_surface, GDK_TYPE_SURFACE)
+
+static void
+gdk_broadway_surface_class_init (GdkBroadwaySurfaceClass *broadway_surface_class)
+{
+}
+
+static void
+gdk_broadway_surface_init (GdkBroadwaySurface *broadway_surface)
+{
+}
+
+G_DEFINE_TYPE (GdkSurfaceImplBroadway,
+ gdk_surface_impl_broadway,
+ GDK_TYPE_SURFACE_IMPL)
+
+static GdkDisplay *
+find_broadway_display (void)
+{
+ GdkDisplay *display;
+ GSList *list, *l;
+
+ display = NULL;
+
+ list = gdk_display_manager_list_displays (gdk_display_manager_get ());
+ for (l = list; l; l = l->next)
+ {
+ if (GDK_IS_BROADWAY_DISPLAY (l->data))
+ {
+ display = l->data;
+ break;
+ }
+ }
+ g_slist_free (list);
+
+ return display;
+}
+
+static guint flush_id = 0;
+
+static gboolean
+flush_idle (gpointer data)
+{
+ flush_id = 0;
+
+ gdk_display_flush (find_broadway_display ());
+
+ return FALSE;
+}
+
+/* We need to flush in an idle rather than AFTER_PAINT, as the clock
+ is frozen during e.g. window resizes so the paint will not happen
+ and the window resize request is never flushed. */
+static void
+queue_flush (GdkSurface *window)
+{
+ if (flush_id == 0)
+ {
+ flush_id = g_idle_add (flush_idle, NULL);
+ g_source_set_name_by_id (flush_id, "[gtk+] flush_idle");
+ }
+}
+
+static void
+gdk_surface_impl_broadway_init (GdkSurfaceImplBroadway *impl)
+{
+ impl->toplevel_window_type = -1;
+}
+
+static void
+gdk_surface_impl_broadway_finalize (GObject *object)
+{
+ GdkSurface *wrapper;
+ GdkSurfaceImplBroadway *impl;
+ GdkBroadwayDisplay *broadway_display;
+
+ g_return_if_fail (GDK_IS_SURFACE_IMPL_BROADWAY (object));
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (object);
+
+ wrapper = impl->wrapper;
+
+ _gdk_broadway_surface_grab_check_destroy (wrapper);
+
+ broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (impl->wrapper));
+
+ g_hash_table_remove (broadway_display->id_ht, GINT_TO_POINTER(impl->id));
+
+ if (impl->cursor)
+ g_object_unref (impl->cursor);
+
+ broadway_display->toplevels = g_list_remove (broadway_display->toplevels, impl);
+
+ G_OBJECT_CLASS (gdk_surface_impl_broadway_parent_class)->finalize (object);
+}
+
+static gboolean
+thaw_clock_cb (GdkFrameClock *clock)
+{
+ _gdk_frame_clock_thaw (clock);
+ g_object_unref (clock);
+ return G_SOURCE_REMOVE;
+}
+
+void
+_gdk_broadway_roundtrip_notify (GdkSurface *window,
+ guint32 tag,
+ gboolean local_reply)
+{
+ GdkFrameClock *clock = gdk_surface_get_frame_clock (window);
+
+ /* If there is no remove web client, rate limit update to once a second */
+ if (local_reply)
+ g_timeout_add_seconds (1, (GSourceFunc)thaw_clock_cb, g_object_ref (clock));
+ else
+ _gdk_frame_clock_thaw (clock);
+}
+
+static void
+on_frame_clock_after_paint (GdkFrameClock *clock,
+ GdkSurface *window)
+{
+ GdkDisplay *display = gdk_surface_get_display (window);
+ GdkSurfaceImplBroadway *impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+ GdkBroadwayDisplay *broadway_display;
+
+ _gdk_frame_clock_freeze (gdk_surface_get_frame_clock (window));
+
+ broadway_display = GDK_BROADWAY_DISPLAY (display);
+
+ _gdk_broadway_server_roundtrip (broadway_display->server, impl->id, _gdk_display_get_next_serial (display));
+
+ gdk_display_flush (display);
+}
+
+static void
+connect_frame_clock (GdkSurface *window)
+{
+ if (WINDOW_IS_TOPLEVEL (window))
+ {
+ GdkFrameClock *frame_clock = gdk_surface_get_frame_clock (window);
+
+ g_signal_connect (frame_clock, "after-paint",
+ G_CALLBACK (on_frame_clock_after_paint), window);
+ }
+}
+
+void
+_gdk_broadway_display_create_window_impl (GdkDisplay *display,
+ GdkSurface *window,
+ GdkSurface *real_parent,
+ GdkEventMask event_mask,
+ GdkSurfaceAttr *attributes)
+{
+ GdkSurfaceImplBroadway *impl;
+ GdkBroadwayDisplay *broadway_display;
+
+ broadway_display = GDK_BROADWAY_DISPLAY (display);
+
+ impl = g_object_new (GDK_TYPE_SURFACE_IMPL_BROADWAY, NULL);
+ window->impl = (GdkSurfaceImpl *)impl;
+ impl->id = _gdk_broadway_server_new_surface (broadway_display->server,
+ window->x,
+ window->y,
+ window->width,
+ window->height,
+ window->window_type == GDK_SURFACE_TEMP);
+ g_hash_table_insert (broadway_display->id_ht, GINT_TO_POINTER(impl->id), window);
+ impl->wrapper = window;
+
+ g_assert (window->window_type == GDK_SURFACE_TOPLEVEL ||
+ window->window_type == GDK_SURFACE_TEMP);
+ g_assert (window->parent == NULL);
+
+ broadway_display->toplevels = g_list_prepend (broadway_display->toplevels, impl);
+
+ connect_frame_clock (window);
+}
+
+static cairo_surface_t *
+gdk_surface_broadway_ref_cairo_surface (GdkSurface *window)
+{
+ GdkSurfaceImplBroadway *impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+
+ if (GDK_IS_SURFACE_IMPL_BROADWAY (window) &&
+ GDK_SURFACE_DESTROYED (impl->wrapper))
+ return NULL;
+
+ return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+}
+
+static void
+_gdk_broadway_surface_destroy (GdkSurface *window,
+ gboolean recursing,
+ gboolean foreign_destroy)
+{
+ GdkSurfaceImplBroadway *impl;
+ GdkBroadwayDisplay *broadway_display;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+
+ if (impl->node_data)
+ g_array_unref (impl->node_data);
+ if (impl->node_data_textures)
+ g_ptr_array_unref (impl->node_data_textures);
+
+ _gdk_broadway_surface_grab_check_destroy (window);
+
+ broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
+ g_hash_table_remove (broadway_display->id_ht, GINT_TO_POINTER (impl->id));
+
+ _gdk_broadway_server_destroy_surface (broadway_display->server, impl->id);
+
+}
+
+void
+gdk_broadway_surface_set_nodes (GdkSurface *window,
+ GArray *nodes,
+ GPtrArray *node_textures)
+{
+ GdkSurfaceImplBroadway *impl;
+ GdkBroadwayDisplay *broadway_display;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+
+ broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
+
+ if (nodes)
+ g_array_ref (nodes);
+ if (impl->node_data)
+ g_array_unref (impl->node_data);
+ impl->node_data = nodes;
+
+ if (node_textures)
+ g_ptr_array_ref (node_textures);
+ if (impl->node_data_textures)
+ g_ptr_array_unref (impl->node_data_textures);
+ impl->node_data_textures = node_textures;
+
+ gdk_broadway_server_surface_set_nodes (broadway_display->server, impl->id, impl->node_data);
+}
+
+/* This function is called when the XWindow is really gone.
+ */
+static void
+gdk_broadway_surface_destroy_notify (GdkSurface *window)
+{
+ if (!GDK_SURFACE_DESTROYED (window))
+ _gdk_surface_destroy (window, TRUE);
+
+ g_object_unref (window);
+}
+
+static void
+gdk_surface_broadway_show (GdkSurface *window, gboolean already_mapped)
+{
+ GdkSurfaceImplBroadway *impl;
+ GdkBroadwayDisplay *broadway_display;
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+ impl->visible = TRUE;
+
+ if (window->event_mask & GDK_STRUCTURE_MASK)
+ _gdk_make_event (GDK_SURFACE (window), GDK_MAP, NULL, FALSE);
+
+ if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
+ _gdk_make_event (GDK_SURFACE (window), GDK_MAP, NULL, FALSE);
+
+ broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
+ if (_gdk_broadway_server_surface_show (broadway_display->server, impl->id))
+ queue_flush (window);
+
+}
+
+static void
+gdk_surface_broadway_hide (GdkSurface *window)
+{
+ GdkSurfaceImplBroadway *impl;
+ GdkBroadwayDisplay *broadway_display;
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+ impl->visible = FALSE;
+
+ if (window->event_mask & GDK_STRUCTURE_MASK)
+ _gdk_make_event (GDK_SURFACE (window), GDK_UNMAP, NULL, FALSE);
+
+ if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
+ _gdk_make_event (GDK_SURFACE (window), GDK_UNMAP, NULL, FALSE);
+
+ broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
+
+ _gdk_broadway_surface_grab_check_unmap (window,
+ _gdk_broadway_server_get_next_serial (broadway_display->server));
+
+ if (_gdk_broadway_server_surface_hide (broadway_display->server, impl->id))
+ queue_flush (window);
+
+ _gdk_surface_clear_update_area (window);
+}
+
+static void
+gdk_surface_broadway_withdraw (GdkSurface *window)
+{
+ gdk_surface_broadway_hide (window);
+}
+
+static void
+gdk_surface_broadway_move_resize (GdkSurface *window,
+ gboolean with_move,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GdkSurfaceImplBroadway *impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+ GdkBroadwayDisplay *broadway_display;
+ gboolean size_changed;
+
+ size_changed = FALSE;
+
+ broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
+
+ if (width > 0 || height > 0)
+ {
+ if (width < 1)
+ width = 1;
+
+ if (height < 1)
+ height = 1;
+
+ if (width != window->width ||
+ height != window->height)
+ {
+ size_changed = TRUE;
+
+ /* Resize clears the content */
+ impl->dirty = TRUE;
+ impl->last_synced = FALSE;
+
+ window->width = width;
+ window->height = height;
+ }
+ }
+
+ _gdk_broadway_server_surface_move_resize (broadway_display->server,
+ impl->id,
+ with_move,
+ x, y,
+ window->width, window->height);
+ queue_flush (window);
+ if (size_changed)
+ window->resize_count++;
+}
+
+static void
+gdk_surface_broadway_raise (GdkSurface *window)
+{
+}
+
+static void
+gdk_surface_broadway_restack_toplevel (GdkSurface *window,
+ GdkSurface *sibling,
+ gboolean above)
+{
+}
+
+static void
+gdk_surface_broadway_lower (GdkSurface *window)
+{
+}
+
+
+static void
+gdk_broadway_surface_focus (GdkSurface *window,
+ guint32 timestamp)
+{
+ GdkSurfaceImplBroadway *impl;
+ GdkBroadwayDisplay *broadway_display;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !window->accept_focus)
+ return;
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+ broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
+ _gdk_broadway_server_surface_focus (broadway_display->server,
+ impl->id);
+}
+
+static void
+gdk_broadway_surface_set_type_hint (GdkSurface *window,
+ GdkSurfaceTypeHint hint)
+{
+}
+
+static GdkSurfaceTypeHint
+gdk_broadway_surface_get_type_hint (GdkSurface *window)
+{
+ return GDK_SURFACE_TYPE_HINT_NORMAL;
+}
+
+static void
+gdk_broadway_surface_set_modal_hint (GdkSurface *window,
+ gboolean modal)
+{
+}
+
+static void
+gdk_broadway_surface_set_skip_taskbar_hint (GdkSurface *window,
+ gboolean skips_taskbar)
+{
+}
+
+static void
+gdk_broadway_surface_set_skip_pager_hint (GdkSurface *window,
+ gboolean skips_pager)
+{
+}
+
+static void
+gdk_broadway_surface_set_urgency_hint (GdkSurface *window,
+ gboolean urgent)
+{
+}
+
+static void
+gdk_broadway_surface_set_geometry_hints (GdkSurface *window,
+ const GdkGeometry *geometry,
+ GdkSurfaceHints geom_mask)
+{
+ GdkSurfaceImplBroadway *impl;
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+
+ impl->geometry_hints = *geometry;
+ impl->geometry_hints_mask = geom_mask;
+}
+
+static void
+gdk_broadway_surface_set_title (GdkSurface *window,
+ const gchar *title)
+{
+}
+
+static void
+gdk_broadway_surface_set_role (GdkSurface *window,
+ const gchar *role)
+{
+}
+
+static void
+gdk_broadway_surface_set_startup_id (GdkSurface *window,
+ const gchar *startup_id)
+{
+}
+
+static void
+gdk_broadway_surface_set_transient_for (GdkSurface *window,
+ GdkSurface *parent)
+{
+ GdkBroadwayDisplay *display;
+ GdkSurfaceImplBroadway *impl;
+ int parent_id;
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+
+ parent_id = 0;
+ if (parent)
+ parent_id = GDK_SURFACE_IMPL_BROADWAY (parent->impl)->id;
+
+ impl->transient_for = parent_id;
+
+ display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (impl->wrapper));
+ _gdk_broadway_server_surface_set_transient_for (display->server, impl->id, impl->transient_for);
+}
+
+static void
+gdk_surface_broadway_get_geometry (GdkSurface *window,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height)
+{
+ GdkSurfaceImplBroadway *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+
+ /* TODO: These should really roundtrip to the client to get the current data */
+
+ if (x)
+ *x = impl->wrapper->x;
+ if (y)
+ *y = impl->wrapper->y;
+ if (width)
+ *width = impl->wrapper->width;
+ if (height)
+ *height = impl->wrapper->height;
+
+}
+
+static void
+gdk_surface_broadway_get_root_coords (GdkSurface *window,
+ gint x,
+ gint y,
+ gint *root_x,
+ gint *root_y)
+{
+ GdkSurfaceImplBroadway *impl;
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+
+ if (root_x)
+ *root_x = x + impl->wrapper->x;
+ if (root_y)
+ *root_y = y + impl->wrapper->y;
+}
+
+static void
+gdk_broadway_surface_get_frame_extents (GdkSurface *window,
+ GdkRectangle *rect)
+{
+ g_return_if_fail (rect != NULL);
+
+ /* TODO: This should take wm frame into account */
+
+ rect->x = window->x;
+ rect->y = window->y;
+ rect->width = window->width;
+ rect->height = window->height;
+}
+
+static gboolean
+gdk_surface_broadway_get_device_state (GdkSurface *window,
+ GdkDevice *device,
+ gdouble *x,
+ gdouble *y,
+ GdkModifierType *mask)
+{
+ GdkSurface *child;
+
+ g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), FALSE);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return FALSE;
+
+ GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
+ &child,
+ NULL, NULL,
+ x, y, mask);
+ return child != NULL;
+}
+
+static GdkEventMask
+gdk_surface_broadway_get_events (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window))
+ return 0;
+
+ return 0;
+}
+
+static void
+gdk_surface_broadway_set_events (GdkSurface *window,
+ GdkEventMask event_mask)
+{
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ }
+}
+
+static void
+gdk_surface_broadway_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+}
+
+static void
+gdk_surface_broadway_input_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+}
+
+static void
+gdk_broadway_surface_set_accept_focus (GdkSurface *window,
+ gboolean accept_focus)
+{
+ accept_focus = accept_focus != FALSE;
+
+ if (window->accept_focus != accept_focus)
+ {
+ window->accept_focus = accept_focus;
+ }
+}
+
+static void
+gdk_broadway_surface_set_focus_on_map (GdkSurface *window,
+ gboolean focus_on_map)
+{
+ focus_on_map = focus_on_map != FALSE;
+
+ if (window->focus_on_map != focus_on_map)
+ {
+ window->focus_on_map = focus_on_map;
+ }
+}
+
+
+static void
+gdk_broadway_surface_set_icon_list (GdkSurface *window,
+ GList *surfaces)
+{
+}
+
+static void
+gdk_broadway_surface_set_icon_name (GdkSurface *window,
+ const gchar *name)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"),
+ GUINT_TO_POINTER (name != NULL));
+}
+
+static void
+gdk_broadway_surface_iconify (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+}
+
+static void
+gdk_broadway_surface_deiconify (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+}
+
+static void
+gdk_broadway_surface_stick (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+}
+
+static void
+gdk_broadway_surface_unstick (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+}
+
+static void
+gdk_broadway_surface_maximize (GdkSurface *window)
+{
+ GdkSurfaceImplBroadway *impl;
+ GdkDisplay *display;
+ GdkMonitor *monitor;
+ GdkRectangle geom;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+
+ if (impl->maximized)
+ return;
+
+ impl->maximized = TRUE;
+
+ gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_MAXIMIZED);
+
+ impl->pre_maximize_x = window->x;
+ impl->pre_maximize_y = window->y;
+ impl->pre_maximize_width = window->width;
+ impl->pre_maximize_height = window->height;
+
+ display = gdk_surface_get_display (window);
+ monitor = gdk_display_get_primary_monitor (display);
+ gdk_monitor_get_geometry (monitor, &geom);
+
+ gdk_surface_move_resize (window,
+ geom.x, geom.y,
+ geom.width, geom.height);
+}
+
+static void
+gdk_broadway_surface_unmaximize (GdkSurface *window)
+{
+ GdkSurfaceImplBroadway *impl;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+
+ if (!impl->maximized)
+ return;
+
+ impl->maximized = FALSE;
+
+ gdk_synthesize_window_state (window, GDK_SURFACE_STATE_MAXIMIZED, 0);
+
+ gdk_surface_move_resize (window,
+ impl->pre_maximize_x,
+ impl->pre_maximize_y,
+ impl->pre_maximize_width,
+ impl->pre_maximize_height);
+}
+
+static void
+gdk_broadway_surface_fullscreen (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+}
+
+static void
+gdk_broadway_surface_unfullscreen (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+}
+
+static void
+gdk_broadway_surface_set_keep_above (GdkSurface *window,
+ gboolean setting)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+}
+
+static void
+gdk_broadway_surface_set_keep_below (GdkSurface *window, gboolean setting)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+}
+
+static GdkSurface *
+gdk_broadway_surface_get_group (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return NULL;
+
+ return window;
+}
+
+static void
+gdk_broadway_surface_set_group (GdkSurface *window,
+ GdkSurface *leader)
+{
+}
+
+static void
+gdk_broadway_surface_set_decorations (GdkSurface *window,
+ GdkWMDecoration decorations)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+}
+
+static gboolean
+gdk_broadway_surface_get_decorations (GdkSurface *window,
+ GdkWMDecoration *decorations)
+{
+ gboolean result = FALSE;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return FALSE;
+
+ return result;
+}
+
+static void
+gdk_broadway_surface_set_functions (GdkSurface *window,
+ GdkWMFunction functions)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+}
+
+static void
+gdk_broadway_surface_end_paint (GdkSurface *window)
+{
+ GdkSurfaceImplBroadway *impl;
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+ impl->dirty = TRUE;
+}
+
+typedef struct _MoveResizeData MoveResizeData;
+
+struct _MoveResizeData
+{
+ GdkDisplay *display;
+
+ GdkSurface *moveresize_window;
+ GdkSurface *moveresize_emulation_window;
+ gboolean is_resize;
+ GdkSurfaceEdge resize_edge;
+ 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;
+ long moveresize_process_time;
+ GdkSurfaceHints moveresize_geom_mask;
+ GdkGeometry moveresize_geometry;
+ BroadwayInputMsg *moveresize_pending_event;
+};
+
+static MoveResizeData *
+get_move_resize_data (GdkDisplay *display,
+ gboolean create)
+{
+ GdkBroadwayDisplay *broadway_display;
+ MoveResizeData *mv_resize;
+
+ broadway_display = GDK_BROADWAY_DISPLAY (display);
+
+ mv_resize = broadway_display->move_resize_data;
+
+ if (!mv_resize && create)
+ {
+ mv_resize = g_new0 (MoveResizeData, 1);
+ mv_resize->display = display;
+
+ broadway_display->move_resize_data = mv_resize;
+ }
+
+ return mv_resize;
+}
+
+static void
+update_pos (MoveResizeData *mv_resize,
+ gint new_root_x,
+ gint new_root_y)
+{
+ gint dx, dy;
+
+ dx = new_root_x - mv_resize->moveresize_x;
+ dy = new_root_y - mv_resize->moveresize_y;
+
+ if (mv_resize->is_resize)
+ {
+ gint x, y, w, h;
+
+ x = mv_resize->moveresize_orig_x;
+ y = mv_resize->moveresize_orig_y;
+
+ w = mv_resize->moveresize_orig_width;
+ h = mv_resize->moveresize_orig_height;
+
+ switch (mv_resize->resize_edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ x += dx;
+ y += dy;
+ w -= dx;
+ h -= dy;
+ break;
+ case GDK_SURFACE_EDGE_NORTH:
+ y += dy;
+ h -= dy;
+ break;
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ y += dy;
+ h -= dy;
+ w += dx;
+ break;
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ h += dy;
+ x += dx;
+ w -= dx;
+ break;
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ w += dx;
+ h += dy;
+ break;
+ case GDK_SURFACE_EDGE_SOUTH:
+ h += dy;
+ break;
+ case GDK_SURFACE_EDGE_EAST:
+ w += dx;
+ break;
+ case GDK_SURFACE_EDGE_WEST:
+ x += dx;
+ w -= dx;
+ break;
+ default:
+ break;
+ }
+
+ x = MAX (x, 0);
+ y = MAX (y, 0);
+ w = MAX (w, 1);
+ h = MAX (h, 1);
+
+ if (mv_resize->moveresize_geom_mask)
+ {
+ gdk_surface_constrain_size (&mv_resize->moveresize_geometry,
+ mv_resize->moveresize_geom_mask,
+ w, h, &w, &h);
+ }
+
+ gdk_surface_move_resize (mv_resize->moveresize_window, x, y, w, h);
+ }
+ else
+ {
+ gint x, y;
+
+ x = mv_resize->moveresize_orig_x + dx;
+ y = mv_resize->moveresize_orig_y + dy;
+
+ gdk_surface_move (mv_resize->moveresize_window, x, y);
+ }
+}
+
+static void
+finish_drag (MoveResizeData *mv_resize)
+{
+ gdk_surface_destroy (mv_resize->moveresize_emulation_window);
+ mv_resize->moveresize_emulation_window = NULL;
+ g_object_unref (mv_resize->moveresize_window);
+ mv_resize->moveresize_window = NULL;
+ g_clear_pointer (&mv_resize->moveresize_pending_event, g_free);
+}
+
+static gboolean
+moveresize_lookahead (GdkDisplay *display,
+ MoveResizeData *mv_resize,
+ BroadwayInputMsg *event)
+{
+ GdkBroadwayDisplay *broadway_display;
+
+ broadway_display = GDK_BROADWAY_DISPLAY (display);
+
+ return !_gdk_broadway_server_lookahead_event (broadway_display->server, "mb");
+}
+
+gboolean
+_gdk_broadway_moveresize_handle_event (GdkDisplay *display,
+ BroadwayInputMsg *event)
+{
+ guint button_mask = 0;
+ MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
+
+ if (!mv_resize || !mv_resize->moveresize_window)
+ return FALSE;
+
+ button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1);
+
+ switch (event->base.type)
+ {
+ case BROADWAY_EVENT_TOUCH:
+ if (event->touch.touch_type == 2) /* END */
+ {
+ update_pos (mv_resize,
+ event->touch.root_x,
+ event->touch.root_y);
+
+ finish_drag (mv_resize);
+ }
+ else if (event->touch.touch_type == 1) /* UPDATE */
+ {
+ if (mv_resize->moveresize_window->resize_count > 0)
+ {
+ if (mv_resize->moveresize_pending_event)
+ *mv_resize->moveresize_pending_event = *event;
+ else
+ mv_resize->moveresize_pending_event =
+ g_memdup (event, sizeof (BroadwayInputMsg));
+
+ break;
+ }
+ update_pos (mv_resize,
+ event->touch.root_x,
+ event->touch.root_y);
+ }
+
+ break;
+
+ case BROADWAY_EVENT_POINTER_MOVE:
+ if (mv_resize->moveresize_window->resize_count > 0)
+ {
+ if (mv_resize->moveresize_pending_event)
+ *mv_resize->moveresize_pending_event = *event;
+ else
+ mv_resize->moveresize_pending_event =
+ g_memdup (event, sizeof (BroadwayInputMsg));
+
+ break;
+ }
+ if (!moveresize_lookahead (display, mv_resize, event))
+ break;
+
+ update_pos (mv_resize,
+ event->pointer.root_x,
+ event->pointer.root_y);
+
+ /* This should never be triggered in normal cases, but in the
+ * case where the drag started without an implicit grab being
+ * in effect, we could miss the release if it occurs before
+ * we grab the pointer; this ensures that we will never
+ * get a permanently stuck grab.
+ */
+ if ((event->pointer.state & button_mask) == 0)
+ finish_drag (mv_resize);
+ break;
+
+ case BROADWAY_EVENT_BUTTON_RELEASE:
+ update_pos (mv_resize,
+ event->pointer.root_x,
+ event->pointer.root_y);
+
+ if (event->button.button == mv_resize->moveresize_button)
+ finish_drag (mv_resize);
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+gboolean
+_gdk_broadway_moveresize_configure_done (GdkDisplay *display,
+ GdkSurface *window)
+{
+ BroadwayInputMsg *tmp_event;
+ MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
+
+ if (!mv_resize || window != mv_resize->moveresize_window)
+ return FALSE;
+
+ if (mv_resize->moveresize_pending_event)
+ {
+ tmp_event = mv_resize->moveresize_pending_event;
+ mv_resize->moveresize_pending_event = NULL;
+ _gdk_broadway_moveresize_handle_event (display, tmp_event);
+ g_free (tmp_event);
+ }
+
+ return TRUE;
+}
+
+static void
+create_moveresize_window (MoveResizeData *mv_resize,
+ guint32 timestamp)
+{
+ GdkGrabStatus status;
+ GdkSeat *seat;
+ GdkDevice *pointer;
+
+ g_assert (mv_resize->moveresize_emulation_window == NULL);
+
+ mv_resize->moveresize_emulation_window = gdk_surface_new_temp (mv_resize->display);
+
+ gdk_surface_show (mv_resize->moveresize_emulation_window);
+
+ seat = gdk_display_get_default_seat (mv_resize->display);
+ pointer = gdk_seat_get_pointer (seat);
+
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+ status = gdk_device_grab (pointer,
+ mv_resize->moveresize_emulation_window,
+ GDK_OWNERSHIP_APPLICATION,
+ FALSE,
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK,
+ NULL,
+ timestamp);
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+
+ if (status != GDK_GRAB_SUCCESS)
+ {
+ /* If this fails, some other client has grabbed the window
+ * already.
+ */
+ finish_drag (mv_resize);
+ }
+
+ mv_resize->moveresize_process_time = 0;
+}
+
+static void
+calculate_unmoving_origin (MoveResizeData *mv_resize)
+{
+ GdkRectangle rect;
+ gint width, height;
+
+ if (mv_resize->moveresize_geom_mask & GDK_HINT_WIN_GRAVITY &&
+ mv_resize->moveresize_geometry.win_gravity == GDK_GRAVITY_STATIC)
+ {
+ gdk_surface_get_origin (mv_resize->moveresize_window,
+ &mv_resize->moveresize_orig_x,
+ &mv_resize->moveresize_orig_y);
+ }
+ else
+ {
+ gdk_surface_get_frame_extents (mv_resize->moveresize_window, &rect);
+ gdk_surface_get_geometry (mv_resize->moveresize_window,
+ NULL, NULL, &width, &height);
+
+ switch (mv_resize->moveresize_geometry.win_gravity)
+ {
+ case GDK_GRAVITY_NORTH_WEST:
+ mv_resize->moveresize_orig_x = rect.x;
+ mv_resize->moveresize_orig_y = rect.y;
+ break;
+ case GDK_GRAVITY_NORTH:
+ mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
+ mv_resize->moveresize_orig_y = rect.y;
+ break;
+ case GDK_GRAVITY_NORTH_EAST:
+ mv_resize->moveresize_orig_x = rect.x + rect.width - width;
+ mv_resize->moveresize_orig_y = rect.y;
+ break;
+ case GDK_GRAVITY_WEST:
+ mv_resize->moveresize_orig_x = rect.x;
+ mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
+ break;
+ case GDK_GRAVITY_CENTER:
+ mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
+ mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
+ break;
+ case GDK_GRAVITY_EAST:
+ mv_resize->moveresize_orig_x = rect.x + rect.width - width;
+ mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
+ break;
+ case GDK_GRAVITY_SOUTH_WEST:
+ mv_resize->moveresize_orig_x = rect.x;
+ mv_resize->moveresize_orig_y = rect.y + rect.height - height;
+ break;
+ case GDK_GRAVITY_SOUTH:
+ mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
+ mv_resize->moveresize_orig_y = rect.y + rect.height - height;
+ break;
+ case GDK_GRAVITY_SOUTH_EAST:
+ mv_resize->moveresize_orig_x = rect.x + rect.width - width;
+ mv_resize->moveresize_orig_y = rect.y + rect.height - height;
+ break;
+ case GDK_GRAVITY_STATIC:
+ default:
+ mv_resize->moveresize_orig_x = rect.x;
+ mv_resize->moveresize_orig_y = rect.y;
+ break;
+ }
+ }
+}
+
+static void
+gdk_broadway_surface_begin_resize_drag (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ MoveResizeData *mv_resize;
+ GdkSurfaceImplBroadway *impl;
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ if (impl->maximized)
+ return;
+
+ mv_resize = get_move_resize_data (gdk_surface_get_display (window), TRUE);
+
+ mv_resize->is_resize = TRUE;
+ mv_resize->moveresize_button = button;
+ mv_resize->resize_edge = edge;
+ mv_resize->moveresize_x = root_x;
+ mv_resize->moveresize_y = root_y;
+ mv_resize->moveresize_window = g_object_ref (window);
+
+ mv_resize->moveresize_orig_width = gdk_surface_get_width (window);
+ mv_resize->moveresize_orig_height = gdk_surface_get_height (window);
+
+ mv_resize->moveresize_geom_mask = impl->geometry_hints_mask;
+ mv_resize->moveresize_geometry = impl->geometry_hints;
+
+ calculate_unmoving_origin (mv_resize);
+
+ create_moveresize_window (mv_resize, timestamp);
+}
+
+static void
+gdk_broadway_surface_begin_move_drag (GdkSurface *window,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ MoveResizeData *mv_resize;
+ GdkSurfaceImplBroadway *impl;
+
+ impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ if (impl->maximized)
+ return;
+
+ mv_resize = get_move_resize_data (gdk_surface_get_display (window), TRUE);
+
+ mv_resize->is_resize = FALSE;
+ mv_resize->moveresize_button = button;
+ mv_resize->moveresize_x = root_x;
+ mv_resize->moveresize_y = root_y;
+ mv_resize->moveresize_window = g_object_ref (window);
+
+ mv_resize->moveresize_orig_width = gdk_surface_get_width (window);
+ mv_resize->moveresize_orig_height = gdk_surface_get_height (window);
+
+ mv_resize->moveresize_geom_mask = impl->geometry_hints_mask;
+ mv_resize->moveresize_geometry = impl->geometry_hints;
+
+ calculate_unmoving_origin (mv_resize);
+
+ create_moveresize_window (mv_resize, timestamp);
+}
+
+static gboolean
+gdk_broadway_surface_beep (GdkSurface *window)
+{
+ return FALSE;
+}
+
+static void
+gdk_broadway_surface_set_opacity (GdkSurface *window,
+ gdouble opacity)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ if (opacity < 0)
+ opacity = 0;
+ else if (opacity > 1)
+ opacity = 1;
+}
+
+guint32
+gdk_broadway_get_last_seen_time (GdkSurface *window)
+{
+ GdkDisplay *display;
+
+ display = gdk_surface_get_display (window);
+ return _gdk_broadway_server_get_last_seen_time (GDK_BROADWAY_DISPLAY (display)->server);
+}
+
+static void
+gdk_surface_impl_broadway_class_init (GdkSurfaceImplBroadwayClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_CLASS (klass);
+
+ object_class->finalize = gdk_surface_impl_broadway_finalize;
+
+ impl_class->ref_cairo_surface = gdk_surface_broadway_ref_cairo_surface;
+ impl_class->show = gdk_surface_broadway_show;
+ impl_class->hide = gdk_surface_broadway_hide;
+ impl_class->withdraw = gdk_surface_broadway_withdraw;
+ impl_class->set_events = gdk_surface_broadway_set_events;
+ impl_class->get_events = gdk_surface_broadway_get_events;
+ impl_class->raise = gdk_surface_broadway_raise;
+ impl_class->lower = gdk_surface_broadway_lower;
+ impl_class->restack_toplevel = gdk_surface_broadway_restack_toplevel;
+ impl_class->move_resize = gdk_surface_broadway_move_resize;
+ impl_class->get_geometry = gdk_surface_broadway_get_geometry;
+ impl_class->get_root_coords = gdk_surface_broadway_get_root_coords;
+ impl_class->get_device_state = gdk_surface_broadway_get_device_state;
+ impl_class->shape_combine_region = gdk_surface_broadway_shape_combine_region;
+ impl_class->input_shape_combine_region = gdk_surface_broadway_input_shape_combine_region;
+ impl_class->destroy = _gdk_broadway_surface_destroy;
+ impl_class->end_paint = gdk_broadway_surface_end_paint;
+ impl_class->beep = gdk_broadway_surface_beep;
+
+ impl_class->focus = gdk_broadway_surface_focus;
+ impl_class->set_type_hint = gdk_broadway_surface_set_type_hint;
+ impl_class->get_type_hint = gdk_broadway_surface_get_type_hint;
+ impl_class->set_modal_hint = gdk_broadway_surface_set_modal_hint;
+ impl_class->set_skip_taskbar_hint = gdk_broadway_surface_set_skip_taskbar_hint;
+ impl_class->set_skip_pager_hint = gdk_broadway_surface_set_skip_pager_hint;
+ impl_class->set_urgency_hint = gdk_broadway_surface_set_urgency_hint;
+ impl_class->set_geometry_hints = gdk_broadway_surface_set_geometry_hints;
+ impl_class->set_title = gdk_broadway_surface_set_title;
+ impl_class->set_role = gdk_broadway_surface_set_role;
+ impl_class->set_startup_id = gdk_broadway_surface_set_startup_id;
+ impl_class->set_transient_for = gdk_broadway_surface_set_transient_for;
+ impl_class->get_frame_extents = gdk_broadway_surface_get_frame_extents;
+ impl_class->set_accept_focus = gdk_broadway_surface_set_accept_focus;
+ impl_class->set_focus_on_map = gdk_broadway_surface_set_focus_on_map;
+ impl_class->set_icon_list = gdk_broadway_surface_set_icon_list;
+ impl_class->set_icon_name = gdk_broadway_surface_set_icon_name;
+ impl_class->iconify = gdk_broadway_surface_iconify;
+ impl_class->deiconify = gdk_broadway_surface_deiconify;
+ impl_class->stick = gdk_broadway_surface_stick;
+ impl_class->unstick = gdk_broadway_surface_unstick;
+ impl_class->maximize = gdk_broadway_surface_maximize;
+ impl_class->unmaximize = gdk_broadway_surface_unmaximize;
+ impl_class->fullscreen = gdk_broadway_surface_fullscreen;
+ impl_class->unfullscreen = gdk_broadway_surface_unfullscreen;
+ impl_class->set_keep_above = gdk_broadway_surface_set_keep_above;
+ impl_class->set_keep_below = gdk_broadway_surface_set_keep_below;
+ impl_class->get_group = gdk_broadway_surface_get_group;
+ impl_class->set_group = gdk_broadway_surface_set_group;
+ impl_class->set_decorations = gdk_broadway_surface_set_decorations;
+ impl_class->get_decorations = gdk_broadway_surface_get_decorations;
+ impl_class->set_functions = gdk_broadway_surface_set_functions;
+ impl_class->begin_resize_drag = gdk_broadway_surface_begin_resize_drag;
+ impl_class->begin_move_drag = gdk_broadway_surface_begin_move_drag;
+ impl_class->set_opacity = gdk_broadway_surface_set_opacity;
+ impl_class->destroy_notify = gdk_broadway_surface_destroy_notify;
+ impl_class->register_dnd = _gdk_broadway_surface_register_dnd;
+ impl_class->drag_begin = _gdk_broadway_surface_drag_begin;
+}
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GDK_SURFACE_BROADWAY_H__
+#define __GDK_SURFACE_BROADWAY_H__
+
+#include <gdk/gdksurfaceimpl.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkSurfaceImplBroadway GdkSurfaceImplBroadway;
+typedef struct _GdkSurfaceImplBroadwayClass GdkSurfaceImplBroadwayClass;
+
+/* Window implementation for Broadway
+ */
+
+#define GDK_TYPE_SURFACE_IMPL_BROADWAY (gdk_surface_impl_broadway_get_type ())
+#define GDK_SURFACE_IMPL_BROADWAY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL_BROADWAY, GdkSurfaceImplBroadway))
+#define GDK_SURFACE_IMPL_BROADWAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL_BROADWAY, GdkSurfaceImplBroadwayClass))
+#define GDK_IS_SURFACE_IMPL_BROADWAY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL_BROADWAY))
+#define GDK_IS_SURFACE_IMPL_BROADWAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL_BROADWAY))
+#define GDK_SURFACE_IMPL_BROADWAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL_BROADWAY, GdkSurfaceImplBroadwayClass))
+
+struct _GdkSurfaceImplBroadway
+{
+ GdkSurfaceImpl parent_instance;
+
+ GdkSurface *wrapper;
+
+ GdkCursor *cursor;
+
+ int id;
+
+ gboolean visible;
+ gboolean maximized;
+ int transient_for;
+
+ int pre_maximize_x;
+ int pre_maximize_y;
+ int pre_maximize_width;
+ int pre_maximize_height;
+
+ gint8 toplevel_window_type;
+ gboolean dirty;
+ gboolean last_synced;
+
+ GdkGeometry geometry_hints;
+ GdkSurfaceHints geometry_hints_mask;
+
+ GArray *node_data;
+ GPtrArray *node_data_textures;
+};
+
+struct _GdkSurfaceImplBroadwayClass
+{
+ GdkSurfaceImplClass parent_class;
+};
+
+GType gdk_surface_impl_broadway_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GDK_SURFACE_BROADWAY_H__ */
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
- * Josh MacDonald, Ryan Lortie
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#include "config.h"
-
-#include "gdkwindow-broadway.h"
-
-#include "gdkbroadwaydisplay.h"
-#include "gdkdisplay.h"
-#include "gdkwindow.h"
-#include "gdkwindowimpl.h"
-#include "gdkdisplay-broadway.h"
-#include "gdkprivate-broadway.h"
-#include "gdkinternals.h"
-#include "gdkdeviceprivate.h"
-#include "gdkeventsource.h"
-#include <gdk/gdktextureprivate.h>
-#include <gdk/gdkframeclockprivate.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-/* Forward declarations */
-static void gdk_surface_impl_broadway_finalize (GObject *object);
-
-#define WINDOW_IS_TOPLEVEL(window) \
- (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD)
-
-struct _GdkBroadwaySurface {
- GdkSurface parent;
-};
-
-struct _GdkBroadwaySurfaceClass {
- GdkSurfaceClass parent_class;
-};
-
-G_DEFINE_TYPE (GdkBroadwaySurface, gdk_broadway_surface, GDK_TYPE_SURFACE)
-
-static void
-gdk_broadway_surface_class_init (GdkBroadwaySurfaceClass *broadway_surface_class)
-{
-}
-
-static void
-gdk_broadway_surface_init (GdkBroadwaySurface *broadway_surface)
-{
-}
-
-G_DEFINE_TYPE (GdkSurfaceImplBroadway,
- gdk_surface_impl_broadway,
- GDK_TYPE_SURFACE_IMPL)
-
-static GdkDisplay *
-find_broadway_display (void)
-{
- GdkDisplay *display;
- GSList *list, *l;
-
- display = NULL;
-
- list = gdk_display_manager_list_displays (gdk_display_manager_get ());
- for (l = list; l; l = l->next)
- {
- if (GDK_IS_BROADWAY_DISPLAY (l->data))
- {
- display = l->data;
- break;
- }
- }
- g_slist_free (list);
-
- return display;
-}
-
-static guint flush_id = 0;
-
-static gboolean
-flush_idle (gpointer data)
-{
- flush_id = 0;
-
- gdk_display_flush (find_broadway_display ());
-
- return FALSE;
-}
-
-/* We need to flush in an idle rather than AFTER_PAINT, as the clock
- is frozen during e.g. window resizes so the paint will not happen
- and the window resize request is never flushed. */
-static void
-queue_flush (GdkSurface *window)
-{
- if (flush_id == 0)
- {
- flush_id = g_idle_add (flush_idle, NULL);
- g_source_set_name_by_id (flush_id, "[gtk+] flush_idle");
- }
-}
-
-static void
-gdk_surface_impl_broadway_init (GdkSurfaceImplBroadway *impl)
-{
- impl->toplevel_window_type = -1;
-}
-
-static void
-gdk_surface_impl_broadway_finalize (GObject *object)
-{
- GdkSurface *wrapper;
- GdkSurfaceImplBroadway *impl;
- GdkBroadwayDisplay *broadway_display;
-
- g_return_if_fail (GDK_IS_SURFACE_IMPL_BROADWAY (object));
-
- impl = GDK_SURFACE_IMPL_BROADWAY (object);
-
- wrapper = impl->wrapper;
-
- _gdk_broadway_surface_grab_check_destroy (wrapper);
-
- broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (impl->wrapper));
-
- g_hash_table_remove (broadway_display->id_ht, GINT_TO_POINTER(impl->id));
-
- if (impl->cursor)
- g_object_unref (impl->cursor);
-
- broadway_display->toplevels = g_list_remove (broadway_display->toplevels, impl);
-
- G_OBJECT_CLASS (gdk_surface_impl_broadway_parent_class)->finalize (object);
-}
-
-static gboolean
-thaw_clock_cb (GdkFrameClock *clock)
-{
- _gdk_frame_clock_thaw (clock);
- g_object_unref (clock);
- return G_SOURCE_REMOVE;
-}
-
-void
-_gdk_broadway_roundtrip_notify (GdkSurface *window,
- guint32 tag,
- gboolean local_reply)
-{
- GdkFrameClock *clock = gdk_surface_get_frame_clock (window);
-
- /* If there is no remove web client, rate limit update to once a second */
- if (local_reply)
- g_timeout_add_seconds (1, (GSourceFunc)thaw_clock_cb, g_object_ref (clock));
- else
- _gdk_frame_clock_thaw (clock);
-}
-
-static void
-on_frame_clock_after_paint (GdkFrameClock *clock,
- GdkSurface *window)
-{
- GdkDisplay *display = gdk_surface_get_display (window);
- GdkSurfaceImplBroadway *impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
- GdkBroadwayDisplay *broadway_display;
-
- _gdk_frame_clock_freeze (gdk_surface_get_frame_clock (window));
-
- broadway_display = GDK_BROADWAY_DISPLAY (display);
-
- _gdk_broadway_server_roundtrip (broadway_display->server, impl->id, _gdk_display_get_next_serial (display));
-
- gdk_display_flush (display);
-}
-
-static void
-connect_frame_clock (GdkSurface *window)
-{
- if (WINDOW_IS_TOPLEVEL (window))
- {
- GdkFrameClock *frame_clock = gdk_surface_get_frame_clock (window);
-
- g_signal_connect (frame_clock, "after-paint",
- G_CALLBACK (on_frame_clock_after_paint), window);
- }
-}
-
-void
-_gdk_broadway_display_create_window_impl (GdkDisplay *display,
- GdkSurface *window,
- GdkSurface *real_parent,
- GdkEventMask event_mask,
- GdkSurfaceAttr *attributes)
-{
- GdkSurfaceImplBroadway *impl;
- GdkBroadwayDisplay *broadway_display;
-
- broadway_display = GDK_BROADWAY_DISPLAY (display);
-
- impl = g_object_new (GDK_TYPE_SURFACE_IMPL_BROADWAY, NULL);
- window->impl = (GdkSurfaceImpl *)impl;
- impl->id = _gdk_broadway_server_new_surface (broadway_display->server,
- window->x,
- window->y,
- window->width,
- window->height,
- window->window_type == GDK_SURFACE_TEMP);
- g_hash_table_insert (broadway_display->id_ht, GINT_TO_POINTER(impl->id), window);
- impl->wrapper = window;
-
- g_assert (window->window_type == GDK_SURFACE_TOPLEVEL ||
- window->window_type == GDK_SURFACE_TEMP);
- g_assert (window->parent == NULL);
-
- broadway_display->toplevels = g_list_prepend (broadway_display->toplevels, impl);
-
- connect_frame_clock (window);
-}
-
-static cairo_surface_t *
-gdk_surface_broadway_ref_cairo_surface (GdkSurface *window)
-{
- GdkSurfaceImplBroadway *impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
-
- if (GDK_IS_SURFACE_IMPL_BROADWAY (window) &&
- GDK_SURFACE_DESTROYED (impl->wrapper))
- return NULL;
-
- return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
-}
-
-static void
-_gdk_broadway_surface_destroy (GdkSurface *window,
- gboolean recursing,
- gboolean foreign_destroy)
-{
- GdkSurfaceImplBroadway *impl;
- GdkBroadwayDisplay *broadway_display;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
-
- if (impl->node_data)
- g_array_unref (impl->node_data);
- if (impl->node_data_textures)
- g_ptr_array_unref (impl->node_data_textures);
-
- _gdk_broadway_surface_grab_check_destroy (window);
-
- broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
- g_hash_table_remove (broadway_display->id_ht, GINT_TO_POINTER (impl->id));
-
- _gdk_broadway_server_destroy_surface (broadway_display->server, impl->id);
-
-}
-
-void
-gdk_broadway_surface_set_nodes (GdkSurface *window,
- GArray *nodes,
- GPtrArray *node_textures)
-{
- GdkSurfaceImplBroadway *impl;
- GdkBroadwayDisplay *broadway_display;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
-
- broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
-
- if (nodes)
- g_array_ref (nodes);
- if (impl->node_data)
- g_array_unref (impl->node_data);
- impl->node_data = nodes;
-
- if (node_textures)
- g_ptr_array_ref (node_textures);
- if (impl->node_data_textures)
- g_ptr_array_unref (impl->node_data_textures);
- impl->node_data_textures = node_textures;
-
- gdk_broadway_server_surface_set_nodes (broadway_display->server, impl->id, impl->node_data);
-}
-
-/* This function is called when the XWindow is really gone.
- */
-static void
-gdk_broadway_surface_destroy_notify (GdkSurface *window)
-{
- if (!GDK_SURFACE_DESTROYED (window))
- _gdk_surface_destroy (window, TRUE);
-
- g_object_unref (window);
-}
-
-static void
-gdk_surface_broadway_show (GdkSurface *window, gboolean already_mapped)
-{
- GdkSurfaceImplBroadway *impl;
- GdkBroadwayDisplay *broadway_display;
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
- impl->visible = TRUE;
-
- if (window->event_mask & GDK_STRUCTURE_MASK)
- _gdk_make_event (GDK_SURFACE (window), GDK_MAP, NULL, FALSE);
-
- if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
- _gdk_make_event (GDK_SURFACE (window), GDK_MAP, NULL, FALSE);
-
- broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
- if (_gdk_broadway_server_surface_show (broadway_display->server, impl->id))
- queue_flush (window);
-
-}
-
-static void
-gdk_surface_broadway_hide (GdkSurface *window)
-{
- GdkSurfaceImplBroadway *impl;
- GdkBroadwayDisplay *broadway_display;
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
- impl->visible = FALSE;
-
- if (window->event_mask & GDK_STRUCTURE_MASK)
- _gdk_make_event (GDK_SURFACE (window), GDK_UNMAP, NULL, FALSE);
-
- if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
- _gdk_make_event (GDK_SURFACE (window), GDK_UNMAP, NULL, FALSE);
-
- broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
-
- _gdk_broadway_surface_grab_check_unmap (window,
- _gdk_broadway_server_get_next_serial (broadway_display->server));
-
- if (_gdk_broadway_server_surface_hide (broadway_display->server, impl->id))
- queue_flush (window);
-
- _gdk_surface_clear_update_area (window);
-}
-
-static void
-gdk_surface_broadway_withdraw (GdkSurface *window)
-{
- gdk_surface_broadway_hide (window);
-}
-
-static void
-gdk_surface_broadway_move_resize (GdkSurface *window,
- gboolean with_move,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- GdkSurfaceImplBroadway *impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
- GdkBroadwayDisplay *broadway_display;
- gboolean size_changed;
-
- size_changed = FALSE;
-
- broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
-
- if (width > 0 || height > 0)
- {
- if (width < 1)
- width = 1;
-
- if (height < 1)
- height = 1;
-
- if (width != window->width ||
- height != window->height)
- {
- size_changed = TRUE;
-
- /* Resize clears the content */
- impl->dirty = TRUE;
- impl->last_synced = FALSE;
-
- window->width = width;
- window->height = height;
- }
- }
-
- _gdk_broadway_server_surface_move_resize (broadway_display->server,
- impl->id,
- with_move,
- x, y,
- window->width, window->height);
- queue_flush (window);
- if (size_changed)
- window->resize_count++;
-}
-
-static void
-gdk_surface_broadway_raise (GdkSurface *window)
-{
-}
-
-static void
-gdk_surface_broadway_restack_toplevel (GdkSurface *window,
- GdkSurface *sibling,
- gboolean above)
-{
-}
-
-static void
-gdk_surface_broadway_lower (GdkSurface *window)
-{
-}
-
-
-static void
-gdk_broadway_surface_focus (GdkSurface *window,
- guint32 timestamp)
-{
- GdkSurfaceImplBroadway *impl;
- GdkBroadwayDisplay *broadway_display;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !window->accept_focus)
- return;
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
- broadway_display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (window));
- _gdk_broadway_server_surface_focus (broadway_display->server,
- impl->id);
-}
-
-static void
-gdk_broadway_surface_set_type_hint (GdkSurface *window,
- GdkSurfaceTypeHint hint)
-{
-}
-
-static GdkSurfaceTypeHint
-gdk_broadway_surface_get_type_hint (GdkSurface *window)
-{
- return GDK_SURFACE_TYPE_HINT_NORMAL;
-}
-
-static void
-gdk_broadway_surface_set_modal_hint (GdkSurface *window,
- gboolean modal)
-{
-}
-
-static void
-gdk_broadway_surface_set_skip_taskbar_hint (GdkSurface *window,
- gboolean skips_taskbar)
-{
-}
-
-static void
-gdk_broadway_surface_set_skip_pager_hint (GdkSurface *window,
- gboolean skips_pager)
-{
-}
-
-static void
-gdk_broadway_surface_set_urgency_hint (GdkSurface *window,
- gboolean urgent)
-{
-}
-
-static void
-gdk_broadway_surface_set_geometry_hints (GdkSurface *window,
- const GdkGeometry *geometry,
- GdkSurfaceHints geom_mask)
-{
- GdkSurfaceImplBroadway *impl;
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
-
- impl->geometry_hints = *geometry;
- impl->geometry_hints_mask = geom_mask;
-}
-
-static void
-gdk_broadway_surface_set_title (GdkSurface *window,
- const gchar *title)
-{
-}
-
-static void
-gdk_broadway_surface_set_role (GdkSurface *window,
- const gchar *role)
-{
-}
-
-static void
-gdk_broadway_surface_set_startup_id (GdkSurface *window,
- const gchar *startup_id)
-{
-}
-
-static void
-gdk_broadway_surface_set_transient_for (GdkSurface *window,
- GdkSurface *parent)
-{
- GdkBroadwayDisplay *display;
- GdkSurfaceImplBroadway *impl;
- int parent_id;
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
-
- parent_id = 0;
- if (parent)
- parent_id = GDK_SURFACE_IMPL_BROADWAY (parent->impl)->id;
-
- impl->transient_for = parent_id;
-
- display = GDK_BROADWAY_DISPLAY (gdk_surface_get_display (impl->wrapper));
- _gdk_broadway_server_surface_set_transient_for (display->server, impl->id, impl->transient_for);
-}
-
-static void
-gdk_surface_broadway_get_geometry (GdkSurface *window,
- gint *x,
- gint *y,
- gint *width,
- gint *height)
-{
- GdkSurfaceImplBroadway *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
-
- /* TODO: These should really roundtrip to the client to get the current data */
-
- if (x)
- *x = impl->wrapper->x;
- if (y)
- *y = impl->wrapper->y;
- if (width)
- *width = impl->wrapper->width;
- if (height)
- *height = impl->wrapper->height;
-
-}
-
-static void
-gdk_surface_broadway_get_root_coords (GdkSurface *window,
- gint x,
- gint y,
- gint *root_x,
- gint *root_y)
-{
- GdkSurfaceImplBroadway *impl;
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
-
- if (root_x)
- *root_x = x + impl->wrapper->x;
- if (root_y)
- *root_y = y + impl->wrapper->y;
-}
-
-static void
-gdk_broadway_surface_get_frame_extents (GdkSurface *window,
- GdkRectangle *rect)
-{
- g_return_if_fail (rect != NULL);
-
- /* TODO: This should take wm frame into account */
-
- rect->x = window->x;
- rect->y = window->y;
- rect->width = window->width;
- rect->height = window->height;
-}
-
-static gboolean
-gdk_surface_broadway_get_device_state (GdkSurface *window,
- GdkDevice *device,
- gdouble *x,
- gdouble *y,
- GdkModifierType *mask)
-{
- GdkSurface *child;
-
- g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), FALSE);
-
- if (GDK_SURFACE_DESTROYED (window))
- return FALSE;
-
- GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
- &child,
- NULL, NULL,
- x, y, mask);
- return child != NULL;
-}
-
-static GdkEventMask
-gdk_surface_broadway_get_events (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return 0;
-
- return 0;
-}
-
-static void
-gdk_surface_broadway_set_events (GdkSurface *window,
- GdkEventMask event_mask)
-{
- if (!GDK_SURFACE_DESTROYED (window))
- {
- }
-}
-
-static void
-gdk_surface_broadway_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
-}
-
-static void
-gdk_surface_broadway_input_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
-}
-
-static void
-gdk_broadway_surface_set_accept_focus (GdkSurface *window,
- gboolean accept_focus)
-{
- accept_focus = accept_focus != FALSE;
-
- if (window->accept_focus != accept_focus)
- {
- window->accept_focus = accept_focus;
- }
-}
-
-static void
-gdk_broadway_surface_set_focus_on_map (GdkSurface *window,
- gboolean focus_on_map)
-{
- focus_on_map = focus_on_map != FALSE;
-
- if (window->focus_on_map != focus_on_map)
- {
- window->focus_on_map = focus_on_map;
- }
-}
-
-
-static void
-gdk_broadway_surface_set_icon_list (GdkSurface *window,
- GList *surfaces)
-{
-}
-
-static void
-gdk_broadway_surface_set_icon_name (GdkSurface *window,
- const gchar *name)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"),
- GUINT_TO_POINTER (name != NULL));
-}
-
-static void
-gdk_broadway_surface_iconify (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-}
-
-static void
-gdk_broadway_surface_deiconify (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-}
-
-static void
-gdk_broadway_surface_stick (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
-}
-
-static void
-gdk_broadway_surface_unstick (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
-}
-
-static void
-gdk_broadway_surface_maximize (GdkSurface *window)
-{
- GdkSurfaceImplBroadway *impl;
- GdkDisplay *display;
- GdkMonitor *monitor;
- GdkRectangle geom;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
-
- if (impl->maximized)
- return;
-
- impl->maximized = TRUE;
-
- gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_MAXIMIZED);
-
- impl->pre_maximize_x = window->x;
- impl->pre_maximize_y = window->y;
- impl->pre_maximize_width = window->width;
- impl->pre_maximize_height = window->height;
-
- display = gdk_surface_get_display (window);
- monitor = gdk_display_get_primary_monitor (display);
- gdk_monitor_get_geometry (monitor, &geom);
-
- gdk_surface_move_resize (window,
- geom.x, geom.y,
- geom.width, geom.height);
-}
-
-static void
-gdk_broadway_surface_unmaximize (GdkSurface *window)
-{
- GdkSurfaceImplBroadway *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
-
- if (!impl->maximized)
- return;
-
- impl->maximized = FALSE;
-
- gdk_synthesize_window_state (window, GDK_SURFACE_STATE_MAXIMIZED, 0);
-
- gdk_surface_move_resize (window,
- impl->pre_maximize_x,
- impl->pre_maximize_y,
- impl->pre_maximize_width,
- impl->pre_maximize_height);
-}
-
-static void
-gdk_broadway_surface_fullscreen (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
-}
-
-static void
-gdk_broadway_surface_unfullscreen (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
-}
-
-static void
-gdk_broadway_surface_set_keep_above (GdkSurface *window,
- gboolean setting)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
-}
-
-static void
-gdk_broadway_surface_set_keep_below (GdkSurface *window, gboolean setting)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
-}
-
-static GdkSurface *
-gdk_broadway_surface_get_group (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return NULL;
-
- return window;
-}
-
-static void
-gdk_broadway_surface_set_group (GdkSurface *window,
- GdkSurface *leader)
-{
-}
-
-static void
-gdk_broadway_surface_set_decorations (GdkSurface *window,
- GdkWMDecoration decorations)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
-}
-
-static gboolean
-gdk_broadway_surface_get_decorations (GdkSurface *window,
- GdkWMDecoration *decorations)
-{
- gboolean result = FALSE;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return FALSE;
-
- return result;
-}
-
-static void
-gdk_broadway_surface_set_functions (GdkSurface *window,
- GdkWMFunction functions)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-}
-
-static void
-gdk_broadway_surface_end_paint (GdkSurface *window)
-{
- GdkSurfaceImplBroadway *impl;
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
- impl->dirty = TRUE;
-}
-
-typedef struct _MoveResizeData MoveResizeData;
-
-struct _MoveResizeData
-{
- GdkDisplay *display;
-
- GdkSurface *moveresize_window;
- GdkSurface *moveresize_emulation_window;
- gboolean is_resize;
- GdkSurfaceEdge resize_edge;
- 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;
- long moveresize_process_time;
- GdkSurfaceHints moveresize_geom_mask;
- GdkGeometry moveresize_geometry;
- BroadwayInputMsg *moveresize_pending_event;
-};
-
-static MoveResizeData *
-get_move_resize_data (GdkDisplay *display,
- gboolean create)
-{
- GdkBroadwayDisplay *broadway_display;
- MoveResizeData *mv_resize;
-
- broadway_display = GDK_BROADWAY_DISPLAY (display);
-
- mv_resize = broadway_display->move_resize_data;
-
- if (!mv_resize && create)
- {
- mv_resize = g_new0 (MoveResizeData, 1);
- mv_resize->display = display;
-
- broadway_display->move_resize_data = mv_resize;
- }
-
- return mv_resize;
-}
-
-static void
-update_pos (MoveResizeData *mv_resize,
- gint new_root_x,
- gint new_root_y)
-{
- gint dx, dy;
-
- dx = new_root_x - mv_resize->moveresize_x;
- dy = new_root_y - mv_resize->moveresize_y;
-
- if (mv_resize->is_resize)
- {
- gint x, y, w, h;
-
- x = mv_resize->moveresize_orig_x;
- y = mv_resize->moveresize_orig_y;
-
- w = mv_resize->moveresize_orig_width;
- h = mv_resize->moveresize_orig_height;
-
- switch (mv_resize->resize_edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- x += dx;
- y += dy;
- w -= dx;
- h -= dy;
- break;
- case GDK_SURFACE_EDGE_NORTH:
- y += dy;
- h -= dy;
- break;
- case GDK_SURFACE_EDGE_NORTH_EAST:
- y += dy;
- h -= dy;
- w += dx;
- break;
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- h += dy;
- x += dx;
- w -= dx;
- break;
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- w += dx;
- h += dy;
- break;
- case GDK_SURFACE_EDGE_SOUTH:
- h += dy;
- break;
- case GDK_SURFACE_EDGE_EAST:
- w += dx;
- break;
- case GDK_SURFACE_EDGE_WEST:
- x += dx;
- w -= dx;
- break;
- default:
- break;
- }
-
- x = MAX (x, 0);
- y = MAX (y, 0);
- w = MAX (w, 1);
- h = MAX (h, 1);
-
- if (mv_resize->moveresize_geom_mask)
- {
- gdk_surface_constrain_size (&mv_resize->moveresize_geometry,
- mv_resize->moveresize_geom_mask,
- w, h, &w, &h);
- }
-
- gdk_surface_move_resize (mv_resize->moveresize_window, x, y, w, h);
- }
- else
- {
- gint x, y;
-
- x = mv_resize->moveresize_orig_x + dx;
- y = mv_resize->moveresize_orig_y + dy;
-
- gdk_surface_move (mv_resize->moveresize_window, x, y);
- }
-}
-
-static void
-finish_drag (MoveResizeData *mv_resize)
-{
- gdk_surface_destroy (mv_resize->moveresize_emulation_window);
- mv_resize->moveresize_emulation_window = NULL;
- g_object_unref (mv_resize->moveresize_window);
- mv_resize->moveresize_window = NULL;
- g_clear_pointer (&mv_resize->moveresize_pending_event, g_free);
-}
-
-static gboolean
-moveresize_lookahead (GdkDisplay *display,
- MoveResizeData *mv_resize,
- BroadwayInputMsg *event)
-{
- GdkBroadwayDisplay *broadway_display;
-
- broadway_display = GDK_BROADWAY_DISPLAY (display);
-
- return !_gdk_broadway_server_lookahead_event (broadway_display->server, "mb");
-}
-
-gboolean
-_gdk_broadway_moveresize_handle_event (GdkDisplay *display,
- BroadwayInputMsg *event)
-{
- guint button_mask = 0;
- MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
-
- if (!mv_resize || !mv_resize->moveresize_window)
- return FALSE;
-
- button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1);
-
- switch (event->base.type)
- {
- case BROADWAY_EVENT_TOUCH:
- if (event->touch.touch_type == 2) /* END */
- {
- update_pos (mv_resize,
- event->touch.root_x,
- event->touch.root_y);
-
- finish_drag (mv_resize);
- }
- else if (event->touch.touch_type == 1) /* UPDATE */
- {
- if (mv_resize->moveresize_window->resize_count > 0)
- {
- if (mv_resize->moveresize_pending_event)
- *mv_resize->moveresize_pending_event = *event;
- else
- mv_resize->moveresize_pending_event =
- g_memdup (event, sizeof (BroadwayInputMsg));
-
- break;
- }
- update_pos (mv_resize,
- event->touch.root_x,
- event->touch.root_y);
- }
-
- break;
-
- case BROADWAY_EVENT_POINTER_MOVE:
- if (mv_resize->moveresize_window->resize_count > 0)
- {
- if (mv_resize->moveresize_pending_event)
- *mv_resize->moveresize_pending_event = *event;
- else
- mv_resize->moveresize_pending_event =
- g_memdup (event, sizeof (BroadwayInputMsg));
-
- break;
- }
- if (!moveresize_lookahead (display, mv_resize, event))
- break;
-
- update_pos (mv_resize,
- event->pointer.root_x,
- event->pointer.root_y);
-
- /* This should never be triggered in normal cases, but in the
- * case where the drag started without an implicit grab being
- * in effect, we could miss the release if it occurs before
- * we grab the pointer; this ensures that we will never
- * get a permanently stuck grab.
- */
- if ((event->pointer.state & button_mask) == 0)
- finish_drag (mv_resize);
- break;
-
- case BROADWAY_EVENT_BUTTON_RELEASE:
- update_pos (mv_resize,
- event->pointer.root_x,
- event->pointer.root_y);
-
- if (event->button.button == mv_resize->moveresize_button)
- finish_drag (mv_resize);
- break;
- default:
- break;
- }
- return TRUE;
-}
-
-gboolean
-_gdk_broadway_moveresize_configure_done (GdkDisplay *display,
- GdkSurface *window)
-{
- BroadwayInputMsg *tmp_event;
- MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
-
- if (!mv_resize || window != mv_resize->moveresize_window)
- return FALSE;
-
- if (mv_resize->moveresize_pending_event)
- {
- tmp_event = mv_resize->moveresize_pending_event;
- mv_resize->moveresize_pending_event = NULL;
- _gdk_broadway_moveresize_handle_event (display, tmp_event);
- g_free (tmp_event);
- }
-
- return TRUE;
-}
-
-static void
-create_moveresize_window (MoveResizeData *mv_resize,
- guint32 timestamp)
-{
- GdkGrabStatus status;
- GdkSeat *seat;
- GdkDevice *pointer;
-
- g_assert (mv_resize->moveresize_emulation_window == NULL);
-
- mv_resize->moveresize_emulation_window = gdk_surface_new_temp (mv_resize->display);
-
- gdk_surface_show (mv_resize->moveresize_emulation_window);
-
- seat = gdk_display_get_default_seat (mv_resize->display);
- pointer = gdk_seat_get_pointer (seat);
-
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
- status = gdk_device_grab (pointer,
- mv_resize->moveresize_emulation_window,
- GDK_OWNERSHIP_APPLICATION,
- FALSE,
- GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK,
- NULL,
- timestamp);
- G_GNUC_END_IGNORE_DEPRECATIONS;
-
- if (status != GDK_GRAB_SUCCESS)
- {
- /* If this fails, some other client has grabbed the window
- * already.
- */
- finish_drag (mv_resize);
- }
-
- mv_resize->moveresize_process_time = 0;
-}
-
-static void
-calculate_unmoving_origin (MoveResizeData *mv_resize)
-{
- GdkRectangle rect;
- gint width, height;
-
- if (mv_resize->moveresize_geom_mask & GDK_HINT_WIN_GRAVITY &&
- mv_resize->moveresize_geometry.win_gravity == GDK_GRAVITY_STATIC)
- {
- gdk_surface_get_origin (mv_resize->moveresize_window,
- &mv_resize->moveresize_orig_x,
- &mv_resize->moveresize_orig_y);
- }
- else
- {
- gdk_surface_get_frame_extents (mv_resize->moveresize_window, &rect);
- gdk_surface_get_geometry (mv_resize->moveresize_window,
- NULL, NULL, &width, &height);
-
- switch (mv_resize->moveresize_geometry.win_gravity)
- {
- case GDK_GRAVITY_NORTH_WEST:
- mv_resize->moveresize_orig_x = rect.x;
- mv_resize->moveresize_orig_y = rect.y;
- break;
- case GDK_GRAVITY_NORTH:
- mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
- mv_resize->moveresize_orig_y = rect.y;
- break;
- case GDK_GRAVITY_NORTH_EAST:
- mv_resize->moveresize_orig_x = rect.x + rect.width - width;
- mv_resize->moveresize_orig_y = rect.y;
- break;
- case GDK_GRAVITY_WEST:
- mv_resize->moveresize_orig_x = rect.x;
- mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
- break;
- case GDK_GRAVITY_CENTER:
- mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
- mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
- break;
- case GDK_GRAVITY_EAST:
- mv_resize->moveresize_orig_x = rect.x + rect.width - width;
- mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
- break;
- case GDK_GRAVITY_SOUTH_WEST:
- mv_resize->moveresize_orig_x = rect.x;
- mv_resize->moveresize_orig_y = rect.y + rect.height - height;
- break;
- case GDK_GRAVITY_SOUTH:
- mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
- mv_resize->moveresize_orig_y = rect.y + rect.height - height;
- break;
- case GDK_GRAVITY_SOUTH_EAST:
- mv_resize->moveresize_orig_x = rect.x + rect.width - width;
- mv_resize->moveresize_orig_y = rect.y + rect.height - height;
- break;
- case GDK_GRAVITY_STATIC:
- default:
- mv_resize->moveresize_orig_x = rect.x;
- mv_resize->moveresize_orig_y = rect.y;
- break;
- }
- }
-}
-
-static void
-gdk_broadway_surface_begin_resize_drag (GdkSurface *window,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- MoveResizeData *mv_resize;
- GdkSurfaceImplBroadway *impl;
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- if (impl->maximized)
- return;
-
- mv_resize = get_move_resize_data (gdk_surface_get_display (window), TRUE);
-
- mv_resize->is_resize = TRUE;
- mv_resize->moveresize_button = button;
- mv_resize->resize_edge = edge;
- mv_resize->moveresize_x = root_x;
- mv_resize->moveresize_y = root_y;
- mv_resize->moveresize_window = g_object_ref (window);
-
- mv_resize->moveresize_orig_width = gdk_surface_get_width (window);
- mv_resize->moveresize_orig_height = gdk_surface_get_height (window);
-
- mv_resize->moveresize_geom_mask = impl->geometry_hints_mask;
- mv_resize->moveresize_geometry = impl->geometry_hints;
-
- calculate_unmoving_origin (mv_resize);
-
- create_moveresize_window (mv_resize, timestamp);
-}
-
-static void
-gdk_broadway_surface_begin_move_drag (GdkSurface *window,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- MoveResizeData *mv_resize;
- GdkSurfaceImplBroadway *impl;
-
- impl = GDK_SURFACE_IMPL_BROADWAY (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- if (impl->maximized)
- return;
-
- mv_resize = get_move_resize_data (gdk_surface_get_display (window), TRUE);
-
- mv_resize->is_resize = FALSE;
- mv_resize->moveresize_button = button;
- mv_resize->moveresize_x = root_x;
- mv_resize->moveresize_y = root_y;
- mv_resize->moveresize_window = g_object_ref (window);
-
- mv_resize->moveresize_orig_width = gdk_surface_get_width (window);
- mv_resize->moveresize_orig_height = gdk_surface_get_height (window);
-
- mv_resize->moveresize_geom_mask = impl->geometry_hints_mask;
- mv_resize->moveresize_geometry = impl->geometry_hints;
-
- calculate_unmoving_origin (mv_resize);
-
- create_moveresize_window (mv_resize, timestamp);
-}
-
-static gboolean
-gdk_broadway_surface_beep (GdkSurface *window)
-{
- return FALSE;
-}
-
-static void
-gdk_broadway_surface_set_opacity (GdkSurface *window,
- gdouble opacity)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- if (opacity < 0)
- opacity = 0;
- else if (opacity > 1)
- opacity = 1;
-}
-
-guint32
-gdk_broadway_get_last_seen_time (GdkSurface *window)
-{
- GdkDisplay *display;
-
- display = gdk_surface_get_display (window);
- return _gdk_broadway_server_get_last_seen_time (GDK_BROADWAY_DISPLAY (display)->server);
-}
-
-static void
-gdk_surface_impl_broadway_class_init (GdkSurfaceImplBroadwayClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_CLASS (klass);
-
- object_class->finalize = gdk_surface_impl_broadway_finalize;
-
- impl_class->ref_cairo_surface = gdk_surface_broadway_ref_cairo_surface;
- impl_class->show = gdk_surface_broadway_show;
- impl_class->hide = gdk_surface_broadway_hide;
- impl_class->withdraw = gdk_surface_broadway_withdraw;
- impl_class->set_events = gdk_surface_broadway_set_events;
- impl_class->get_events = gdk_surface_broadway_get_events;
- impl_class->raise = gdk_surface_broadway_raise;
- impl_class->lower = gdk_surface_broadway_lower;
- impl_class->restack_toplevel = gdk_surface_broadway_restack_toplevel;
- impl_class->move_resize = gdk_surface_broadway_move_resize;
- impl_class->get_geometry = gdk_surface_broadway_get_geometry;
- impl_class->get_root_coords = gdk_surface_broadway_get_root_coords;
- impl_class->get_device_state = gdk_surface_broadway_get_device_state;
- impl_class->shape_combine_region = gdk_surface_broadway_shape_combine_region;
- impl_class->input_shape_combine_region = gdk_surface_broadway_input_shape_combine_region;
- impl_class->destroy = _gdk_broadway_surface_destroy;
- impl_class->end_paint = gdk_broadway_surface_end_paint;
- impl_class->beep = gdk_broadway_surface_beep;
-
- impl_class->focus = gdk_broadway_surface_focus;
- impl_class->set_type_hint = gdk_broadway_surface_set_type_hint;
- impl_class->get_type_hint = gdk_broadway_surface_get_type_hint;
- impl_class->set_modal_hint = gdk_broadway_surface_set_modal_hint;
- impl_class->set_skip_taskbar_hint = gdk_broadway_surface_set_skip_taskbar_hint;
- impl_class->set_skip_pager_hint = gdk_broadway_surface_set_skip_pager_hint;
- impl_class->set_urgency_hint = gdk_broadway_surface_set_urgency_hint;
- impl_class->set_geometry_hints = gdk_broadway_surface_set_geometry_hints;
- impl_class->set_title = gdk_broadway_surface_set_title;
- impl_class->set_role = gdk_broadway_surface_set_role;
- impl_class->set_startup_id = gdk_broadway_surface_set_startup_id;
- impl_class->set_transient_for = gdk_broadway_surface_set_transient_for;
- impl_class->get_frame_extents = gdk_broadway_surface_get_frame_extents;
- impl_class->set_accept_focus = gdk_broadway_surface_set_accept_focus;
- impl_class->set_focus_on_map = gdk_broadway_surface_set_focus_on_map;
- impl_class->set_icon_list = gdk_broadway_surface_set_icon_list;
- impl_class->set_icon_name = gdk_broadway_surface_set_icon_name;
- impl_class->iconify = gdk_broadway_surface_iconify;
- impl_class->deiconify = gdk_broadway_surface_deiconify;
- impl_class->stick = gdk_broadway_surface_stick;
- impl_class->unstick = gdk_broadway_surface_unstick;
- impl_class->maximize = gdk_broadway_surface_maximize;
- impl_class->unmaximize = gdk_broadway_surface_unmaximize;
- impl_class->fullscreen = gdk_broadway_surface_fullscreen;
- impl_class->unfullscreen = gdk_broadway_surface_unfullscreen;
- impl_class->set_keep_above = gdk_broadway_surface_set_keep_above;
- impl_class->set_keep_below = gdk_broadway_surface_set_keep_below;
- impl_class->get_group = gdk_broadway_surface_get_group;
- impl_class->set_group = gdk_broadway_surface_set_group;
- impl_class->set_decorations = gdk_broadway_surface_set_decorations;
- impl_class->get_decorations = gdk_broadway_surface_get_decorations;
- impl_class->set_functions = gdk_broadway_surface_set_functions;
- impl_class->begin_resize_drag = gdk_broadway_surface_begin_resize_drag;
- impl_class->begin_move_drag = gdk_broadway_surface_begin_move_drag;
- impl_class->set_opacity = gdk_broadway_surface_set_opacity;
- impl_class->destroy_notify = gdk_broadway_surface_destroy_notify;
- impl_class->register_dnd = _gdk_broadway_surface_register_dnd;
- impl_class->drag_begin = _gdk_broadway_surface_drag_begin;
-}
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#ifndef __GDK_SURFACE_BROADWAY_H__
-#define __GDK_SURFACE_BROADWAY_H__
-
-#include <gdk/gdkwindowimpl.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GdkSurfaceImplBroadway GdkSurfaceImplBroadway;
-typedef struct _GdkSurfaceImplBroadwayClass GdkSurfaceImplBroadwayClass;
-
-/* Window implementation for Broadway
- */
-
-#define GDK_TYPE_SURFACE_IMPL_BROADWAY (gdk_surface_impl_broadway_get_type ())
-#define GDK_SURFACE_IMPL_BROADWAY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL_BROADWAY, GdkSurfaceImplBroadway))
-#define GDK_SURFACE_IMPL_BROADWAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL_BROADWAY, GdkSurfaceImplBroadwayClass))
-#define GDK_IS_SURFACE_IMPL_BROADWAY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL_BROADWAY))
-#define GDK_IS_SURFACE_IMPL_BROADWAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL_BROADWAY))
-#define GDK_SURFACE_IMPL_BROADWAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL_BROADWAY, GdkSurfaceImplBroadwayClass))
-
-struct _GdkSurfaceImplBroadway
-{
- GdkSurfaceImpl parent_instance;
-
- GdkSurface *wrapper;
-
- GdkCursor *cursor;
-
- int id;
-
- gboolean visible;
- gboolean maximized;
- int transient_for;
-
- int pre_maximize_x;
- int pre_maximize_y;
- int pre_maximize_width;
- int pre_maximize_height;
-
- gint8 toplevel_window_type;
- gboolean dirty;
- gboolean last_synced;
-
- GdkGeometry geometry_hints;
- GdkSurfaceHints geometry_hints_mask;
-
- GArray *node_data;
- GPtrArray *node_data_textures;
-};
-
-struct _GdkSurfaceImplBroadwayClass
-{
- GdkSurfaceImplClass parent_class;
-};
-
-GType gdk_surface_impl_broadway_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GDK_SURFACE_BROADWAY_H__ */
'gdkkeys-broadway.c',
'gdkmonitor-broadway.c',
'gdkselection-broadway.c',
- 'gdkwindow-broadway.c',
+ 'gdksurface-broadway.c',
])
gdk_broadway_public_headers = [
'gdkbroadwaydisplay.h',
- 'gdkbroadwaywindow.h',
+ 'gdkbroadwaysurface.h',
'gdkbroadwaycursor.h',
'gdkbroadwaymonitor.h',
]
#include <gdk/gdktexture.h>
#include <gdk/gdktypes.h>
#include <gdk/gdkvulkancontext.h>
-#include <gdk/gdkwindow.h>
+#include <gdk/gdksurface.h>
#include <gdk/gdk-autocleanup.h>
#include "gdkdeviceprivate.h"
#include "gdkdisplaymanagerprivate.h"
#include "gdkevents.h"
-#include "gdkwindowimpl.h"
+#include "gdksurfaceimpl.h"
#include "gdkinternals.h"
#include "gdkmonitorprivate.h"
#define __GDK_DISPLAY_PRIVATE_H__
#include "gdkdisplay.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkcursor.h"
#include "gdkmonitor.h"
#include "gdkinternals.h"
#include "gdkdndprivate.h"
#include "gdkdisplay.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkintl.h"
#include "gdkcontentformats.h"
#include "gdkcontentprovider.h"
#include "gdkinternals.h"
#include "gdkintl.h"
#include "gdkframeclockidle.h"
-#include "gdkwindowimpl.h"
+#include "gdksurfaceimpl.h"
#include "gdkglcontextprivate.h"
#include "gdk-private.h"
#define __GDK_INTERNALS_H__
#include <gdk-pixbuf/gdk-pixbuf.h>
-#include "gdkwindowimpl.h"
+#include "gdksurfaceimpl.h"
#include "gdkdisplay.h"
#include "gdkeventsprivate.h"
#include "gdkenumtypes.h"
#include "gdkpixbuf.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkinternals.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#endif
#include <glib-object.h>
-#include <gdk/gdkwindow.h>
+#include <gdk/gdksurface.h>
#include <gdk/gdkevents.h>
#include <gdk/gdktypes.h>
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
+ * Josh MacDonald, Ryan Lortie
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include <cairo-gobject.h>
+
+#include "gdksurface.h"
+
+#include "gdkrectangle.h"
+#include "gdkinternals.h"
+#include "gdkintl.h"
+#include "gdkdisplayprivate.h"
+#include "gdkdeviceprivate.h"
+#include "gdkmarshalers.h"
+#include "gdkframeclockidle.h"
+#include "gdksurfaceimpl.h"
+#include "gdkglcontextprivate.h"
+#include "gdkdrawingcontextprivate.h"
+#include "gdk-private.h"
+
+#include <math.h>
+
+#include <epoxy/gl.h>
+
+/* for the use of round() */
+#include "fallback-c89.c"
+
+#ifdef GDK_WINDOWING_WAYLAND
+#include "wayland/gdkwayland.h"
+#endif
+
+#undef DEBUG_WINDOW_PRINTING
+
+
+/**
+ * SECTION:windows
+ * @Short_description: Onscreen display areas in the target window system
+ * @Title: Windows
+ *
+ * A #GdkSurface is a (usually) rectangular region on the screen.
+ * It’s a low-level object, used to implement high-level objects such as
+ * #GtkWidget and #GtkWindow on the GTK+ level. A #GtkWindow is a toplevel
+ * window, the thing a user might think of as a “window” with a titlebar
+ * and so on; a #GtkWindow may contain many sub-GdkSurfaces.
+ */
+
+/**
+ * GdkSurface:
+ *
+ * The GdkSurface struct contains only private fields and
+ * should not be accessed directly.
+ */
+
+/* Historically a GdkSurface always matches a platform native window,
+ * be it a toplevel window or a child window. In this setup the
+ * GdkSurface (and other GdkDrawables) were platform independent classes,
+ * and the actual platform specific implementation was in a delegate
+ * object available as “impl” in the window object.
+ *
+ * With the addition of client side windows this changes a bit. The
+ * application-visible GdkSurface object behaves as it did before, but
+ * such windows now don't a corresponding native window. Instead subwindows
+ * windows are “client side”, i.e. emulated by the gdk code such
+ * that clipping, drawing, moving, events etc work as expected.
+ *
+ * GdkSurfaces have a pointer to the “impl window” they are in, i.e.
+ * the topmost GdkSurface which have the same “impl” value. This is stored
+ * in impl_window, which is different from the window itself only for client
+ * side windows.
+ * All GdkSurfaces (native or not) track the position of the window in the parent
+ * (x, y), the size of the window (width, height), the position of the window
+ * with respect to the impl window (abs_x, abs_y). We also track the clip
+ * region of the window wrt parent windows, in window-relative coordinates (clip_region).
+ */
+
+enum {
+ MOVED_TO_RECT,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0,
+ PROP_CURSOR,
+ PROP_DISPLAY,
+ PROP_STATE,
+ LAST_PROP
+};
+
+/* Global info */
+
+static void gdk_surface_finalize (GObject *object);
+
+static void gdk_surface_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gdk_surface_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gdk_surface_clear_backing_region (GdkSurface *window);
+
+static void recompute_visible_regions (GdkSurface *private,
+ gboolean recalculate_children);
+static void gdk_surface_invalidate_in_parent (GdkSurface *private);
+static void update_cursor (GdkDisplay *display,
+ GdkDevice *device);
+static void impl_window_add_update_area (GdkSurface *impl_window,
+ cairo_region_t *region);
+static void gdk_surface_invalidate_region_full (GdkSurface *window,
+ const cairo_region_t *region,
+ gboolean invalidate_children);
+static void gdk_surface_invalidate_rect_full (GdkSurface *window,
+ const GdkRectangle *rect,
+ gboolean invalidate_children);
+static cairo_surface_t *gdk_surface_ref_impl_surface (GdkSurface *window);
+
+static void gdk_surface_set_frame_clock (GdkSurface *window,
+ GdkFrameClock *clock);
+
+
+static guint signals[LAST_SIGNAL] = { 0 };
+static GParamSpec *properties[LAST_PROP] = { NULL, };
+
+G_DEFINE_ABSTRACT_TYPE (GdkSurface, gdk_surface, G_TYPE_OBJECT)
+
+#ifdef DEBUG_WINDOW_PRINTING
+char *
+print_region (cairo_region_t *region)
+{
+ GString *s = g_string_new ("{");
+ if (cairo_region_is_empty (region))
+ {
+ g_string_append (s, "empty");
+ }
+ else
+ {
+ int num = cairo_region_num_rectangles (region);
+ cairo_rectangle_int_t r;
+
+ if (num == 1)
+ {
+ cairo_region_get_rectangle (region, 0, &r);
+ g_string_append_printf (s, "%dx%d @%d,%d", r.width, r.height, r.x, r.y);
+ }
+ else
+ {
+ int i;
+ cairo_region_get_extents (region, &r);
+ g_string_append_printf (s, "extent: %dx%d @%d,%d, details: ", r.width, r.height, r.x, r.y);
+ for (i = 0; i < num; i++)
+ {
+ cairo_region_get_rectangle (region, i, &r);
+ g_string_append_printf (s, "[%dx%d @%d,%d]", r.width, r.height, r.x, r.y);
+ if (i != num -1)
+ g_string_append (s, ", ");
+ }
+ }
+ }
+ g_string_append (s, "}");
+ return g_string_free (s, FALSE);
+}
+#endif
+
+static GList *
+list_insert_link_before (GList *list,
+ GList *sibling,
+ GList *link)
+{
+ if (list == NULL || sibling == list)
+ {
+ link->prev = NULL;
+ link->next = list;
+ if (list)
+ list->prev = link;
+ return link;
+ }
+ else if (sibling == NULL)
+ {
+ GList *last = g_list_last (list);
+
+ last->next = link;
+ link->prev = last;
+ link->next = NULL;
+
+ return list;
+ }
+ else
+ {
+ link->next = sibling;
+ link->prev = sibling->prev;
+ sibling->prev = link;
+
+ if (link->prev)
+ link->prev->next = link;
+
+ return list;
+ }
+}
+
+static void
+gdk_surface_init (GdkSurface *window)
+{
+ /* 0-initialization is good for all other fields. */
+
+ window->window_type = GDK_SURFACE_CHILD;
+
+ window->state = GDK_SURFACE_STATE_WITHDRAWN;
+ window->fullscreen_mode = GDK_FULLSCREEN_ON_CURRENT_MONITOR;
+ window->width = 1;
+ window->height = 1;
+ window->toplevel_window_type = -1;
+ window->children_list_node.data = window;
+
+ window->device_cursor = g_hash_table_new_full (NULL, NULL,
+ NULL, g_object_unref);
+}
+
+static void
+gdk_surface_class_init (GdkSurfaceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdk_surface_finalize;
+ object_class->set_property = gdk_surface_set_property;
+ object_class->get_property = gdk_surface_get_property;
+
+ /* Properties */
+
+ /**
+ * GdkSurface:cursor:
+ *
+ * The mouse pointer for a #GdkSurface. See gdk_surface_set_cursor() and
+ * gdk_surface_get_cursor() for details.
+ */
+ properties[PROP_CURSOR] =
+ g_param_spec_object ("cursor",
+ P_("Cursor"),
+ P_("Cursor"),
+ GDK_TYPE_CURSOR,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GdkSurface:display:
+ *
+ * The #GdkDisplay connection of the window. See gdk_surface_get_display()
+ * for details.
+ */
+ properties[PROP_DISPLAY] =
+ g_param_spec_object ("display",
+ P_("Display"),
+ P_("Display"),
+ GDK_TYPE_DISPLAY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATE] =
+ g_param_spec_flags ("state",
+ P_("State"),
+ P_("State"),
+ GDK_TYPE_SURFACE_STATE, GDK_SURFACE_STATE_WITHDRAWN,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, properties);
+
+ /**
+ * GdkSurface::moved-to-rect:
+ * @window: the #GdkSurface that moved
+ * @flipped_rect: (nullable): the position of @window after any possible
+ * flipping or %NULL if the backend can't obtain it
+ * @final_rect: (nullable): the final position of @window or %NULL if the
+ * backend can't obtain it
+ * @flipped_x: %TRUE if the anchors were flipped horizontally
+ * @flipped_y: %TRUE if the anchors were flipped vertically
+ *
+ * Emitted when the position of @window is finalized after being moved to a
+ * destination rectangle.
+ *
+ * @window might be flipped over the destination rectangle in order to keep
+ * it on-screen, in which case @flipped_x and @flipped_y will be set to %TRUE
+ * accordingly.
+ *
+ * @flipped_rect is the ideal position of @window after any possible
+ * flipping, but before any possible sliding. @final_rect is @flipped_rect,
+ * but possibly translated in the case that flipping is still ineffective in
+ * keeping @window on-screen.
+ * Stability: Private
+ */
+ signals[MOVED_TO_RECT] =
+ g_signal_new (g_intern_static_string ("moved-to-rect"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL,
+ NULL,
+ _gdk_marshal_VOID__POINTER_POINTER_BOOLEAN_BOOLEAN,
+ G_TYPE_NONE,
+ 4,
+ G_TYPE_POINTER,
+ G_TYPE_POINTER,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN);
+}
+
+static void
+seat_removed_cb (GdkDisplay *display,
+ GdkSeat *seat,
+ GdkSurface *window)
+{
+ GdkDevice *device = gdk_seat_get_pointer (seat);
+
+ window->devices_inside = g_list_remove (window->devices_inside, device);
+ g_hash_table_remove (window->device_cursor, device);
+
+ if (window->device_events)
+ g_hash_table_remove (window->device_events, device);
+}
+
+static void
+gdk_surface_finalize (GObject *object)
+{
+ GdkSurface *window = GDK_SURFACE (object);
+
+ g_signal_handlers_disconnect_by_func (gdk_surface_get_display (window),
+ seat_removed_cb, window);
+
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ if (GDK_SURFACE_TYPE (window) != GDK_SURFACE_FOREIGN)
+ {
+ g_warning ("losing last reference to undestroyed window");
+ _gdk_surface_destroy (window, FALSE);
+ }
+ else
+ /* We use TRUE here, to keep us from actually calling
+ * XDestroyWindow() on the window
+ */
+ _gdk_surface_destroy (window, TRUE);
+ }
+
+ if (window->impl)
+ {
+ g_object_unref (window->impl);
+ window->impl = NULL;
+ }
+
+ if (window->impl_window != window)
+ {
+ g_object_unref (window->impl_window);
+ window->impl_window = NULL;
+ }
+
+ if (window->shape)
+ cairo_region_destroy (window->shape);
+
+ if (window->input_shape)
+ cairo_region_destroy (window->input_shape);
+
+ if (window->cursor)
+ g_object_unref (window->cursor);
+
+ if (window->device_cursor)
+ g_hash_table_destroy (window->device_cursor);
+
+ if (window->device_events)
+ g_hash_table_destroy (window->device_events);
+
+ if (window->devices_inside)
+ g_list_free (window->devices_inside);
+
+ g_clear_object (&window->display);
+
+ if (window->opaque_region)
+ cairo_region_destroy (window->opaque_region);
+
+ G_OBJECT_CLASS (gdk_surface_parent_class)->finalize (object);
+}
+
+static void
+gdk_surface_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkSurface *window = GDK_SURFACE (object);
+
+ switch (prop_id)
+ {
+ case PROP_CURSOR:
+ gdk_surface_set_cursor (window, g_value_get_object (value));
+ break;
+
+ case PROP_DISPLAY:
+ window->display = g_value_dup_object (value);
+ g_assert (window->display != NULL);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_surface_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkSurface *window = GDK_SURFACE (object);
+
+ switch (prop_id)
+ {
+ case PROP_CURSOR:
+ g_value_set_object (value, gdk_surface_get_cursor (window));
+ break;
+
+ case PROP_DISPLAY:
+ g_value_set_object (value, window->display);
+ break;
+
+ case PROP_STATE:
+ g_value_set_flags (value, window->state);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+gdk_surface_is_subsurface (GdkSurface *window)
+{
+ return window->window_type == GDK_SURFACE_SUBSURFACE;
+}
+
+static GdkSurface *
+gdk_surface_get_impl_window (GdkSurface *window)
+{
+ return window->impl_window;
+}
+
+GdkSurface *
+_gdk_surface_get_impl_window (GdkSurface *window)
+{
+ return gdk_surface_get_impl_window (window);
+}
+
+static gboolean
+gdk_surface_has_impl (GdkSurface *window)
+{
+ return window->impl_window == window;
+}
+
+static gboolean
+gdk_surface_is_toplevel (GdkSurface *window)
+{
+ return
+ window->parent == NULL ||
+ window->parent->window_type == GDK_SURFACE_ROOT;
+}
+
+gboolean
+_gdk_surface_has_impl (GdkSurface *window)
+{
+ return gdk_surface_has_impl (window);
+}
+
+static gboolean
+gdk_surface_has_no_impl (GdkSurface *window)
+{
+ return window->impl_window != window;
+}
+
+static void
+remove_sibling_overlapped_area (GdkSurface *window,
+ cairo_region_t *region)
+{
+ GdkSurface *parent;
+ GdkSurface *sibling;
+ cairo_region_t *child_region;
+ GdkRectangle r;
+ GList *l;
+
+ parent = window->parent;
+
+ if (gdk_surface_is_toplevel (window))
+ return;
+
+ /* Convert from from window coords to parent coords */
+ cairo_region_translate (region, window->x, window->y);
+
+ for (l = parent->children; l; l = l->next)
+ {
+ sibling = l->data;
+
+ if (sibling == window)
+ break;
+
+ if (!GDK_SURFACE_IS_MAPPED (sibling) || sibling->input_only)
+ continue;
+
+ r.x = sibling->x;
+ r.y = sibling->y;
+ r.width = sibling->width;
+ r.height = sibling->height;
+
+ child_region = cairo_region_create_rectangle (&r);
+
+ if (sibling->shape)
+ {
+ /* Adjust shape region to parent window coords */
+ cairo_region_translate (sibling->shape, sibling->x, sibling->y);
+ cairo_region_intersect (child_region, sibling->shape);
+ cairo_region_translate (sibling->shape, -sibling->x, -sibling->y);
+ }
+
+ cairo_region_subtract (region, child_region);
+ cairo_region_destroy (child_region);
+ }
+
+ remove_sibling_overlapped_area (parent, region);
+
+ /* Convert back to window coords */
+ cairo_region_translate (region, -window->x, -window->y);
+}
+
+static void
+remove_child_area (GdkSurface *window,
+ gboolean for_input,
+ cairo_region_t *region)
+{
+ GdkSurface *child;
+ cairo_region_t *child_region;
+ GdkRectangle r;
+ GList *l;
+
+ for (l = window->children; l; l = l->next)
+ {
+ child = l->data;
+
+ /* If region is empty already, no need to do
+ anything potentially costly */
+ if (cairo_region_is_empty (region))
+ break;
+
+ if (!GDK_SURFACE_IS_MAPPED (child) || child->input_only)
+ continue;
+
+ r.x = child->x;
+ r.y = child->y;
+ r.width = child->width;
+ r.height = child->height;
+
+ /* Bail early if child totally outside region */
+ if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
+ continue;
+
+ child_region = cairo_region_create_rectangle (&r);
+
+ if (child->shape)
+ {
+ /* Adjust shape region to parent window coords */
+ cairo_region_translate (child->shape, child->x, child->y);
+ cairo_region_intersect (child_region, child->shape);
+ cairo_region_translate (child->shape, -child->x, -child->y);
+ }
+
+ if (for_input)
+ {
+ if (child->input_shape)
+ cairo_region_intersect (child_region, child->input_shape);
+ }
+
+ cairo_region_subtract (region, child_region);
+ cairo_region_destroy (child_region);
+ }
+}
+
+static gboolean
+should_apply_clip_as_shape (GdkSurface *window)
+{
+ return
+ gdk_surface_has_impl (window) &&
+ /* Not for non-shaped toplevels */
+ (window->shape != NULL || window->applied_shape) &&
+ /* or for foreign windows */
+ window->window_type != GDK_SURFACE_FOREIGN &&
+ /* or for the root window */
+ window->window_type != GDK_SURFACE_ROOT;
+}
+
+static void
+apply_shape (GdkSurface *window,
+ cairo_region_t *region)
+{
+ GdkSurfaceImplClass *impl_class;
+
+ /* We trash whether we applied a shape so that
+ we can avoid unsetting it many times, which
+ could happen in e.g. apply_clip_as_shape as
+ windows get resized */
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ if (region)
+ impl_class->shape_combine_region (window,
+ region, 0, 0);
+ else if (window->applied_shape)
+ impl_class->shape_combine_region (window,
+ NULL, 0, 0);
+
+ window->applied_shape = region != NULL;
+}
+
+static gboolean
+region_rect_equal (const cairo_region_t *region,
+ const GdkRectangle *rect)
+{
+ GdkRectangle extents;
+
+ if (cairo_region_num_rectangles (region) != 1)
+ return FALSE;
+
+ cairo_region_get_extents (region, &extents);
+
+ return extents.x == rect->x &&
+ extents.y == rect->y &&
+ extents.width == rect->width &&
+ extents.height == rect->height;
+}
+
+static void
+apply_clip_as_shape (GdkSurface *window)
+{
+ GdkRectangle r;
+ cairo_region_t *region;
+
+ r.x = r.y = 0;
+ r.width = window->width;
+ r.height = window->height;
+
+ region = cairo_region_copy (window->clip_region);
+ remove_sibling_overlapped_area (window, region);
+
+ /* We only apply the clip region if would differ
+ from the actual clip region implied by the size
+ of the window. This is to avoid unneccessarily
+ adding meaningless shapes to all native subwindows */
+ if (!region_rect_equal (region, &r))
+ apply_shape (window, region);
+ else
+ apply_shape (window, NULL);
+
+ cairo_region_destroy (region);
+}
+
+static void
+recompute_visible_regions_internal (GdkSurface *private,
+ gboolean recalculate_clip,
+ gboolean recalculate_children)
+{
+ GdkRectangle r;
+ GList *l;
+ GdkSurface *child;
+ cairo_region_t *new_clip;
+ gboolean clip_region_changed;
+ gboolean abs_pos_changed;
+ int old_abs_x, old_abs_y;
+
+ old_abs_x = private->abs_x;
+ old_abs_y = private->abs_y;
+
+ /* Update absolute position */
+ if ((gdk_surface_has_impl (private) &&
+ private->window_type != GDK_SURFACE_SUBSURFACE) ||
+ (gdk_surface_is_toplevel (private) &&
+ private->window_type == GDK_SURFACE_SUBSURFACE))
+ {
+ /* Native windows and toplevel subsurfaces start here */
+ private->abs_x = 0;
+ private->abs_y = 0;
+ }
+ else
+ {
+ private->abs_x = private->parent->abs_x + private->x;
+ private->abs_y = private->parent->abs_y + private->y;
+ }
+
+ abs_pos_changed =
+ private->abs_x != old_abs_x ||
+ private->abs_y != old_abs_y;
+
+ /* Update clip region based on:
+ * parent clip
+ * window size/position
+ */
+ clip_region_changed = FALSE;
+ if (recalculate_clip)
+ {
+ if (private->viewable)
+ {
+ /* Calculate visible region (sans children) in parent window coords */
+ r.x = private->x;
+ r.y = private->y;
+ r.width = private->width;
+ r.height = private->height;
+ new_clip = cairo_region_create_rectangle (&r);
+
+ if (!gdk_surface_is_toplevel (private))
+ cairo_region_intersect (new_clip, private->parent->clip_region);
+
+ /* Convert from parent coords to window coords */
+ cairo_region_translate (new_clip, -private->x, -private->y);
+
+ if (should_apply_clip_as_shape (private) && private->shape)
+ cairo_region_intersect (new_clip, private->shape);
+ }
+ else
+ new_clip = cairo_region_create ();
+
+ if (private->clip_region == NULL ||
+ !cairo_region_equal (private->clip_region, new_clip))
+ clip_region_changed = TRUE;
+
+ if (private->clip_region)
+ cairo_region_destroy (private->clip_region);
+ private->clip_region = new_clip;
+ }
+
+ /* Update all children, recursively (except for root, where children are not exact). */
+ if ((abs_pos_changed || clip_region_changed || recalculate_children) &&
+ private->window_type != GDK_SURFACE_ROOT)
+ {
+ for (l = private->children; l; l = l->next)
+ {
+ child = l->data;
+ /* Only recalculate clip if the the clip region changed, otherwise
+ * there is no way the child clip region could change (its has not e.g. moved)
+ * Except if recalculate_children is set to force child updates
+ */
+ recompute_visible_regions_internal (child,
+ recalculate_clip && (clip_region_changed || recalculate_children),
+ FALSE);
+ }
+ }
+}
+
+/* Call this when private has changed in one or more of these ways:
+ * size changed
+ * window moved
+ * new window added
+ * stacking order of window changed
+ * child deleted
+ *
+ * It will recalculate abs_x/y and the clip regions
+ *
+ * Unless the window didn’t change stacking order or size/pos, pass in TRUE
+ * for recalculate_siblings. (Mostly used internally for the recursion)
+ *
+ * If a child window was removed (and you can’t use that child for
+ * recompute_visible_regions), pass in TRUE for recalculate_children on the parent
+ */
+static void
+recompute_visible_regions (GdkSurface *private,
+ gboolean recalculate_children)
+{
+ GdkSurface *toplevel;
+
+ toplevel = gdk_surface_get_toplevel (private);
+ toplevel->geometry_dirty = TRUE;
+
+ recompute_visible_regions_internal (private,
+ TRUE,
+ recalculate_children);
+}
+
+static void
+gdk_surface_clear_old_updated_area (GdkSurface *window)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ if (window->old_updated_area[i])
+ {
+ cairo_region_destroy (window->old_updated_area[i]);
+ window->old_updated_area[i] = NULL;
+ }
+ }
+}
+
+static void
+gdk_surface_append_old_updated_area (GdkSurface *window,
+ cairo_region_t *region)
+{
+ if (window->old_updated_area[1])
+ cairo_region_destroy (window->old_updated_area[1]);
+ window->old_updated_area[1] = window->old_updated_area[0];
+ window->old_updated_area[0] = cairo_region_reference (region);
+}
+
+void
+_gdk_surface_update_size (GdkSurface *window)
+{
+ gdk_surface_clear_old_updated_area (window);
+ recompute_visible_regions (window, FALSE);
+}
+
+static GdkEventMask
+get_native_device_event_mask (GdkSurface *private,
+ GdkDevice *device)
+{
+ GdkEventMask event_mask;
+
+ if (device)
+ event_mask = GPOINTER_TO_INT (g_hash_table_lookup (private->device_events, device));
+ else
+ event_mask = private->event_mask;
+
+ if (private->window_type == GDK_SURFACE_ROOT ||
+ private->window_type == GDK_SURFACE_FOREIGN)
+ return event_mask;
+ else
+ {
+ GdkEventMask mask;
+
+ mask = private->event_mask;
+
+ /* We need thse for all native windows so we can
+ emulate events on children: */
+ mask |=
+ GDK_EXPOSURE_MASK |
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
+ GDK_TOUCH_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_SCROLL_MASK;
+
+ return mask;
+ }
+}
+
+static GdkEventMask
+get_native_event_mask (GdkSurface *private)
+{
+ return get_native_device_event_mask (private, NULL);
+}
+
+GdkSurface*
+gdk_surface_new (GdkDisplay *display,
+ GdkSurface *parent,
+ GdkSurfaceAttr *attributes)
+{
+ GdkSurface *window;
+ gboolean native;
+ GdkEventMask event_mask;
+
+ g_return_val_if_fail (attributes != NULL, NULL);
+
+ if (parent != NULL && GDK_SURFACE_DESTROYED (parent))
+ {
+ g_warning ("gdk_surface_new(): parent is destroyed");
+ return NULL;
+ }
+
+ window = _gdk_display_create_window (display);
+
+ window->parent = parent;
+
+ window->accept_focus = TRUE;
+ window->focus_on_map = TRUE;
+
+ window->x = attributes->x;
+ window->y = attributes->y;
+ window->width = (attributes->width > 1) ? (attributes->width) : (1);
+ window->height = (attributes->height > 1) ? (attributes->height) : (1);
+ window->alpha = 255;
+
+ if (attributes->wclass == GDK_INPUT_ONLY)
+ {
+ /* Backwards compatiblity - we've always ignored
+ * attributes->window_type for input-only windows
+ * before
+ */
+ if (parent == NULL)
+ window->window_type = GDK_SURFACE_TEMP;
+ else
+ window->window_type = GDK_SURFACE_CHILD;
+ }
+ else
+ window->window_type = attributes->window_type;
+
+ /* Sanity checks */
+ switch (window->window_type)
+ {
+ case GDK_SURFACE_TOPLEVEL:
+ case GDK_SURFACE_TEMP:
+ if (parent != NULL && GDK_SURFACE_TYPE (parent) != GDK_SURFACE_ROOT)
+ g_warning (G_STRLOC "Toplevel windows must be created as children of\n"
+ "a window of type GDK_SURFACE_ROOT");
+ break;
+ case GDK_SURFACE_SUBSURFACE:
+#ifdef GDK_WINDOWING_WAYLAND
+ if (!GDK_IS_WAYLAND_DISPLAY (display))
+ {
+ g_warning (G_STRLOC "Subsurface windows can only be used on Wayland");
+ return NULL;
+ }
+#endif
+ break;
+ case GDK_SURFACE_CHILD:
+ if (GDK_SURFACE_TYPE (parent) == GDK_SURFACE_ROOT ||
+ GDK_SURFACE_TYPE (parent) == GDK_SURFACE_FOREIGN)
+ {
+ g_warning (G_STRLOC "Child windows must not be created as children of\n"
+ "a window of type GDK_SURFACE_ROOT or GDK_SURFACE_FOREIGN");
+ return NULL;
+ }
+ break;
+ default:
+ g_warning (G_STRLOC "cannot make windows of type %d", window->window_type);
+ return NULL;
+ }
+
+ window->event_mask = GDK_ALL_EVENTS_MASK;
+
+ if (attributes->wclass == GDK_INPUT_OUTPUT)
+ {
+ window->input_only = FALSE;
+ }
+ else
+ {
+ window->input_only = TRUE;
+ }
+
+ native = FALSE;
+
+ if (window->parent != NULL)
+ window->parent->children = g_list_concat (&window->children_list_node, window->parent->children);
+ else
+ {
+ GdkFrameClock *frame_clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE, NULL);
+ gdk_surface_set_frame_clock (window, frame_clock);
+ g_object_unref (frame_clock);
+
+ native = TRUE; /* Always use native windows for toplevels */
+ }
+
+#ifdef GDK_WINDOWING_WAYLAND
+ if (window->window_type == GDK_SURFACE_SUBSURFACE)
+ native = TRUE; /* Always use native windows for subsurfaces as well */
+#endif
+
+ if (native)
+ {
+ event_mask = get_native_event_mask (window);
+
+ /* Create the impl */
+ _gdk_display_create_window_impl (display, window, parent, event_mask, attributes);
+ window->impl_window = window;
+ }
+ else
+ {
+ window->impl_window = g_object_ref (window->parent->impl_window);
+ window->impl = g_object_ref (window->impl_window->impl);
+ }
+
+ recompute_visible_regions (window, FALSE);
+
+ g_signal_connect (display, "seat-removed", G_CALLBACK (seat_removed_cb), window);
+
+ return window;
+}
+
+/**
+ * gdk_surface_new_toplevel: (constructor)
+ * @display: the display to create the window on
+ * @width: width of new window
+ * @height: height of new window
+ *
+ * Creates a new toplevel window. The window will be managed by the window
+ * manager.
+ *
+ * Returns: (transfer full): the new #GdkSurface
+ **/
+GdkSurface *
+gdk_surface_new_toplevel (GdkDisplay *display,
+ gint width,
+ gint height)
+{
+ GdkSurfaceAttr attr;
+
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+ attr.wclass = GDK_INPUT_OUTPUT;
+ attr.x = 0;
+ attr.y = 0;
+ attr.width = width;
+ attr.height = height;
+ attr.window_type = GDK_SURFACE_TOPLEVEL;
+
+ return gdk_surface_new (display, NULL, &attr);
+}
+
+/**
+ * gdk_surface_new_popup: (constructor)
+ * @display: the display to create the window on
+ * @position: position of the window on screen
+ *
+ * Creates a new toplevel popup window. The window will bypass window
+ * management.
+ *
+ * Returns: (transfer full): the new #GdkSurface
+ **/
+GdkSurface *
+gdk_surface_new_popup (GdkDisplay *display,
+ const GdkRectangle *position)
+{
+ GdkSurfaceAttr attr;
+
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+ g_return_val_if_fail (position != NULL, NULL);
+
+ attr.wclass = GDK_INPUT_OUTPUT;
+ attr.x = position->x;
+ attr.y = position->y;
+ attr.width = position->width;
+ attr.height = position->height;
+ attr.window_type = GDK_SURFACE_TEMP;
+
+ return gdk_surface_new (display, NULL, &attr);
+}
+
+/**
+ * gdk_surface_new_temp: (constructor)
+ * @display: the display to create the window on
+ *
+ * Creates a new toplevel temporary window. The window will be
+ * situated off-screen and not handle output.
+ *
+ * You most likely do not want to use this function.
+ *
+ * Returns: (transfer full): the new #GdkSurface
+ **/
+GdkSurface *
+gdk_surface_new_temp (GdkDisplay *display)
+{
+ GdkSurfaceAttr attr;
+
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+ attr.wclass = GDK_INPUT_ONLY;
+ attr.x = -100;
+ attr.y = -100;
+ attr.width = 10;
+ attr.height = 10;
+ attr.window_type = GDK_SURFACE_TEMP;
+
+ return gdk_surface_new (display, NULL, &attr);
+}
+
+/**
+ * gdk_surface_new_child: (constructor)
+ * @parent: the parent window
+ * @position: placement of the window inside @parent
+ *
+ * Creates a new client-side child window.
+ *
+ * Returns: (transfer full): the new #GdkSurface
+ **/
+GdkSurface *
+gdk_surface_new_child (GdkSurface *parent,
+ const GdkRectangle *position)
+{
+ GdkSurfaceAttr attr;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (parent), NULL);
+
+ attr.wclass = GDK_INPUT_OUTPUT;
+ attr.x = position->x;
+ attr.y = position->y;
+ attr.width = position->width;
+ attr.height = position->height;
+ attr.window_type = GDK_SURFACE_CHILD;
+
+ return gdk_surface_new (gdk_surface_get_display (parent), parent, &attr);
+}
+
+static void
+update_pointer_info_foreach (GdkDisplay *display,
+ GdkDevice *device,
+ GdkPointerSurfaceInfo *pointer_info,
+ gpointer user_data)
+{
+ GdkSurface *window = user_data;
+
+ if (pointer_info->window_under_pointer == window)
+ {
+ g_object_unref (pointer_info->window_under_pointer);
+ pointer_info->window_under_pointer = NULL;
+ }
+}
+
+static void
+window_remove_from_pointer_info (GdkSurface *window,
+ GdkDisplay *display)
+{
+ _gdk_display_pointer_info_foreach (display,
+ update_pointer_info_foreach,
+ window);
+}
+
+static void
+gdk_surface_free_current_paint (GdkSurface *window)
+{
+ cairo_surface_destroy (window->current_paint.surface);
+ window->current_paint.surface = NULL;
+
+ cairo_region_destroy (window->current_paint.region);
+ window->current_paint.region = NULL;
+
+ window->current_paint.surface_needs_composite = FALSE;
+}
+
+/**
+ * _gdk_surface_destroy_hierarchy:
+ * @window: a #GdkSurface
+ * @recursing: If %TRUE, then this is being called because a parent
+ * was destroyed.
+ * @recursing_native: If %TRUE, then this is being called because a native parent
+ * was destroyed. This generally means that the call to the
+ * windowing system to destroy the window can be omitted, since
+ * it will be destroyed as a result of the parent being destroyed.
+ * Unless @foreign_destroy.
+ * @foreign_destroy: If %TRUE, the window or a parent was destroyed by some
+ * external agency. The window has already been destroyed and no
+ * windowing system calls should be made. (This may never happen
+ * for some windowing systems.)
+ *
+ * Internal function to destroy a window. Like gdk_surface_destroy(),
+ * but does not drop the reference count created by gdk_surface_new().
+ **/
+static void
+_gdk_surface_destroy_hierarchy (GdkSurface *window,
+ gboolean recursing,
+ gboolean recursing_native,
+ gboolean foreign_destroy)
+{
+ GdkSurfaceImplClass *impl_class;
+ GdkSurface *temp_window;
+ GdkDisplay *display;
+ GList *tmp;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ display = gdk_surface_get_display (window);
+
+ switch (window->window_type)
+ {
+ default:
+ g_assert_not_reached ();
+ break;
+
+ case GDK_SURFACE_ROOT:
+ if (!gdk_display_is_closed (display))
+ {
+ g_error ("attempted to destroy root window");
+ break;
+ }
+ /* else fall thru */
+ case GDK_SURFACE_TOPLEVEL:
+ case GDK_SURFACE_CHILD:
+ case GDK_SURFACE_TEMP:
+ case GDK_SURFACE_FOREIGN:
+ case GDK_SURFACE_SUBSURFACE:
+ if (window->window_type == GDK_SURFACE_FOREIGN && !foreign_destroy)
+ {
+ }
+ else
+ {
+ if (window->parent)
+ {
+ if (window->parent->children)
+ window->parent->children = g_list_remove_link (window->parent->children, &window->children_list_node);
+
+ if (!recursing &&
+ GDK_SURFACE_IS_MAPPED (window))
+ {
+ recompute_visible_regions (window, FALSE);
+ gdk_surface_invalidate_in_parent (window);
+ }
+ }
+
+ if (window->gl_paint_context)
+ {
+ /* Make sure to destroy if current */
+ g_object_run_dispose (G_OBJECT (window->gl_paint_context));
+ g_object_unref (window->gl_paint_context);
+ window->gl_paint_context = NULL;
+ }
+
+ if (window->frame_clock)
+ {
+ g_object_run_dispose (G_OBJECT (window->frame_clock));
+ gdk_surface_set_frame_clock (window, NULL);
+ }
+
+ gdk_surface_free_current_paint (window);
+
+ if (window->window_type == GDK_SURFACE_FOREIGN)
+ g_assert (window->children == NULL);
+ else
+ {
+ tmp = window->children;
+ window->children = NULL;
+ /* No need to free children list, its all made up of in-struct nodes */
+
+ while (tmp)
+ {
+ temp_window = tmp->data;
+ tmp = tmp->next;
+
+ if (temp_window)
+ _gdk_surface_destroy_hierarchy (temp_window,
+ TRUE,
+ recursing_native || gdk_surface_has_impl (window),
+ foreign_destroy);
+ }
+ }
+
+ _gdk_surface_clear_update_area (window);
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ if (gdk_surface_has_impl (window))
+ impl_class->destroy (window, recursing_native, foreign_destroy);
+ else
+ {
+ /* hide to make sure we repaint and break grabs */
+ gdk_surface_hide (window);
+ }
+
+ window->state |= GDK_SURFACE_STATE_WITHDRAWN;
+ window->parent = NULL;
+ window->destroyed = TRUE;
+
+ window_remove_from_pointer_info (window, display);
+
+ if (window->clip_region)
+ {
+ cairo_region_destroy (window->clip_region);
+ window->clip_region = NULL;
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_STATE]);
+ }
+ break;
+ }
+}
+
+/**
+ * _gdk_surface_destroy:
+ * @window: a #GdkSurface
+ * @foreign_destroy: If %TRUE, the window or a parent was destroyed by some
+ * external agency. The window has already been destroyed and no
+ * windowing system calls should be made. (This may never happen
+ * for some windowing systems.)
+ *
+ * Internal function to destroy a window. Like gdk_surface_destroy(),
+ * but does not drop the reference count created by gdk_surface_new().
+ **/
+void
+_gdk_surface_destroy (GdkSurface *window,
+ gboolean foreign_destroy)
+{
+ _gdk_surface_destroy_hierarchy (window, FALSE, FALSE, foreign_destroy);
+}
+
+/**
+ * gdk_surface_destroy:
+ * @window: a #GdkSurface
+ *
+ * Destroys the window system resources associated with @window and decrements @window's
+ * reference count. The window system resources for all children of @window are also
+ * destroyed, but the children’s reference counts are not decremented.
+ *
+ * Note that a window will not be destroyed automatically when its reference count
+ * reaches zero. You must call this function yourself before that happens.
+ *
+ **/
+void
+gdk_surface_destroy (GdkSurface *window)
+{
+ _gdk_surface_destroy_hierarchy (window, FALSE, FALSE, FALSE);
+ g_object_unref (window);
+}
+
+/**
+ * gdk_surface_set_user_data:
+ * @window: a #GdkSurface
+ * @user_data: (allow-none) (type GObject.Object): user data
+ *
+ * For most purposes this function is deprecated in favor of
+ * g_object_set_data(). However, for historical reasons GTK+ stores
+ * the #GtkWidget that owns a #GdkSurface as user data on the
+ * #GdkSurface. So, custom widget implementations should use
+ * this function for that. If GTK+ receives an event for a #GdkSurface,
+ * and the user data for the window is non-%NULL, GTK+ will assume the
+ * user data is a #GtkWidget, and forward the event to that widget.
+ *
+ **/
+void
+gdk_surface_set_user_data (GdkSurface *window,
+ gpointer user_data)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ window->user_data = user_data;
+}
+
+/**
+ * gdk_surface_get_user_data:
+ * @window: a #GdkSurface
+ * @data: (out): return location for user data
+ *
+ * Retrieves the user data for @window, which is normally the widget
+ * that @window belongs to. See gdk_surface_set_user_data().
+ *
+ **/
+void
+gdk_surface_get_user_data (GdkSurface *window,
+ gpointer *data)
+{
+ *data = window->user_data;
+}
+
+/**
+ * gdk_surface_get_window_type:
+ * @window: a #GdkSurface
+ *
+ * Gets the type of the window. See #GdkSurfaceType.
+ *
+ * Returns: type of window
+ **/
+GdkSurfaceType
+gdk_surface_get_window_type (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), (GdkSurfaceType) -1);
+
+ return GDK_SURFACE_TYPE (window);
+}
+
+/**
+ * gdk_surface_get_display:
+ * @window: a #GdkSurface
+ *
+ * Gets the #GdkDisplay associated with a #GdkSurface.
+ *
+ * Returns: (transfer none): the #GdkDisplay associated with @window
+ **/
+GdkDisplay *
+gdk_surface_get_display (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ return window->display;
+}
+/**
+ * gdk_surface_is_destroyed:
+ * @window: a #GdkSurface
+ *
+ * Check to see if a window is destroyed..
+ *
+ * Returns: %TRUE if the window is destroyed
+ **/
+gboolean
+gdk_surface_is_destroyed (GdkSurface *window)
+{
+ return GDK_SURFACE_DESTROYED (window);
+}
+
+/**
+ * gdk_surface_has_native:
+ * @window: a #GdkSurface
+ *
+ * Checks whether the window has a native window or not.
+ *
+ * Returns: %TRUE if the @window has a native window, %FALSE otherwise.
+ */
+gboolean
+gdk_surface_has_native (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ return window->parent == NULL || window->parent->impl != window->impl;
+}
+
+/**
+ * gdk_surface_get_position:
+ * @window: a #GdkSurface
+ * @x: (out) (allow-none): X coordinate of window
+ * @y: (out) (allow-none): Y coordinate of window
+ *
+ * Obtains the position of the window as reported in the
+ * most-recently-processed #GdkEventConfigure. Contrast with
+ * gdk_surface_get_geometry() which queries the X server for the
+ * current window position, regardless of which events have been
+ * received or processed.
+ *
+ * The position coordinates are relative to the window’s parent window.
+ *
+ **/
+void
+gdk_surface_get_position (GdkSurface *window,
+ gint *x,
+ gint *y)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (x)
+ *x = window->x;
+ if (y)
+ *y = window->y;
+}
+
+/**
+ * gdk_surface_get_parent:
+ * @window: a #GdkSurface
+ *
+ * Obtains the parent of @window, as known to GDK. Does not query the
+ * X server; thus this returns the parent as passed to gdk_surface_new(),
+ * not the actual parent. This should never matter unless you’re using
+ * Xlib calls mixed with GDK calls on the X11 platform. It may also
+ * matter for toplevel windows, because the window manager may choose
+ * to reparent them.
+ *
+ * Returns: (transfer none): parent of @window
+ **/
+GdkSurface*
+gdk_surface_get_parent (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ if (gdk_surface_is_subsurface (window))
+ return window->transient_for;
+ else
+ return window->parent;
+}
+
+/**
+ * gdk_surface_get_toplevel:
+ * @window: a #GdkSurface
+ *
+ * Gets the toplevel window that’s an ancestor of @window.
+ *
+ * Any window type but %GDK_SURFACE_CHILD is considered a
+ * toplevel window, as is a %GDK_SURFACE_CHILD window that
+ * has a root window as parent.
+ *
+ * Returns: (transfer none): the toplevel window containing @window
+ **/
+GdkSurface *
+gdk_surface_get_toplevel (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ while (window->window_type == GDK_SURFACE_CHILD ||
+ window->window_type == GDK_SURFACE_SUBSURFACE)
+ {
+ if (gdk_surface_is_toplevel (window))
+ break;
+ window = window->parent;
+ }
+
+ return window;
+}
+
+/**
+ * gdk_surface_get_children:
+ * @window: a #GdkSurface
+ *
+ * Gets the list of children of @window known to GDK.
+ * This function only returns children created via GDK,
+ * so for example it’s useless when used with the root window;
+ * it only returns windows an application created itself.
+ *
+ * The returned list must be freed, but the elements in the
+ * list need not be.
+ *
+ * Returns: (transfer container) (element-type GdkSurface):
+ * list of child windows inside @window
+ **/
+GList*
+gdk_surface_get_children (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return NULL;
+
+ return g_list_copy (window->children);
+}
+
+/**
+ * gdk_surface_peek_children:
+ * @window: a #GdkSurface
+ *
+ * Like gdk_surface_get_children(), but does not copy the list of
+ * children, so the list does not need to be freed.
+ *
+ * Returns: (transfer none) (element-type GdkSurface):
+ * a reference to the list of child windows in @window
+ **/
+GList *
+gdk_surface_peek_children (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return NULL;
+
+ return window->children;
+}
+
+
+/**
+ * gdk_surface_get_children_with_user_data:
+ * @window: a #GdkSurface
+ * @user_data: user data to look for
+ *
+ * Gets the list of children of @window known to GDK with a
+ * particular @user_data set on it.
+ *
+ * The returned list must be freed, but the elements in the
+ * list need not be.
+ *
+ * The list is returned in (relative) stacking order, i.e. the
+ * lowest window is first.
+ *
+ * Returns: (transfer container) (element-type GdkSurface):
+ * list of child windows inside @window
+ **/
+GList *
+gdk_surface_get_children_with_user_data (GdkSurface *window,
+ gpointer user_data)
+{
+ GdkSurface *child;
+ GList *res, *l;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return NULL;
+
+ res = NULL;
+ for (l = window->children; l != NULL; l = l->next)
+ {
+ child = l->data;
+
+ if (child->user_data == user_data)
+ res = g_list_prepend (res, child);
+ }
+
+ return res;
+}
+
+
+/**
+ * gdk_surface_is_visible:
+ * @window: a #GdkSurface
+ *
+ * Checks whether the window has been mapped (with gdk_surface_show() or
+ * gdk_surface_show_unraised()).
+ *
+ * Returns: %TRUE if the window is mapped
+ **/
+gboolean
+gdk_surface_is_visible (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ return GDK_SURFACE_IS_MAPPED (window);
+}
+
+/**
+ * gdk_surface_is_viewable:
+ * @window: a #GdkSurface
+ *
+ * Check if the window and all ancestors of the window are
+ * mapped. (This is not necessarily "viewable" in the X sense, since
+ * we only check as far as we have GDK window parents, not to the root
+ * window.)
+ *
+ * Returns: %TRUE if the window is viewable
+ **/
+gboolean
+gdk_surface_is_viewable (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ if (window->destroyed)
+ return FALSE;
+
+ return window->viewable;
+}
+
+/**
+ * gdk_surface_get_state:
+ * @window: a #GdkSurface
+ *
+ * Gets the bitwise OR of the currently active window state flags,
+ * from the #GdkSurfaceState enumeration.
+ *
+ * Returns: window state bitfield
+ **/
+GdkSurfaceState
+gdk_surface_get_state (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ return window->state;
+}
+
+static cairo_content_t
+gdk_surface_get_content (GdkSurface *window)
+{
+ cairo_surface_t *surface;
+ cairo_content_t content;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
+
+ surface = gdk_surface_ref_impl_surface (window);
+ content = cairo_surface_get_content (surface);
+ cairo_surface_destroy (surface);
+
+ return content;
+}
+
+static cairo_surface_t *
+gdk_surface_ref_impl_surface (GdkSurface *window)
+{
+ return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->ref_cairo_surface (gdk_surface_get_impl_window (window));
+}
+
+GdkGLContext *
+gdk_surface_get_paint_gl_context (GdkSurface *window,
+ GError **error)
+{
+ GError *internal_error = NULL;
+
+ if (GDK_DISPLAY_DEBUG_CHECK (window->display, GL_DISABLE))
+ {
+ g_set_error_literal (error, GDK_GL_ERROR,
+ GDK_GL_ERROR_NOT_AVAILABLE,
+ _("GL support disabled via GDK_DEBUG"));
+ return NULL;
+ }
+
+ if (window->impl_window->gl_paint_context == NULL)
+ {
+ GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ if (impl_class->create_gl_context == NULL)
+ {
+ g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
+ _("The current backend does not support OpenGL"));
+ return NULL;
+ }
+
+ window->impl_window->gl_paint_context =
+ impl_class->create_gl_context (window->impl_window,
+ TRUE,
+ NULL,
+ &internal_error);
+ }
+
+ if (internal_error != NULL)
+ {
+ g_propagate_error (error, internal_error);
+ g_clear_object (&(window->impl_window->gl_paint_context));
+ return NULL;
+ }
+
+ gdk_gl_context_realize (window->impl_window->gl_paint_context, &internal_error);
+ if (internal_error != NULL)
+ {
+ g_propagate_error (error, internal_error);
+ g_clear_object (&(window->impl_window->gl_paint_context));
+ return NULL;
+ }
+
+ return window->impl_window->gl_paint_context;
+}
+
+/**
+ * gdk_surface_create_gl_context:
+ * @window: a #GdkSurface
+ * @error: return location for an error
+ *
+ * Creates a new #GdkGLContext matching the
+ * framebuffer format to the visual of the #GdkSurface. The context
+ * is disconnected from any particular window or surface.
+ *
+ * If the creation of the #GdkGLContext failed, @error will be set.
+ *
+ * Before using the returned #GdkGLContext, you will need to
+ * call gdk_gl_context_make_current() or gdk_gl_context_realize().
+ *
+ * Returns: (transfer full): the newly created #GdkGLContext, or
+ * %NULL on error
+ **/
+GdkGLContext *
+gdk_surface_create_gl_context (GdkSurface *window,
+ GError **error)
+{
+ GdkGLContext *paint_context;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ paint_context = gdk_surface_get_paint_gl_context (window, error);
+ if (paint_context == NULL)
+ return NULL;
+
+ return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->create_gl_context (window->impl_window,
+ FALSE,
+ paint_context,
+ error);
+}
+
+/**
+ * gdk_surface_create_vulkan_context:
+ * @window: a #GdkSurface
+ * @error: return location for an error
+ *
+ * Creates a new #GdkVulkanContext for rendering on @window.
+ *
+ * If the creation of the #GdkVulkanContext failed, @error will be set.
+ *
+ * Returns: (transfer full): the newly created #GdkVulkanContext, or
+ * %NULL on error
+ **/
+GdkVulkanContext *
+gdk_surface_create_vulkan_context (GdkSurface *window,
+ GError **error)
+{
+ GdkDisplay *display;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ if (GDK_DISPLAY_DEBUG_CHECK (window->display, VULKAN_DISABLE))
+ {
+ g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE,
+ _("Vulkan support disabled via GDK_DEBUG"));
+ return NULL;
+ }
+
+ display = gdk_surface_get_display (window);
+
+ if (GDK_DISPLAY_GET_CLASS (display)->vk_extension_name == NULL)
+ {
+ g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
+ "The %s backend has no Vulkan support.", G_OBJECT_TYPE_NAME (display));
+ return FALSE;
+ }
+
+ return g_initable_new (GDK_DISPLAY_GET_CLASS (display)->vk_context_type,
+ NULL,
+ error,
+ "window", window,
+ NULL);
+}
+
+static void
+gdk_surface_begin_paint_internal (GdkSurface *window,
+ const cairo_region_t *region)
+{
+ GdkRectangle clip_box;
+ GdkSurfaceImplClass *impl_class;
+ double sx, sy;
+ gboolean needs_surface;
+ cairo_content_t surface_content;
+
+ if (window->current_paint.surface != NULL)
+ {
+ g_warning ("A paint operation on the window is alredy in progress. "
+ "This is not allowed.");
+ return;
+ }
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ needs_surface = TRUE;
+ if (impl_class->begin_paint)
+ needs_surface = impl_class->begin_paint (window);
+
+ window->current_paint.region = cairo_region_copy (region);
+ cairo_region_intersect (window->current_paint.region, window->clip_region);
+ cairo_region_get_extents (window->current_paint.region, &clip_box);
+
+ surface_content = gdk_surface_get_content (window);
+
+ if (needs_surface)
+ {
+ window->current_paint.surface = gdk_surface_create_similar_surface (window,
+ surface_content,
+ MAX (clip_box.width, 1),
+ MAX (clip_box.height, 1));
+ sx = sy = 1;
+ cairo_surface_get_device_scale (window->current_paint.surface, &sx, &sy);
+ cairo_surface_set_device_offset (window->current_paint.surface, -clip_box.x*sx, -clip_box.y*sy);
+ gdk_cairo_surface_mark_as_direct (window->current_paint.surface, window);
+
+ window->current_paint.surface_needs_composite = TRUE;
+ }
+ else
+ {
+ window->current_paint.surface = gdk_surface_ref_impl_surface (window);
+ window->current_paint.surface_needs_composite = FALSE;
+ }
+
+ if (!cairo_region_is_empty (window->current_paint.region))
+ gdk_surface_clear_backing_region (window);
+}
+
+static void
+gdk_surface_end_paint_internal (GdkSurface *window)
+{
+ GdkSurfaceImplClass *impl_class;
+ cairo_t *cr;
+
+ if (window->current_paint.surface == NULL)
+ {
+ g_warning (G_STRLOC": no preceding call to gdk_surface_begin_draw_frame(), see documentation");
+ return;
+ }
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ if (impl_class->end_paint)
+ impl_class->end_paint (window);
+
+ if (window->current_paint.surface_needs_composite)
+ {
+ cairo_surface_t *surface;
+
+ surface = gdk_surface_ref_impl_surface (window);
+ cr = cairo_create (surface);
+
+ cairo_set_source_surface (cr, window->current_paint.surface, 0, 0);
+ gdk_cairo_region (cr, window->current_paint.region);
+ cairo_clip (cr);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+
+ cairo_surface_flush (surface);
+ cairo_surface_destroy (surface);
+ }
+
+ gdk_surface_free_current_paint (window);
+}
+
+/**
+ * gdk_surface_begin_draw_frame:
+ * @window: a #GdkSurface
+ * @context: (allow-none): the context used to draw the frame
+ * @region: a Cairo region
+ *
+ * Indicates that you are beginning the process of redrawing @region
+ * on @window, and provides you with a #GdkDrawingContext.
+ *
+ * If @window is a top level #GdkSurface, backed by a native window
+ * implementation, a backing store (offscreen buffer) large enough to
+ * contain @region will be created. The backing store will be initialized
+ * with the background color or background surface for @window. Then, all
+ * drawing operations performed on @window will be diverted to the
+ * backing store. When you call gdk_surface_end_frame(), the contents of
+ * the backing store will be copied to @window, making it visible
+ * on screen. Only the part of @window contained in @region will be
+ * modified; that is, drawing operations are clipped to @region.
+ *
+ * The net result of all this is to remove flicker, because the user
+ * sees the finished product appear all at once when you call
+ * gdk_surface_end_draw_frame(). If you draw to @window directly without
+ * calling gdk_surface_begin_draw_frame(), the user may see flicker
+ * as individual drawing operations are performed in sequence.
+ *
+ * When using GTK+, the widget system automatically places calls to
+ * gdk_surface_begin_draw_frame() and gdk_surface_end_draw_frame() around
+ * emissions of the `GtkWidget::draw` signal. That is, if you’re
+ * drawing the contents of the widget yourself, you can assume that the
+ * widget has a cleared background, is already set as the clip region,
+ * and already has a backing store. Therefore in most cases, application
+ * code in GTK does not need to call gdk_surface_begin_draw_frame()
+ * explicitly.
+ *
+ * Returns: (transfer none): a #GdkDrawingContext context that should be
+ * used to draw the contents of the window; the returned context is owned
+ * by GDK.
+ */
+GdkDrawingContext *
+gdk_surface_begin_draw_frame (GdkSurface *window,
+ GdkDrawContext *draw_context,
+ const cairo_region_t *region)
+{
+ GdkDrawingContext *context;
+ cairo_region_t *real_region;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+ g_return_val_if_fail (gdk_surface_has_native (window), NULL);
+ g_return_val_if_fail (gdk_surface_is_toplevel (window), NULL);
+ g_return_val_if_fail (region != NULL, NULL);
+ if (draw_context != NULL)
+ {
+ g_return_val_if_fail (GDK_IS_DRAW_CONTEXT (draw_context), NULL);
+ g_return_val_if_fail (gdk_draw_context_get_window (draw_context) == window, NULL);
+ }
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return NULL;
+
+ if (window->drawing_context != NULL)
+ {
+ g_critical ("The window %p already has a drawing context. You cannot "
+ "call gdk_surface_begin_draw_frame() without calling "
+ "gdk_surface_end_draw_frame() first.", window);
+ return NULL;
+ }
+
+ real_region = cairo_region_copy (region);
+
+ if (draw_context)
+ gdk_draw_context_begin_frame (draw_context, real_region);
+ else
+ gdk_surface_begin_paint_internal (window, real_region);
+
+ context = g_object_new (GDK_TYPE_DRAWING_CONTEXT,
+ "window", window,
+ "paint-context", draw_context,
+ "clip", real_region,
+ NULL);
+
+ /* Do not take a reference, to avoid creating cycles */
+ window->drawing_context = context;
+
+ cairo_region_destroy (real_region);
+
+ return context;
+}
+
+/**
+ * gdk_surface_end_draw_frame:
+ * @window: a #GdkSurface
+ * @context: the #GdkDrawingContext created by gdk_surface_begin_draw_frame()
+ *
+ * Indicates that the drawing of the contents of @window started with
+ * gdk_surface_begin_frame() has been completed.
+ *
+ * This function will take care of destroying the #GdkDrawingContext.
+ *
+ * It is an error to call this function without a matching
+ * gdk_surface_begin_frame() first.
+ */
+void
+gdk_surface_end_draw_frame (GdkSurface *window,
+ GdkDrawingContext *context)
+{
+ GdkDrawContext *paint_context;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (GDK_IS_DRAWING_CONTEXT (context));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (window->drawing_context == NULL)
+ {
+ g_critical ("The window %p has no drawing context. You must call "
+ "gdk_surface_begin_draw_frame() before calling "
+ "gdk_surface_end_draw_frame().", window);
+ return;
+ }
+ g_return_if_fail (window->drawing_context == context);
+
+ paint_context = gdk_drawing_context_get_paint_context (context);
+ if (paint_context)
+ {
+ cairo_region_t *clip = gdk_drawing_context_get_clip (context);
+
+ gdk_draw_context_end_frame (paint_context,
+ clip,
+ window->active_update_area);
+
+ cairo_region_destroy (clip);
+ }
+ else
+ {
+ gdk_surface_end_paint_internal (window);
+ }
+
+ window->drawing_context = NULL;
+
+ g_object_unref (context);
+}
+
+/*< private >
+ * gdk_surface_get_current_paint_region:
+ * @window: a #GdkSurface
+ *
+ * Retrieves a copy of the current paint region.
+ *
+ * Returns: (transfer full): a Cairo region
+ */
+cairo_region_t *
+gdk_surface_get_current_paint_region (GdkSurface *window)
+{
+ cairo_region_t *region;
+
+ if (window->impl_window->current_paint.region != NULL)
+ {
+ region = cairo_region_copy (window->impl_window->current_paint.region);
+ cairo_region_translate (region, -window->abs_x, -window->abs_y);
+ }
+ else
+ {
+ region = cairo_region_copy (window->clip_region);
+ }
+
+ return region;
+}
+
+/*< private >
+ * gdk_surface_get_drawing_context:
+ * @window: a #GdkSurface
+ *
+ * Retrieves the #GdkDrawingContext associated to @window by
+ * gdk_surface_begin_draw_frame().
+ *
+ * Returns: (transfer none) (nullable): a #GdkDrawingContext, if any is set
+ */
+GdkDrawingContext *
+gdk_surface_get_drawing_context (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return NULL;
+
+ return window->drawing_context;
+}
+
+/**
+ * gdk_surface_get_clip_region:
+ * @window: a #GdkSurface
+ *
+ * Computes the region of a window that potentially can be written
+ * to by drawing primitives. This region may not take into account
+ * other factors such as if the window is obscured by other windows,
+ * but no area outside of this region will be affected by drawing
+ * primitives.
+ *
+ * Returns: a #cairo_region_t. This must be freed with cairo_region_destroy()
+ * when you are done.
+ **/
+cairo_region_t*
+gdk_surface_get_clip_region (GdkSurface *window)
+{
+ cairo_region_t *result;
+
+ g_return_val_if_fail (GDK_SURFACE (window), NULL);
+
+ result = cairo_region_copy (window->clip_region);
+
+ if (window->current_paint.region != NULL)
+ cairo_region_intersect (result, window->current_paint.region);
+
+ return result;
+}
+
+/**
+ * gdk_surface_get_visible_region:
+ * @window: a #GdkSurface
+ *
+ * Computes the region of the @window that is potentially visible.
+ * This does not necessarily take into account if the window is
+ * obscured by other windows, but no area outside of this region
+ * is visible.
+ *
+ * Returns: a #cairo_region_t. This must be freed with cairo_region_destroy()
+ * when you are done.
+ **/
+cairo_region_t *
+gdk_surface_get_visible_region (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ return cairo_region_copy (window->clip_region);
+}
+
+static void
+gdk_surface_clear_backing_region (GdkSurface *window)
+{
+ cairo_t *cr;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ cr = cairo_create (window->current_paint.surface);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ gdk_cairo_region (cr, window->current_paint.region);
+ cairo_fill (cr);
+
+ cairo_destroy (cr);
+}
+
+/* This returns either the current working surface on the paint stack
+ * or the actual impl surface of the window. This should not be used
+ * from very many places: be careful! */
+static cairo_surface_t *
+ref_window_surface (GdkSurface *window)
+{
+ if (window->impl_window->current_paint.surface)
+ return cairo_surface_reference (window->impl_window->current_paint.surface);
+ else
+ return gdk_surface_ref_impl_surface (window);
+}
+
+/* This is used in places like gdk_cairo_set_source_window and
+ * other places to take "screenshots" of windows. Thus, we allow
+ * it to be used outside of a begin_paint / end_paint. */
+cairo_surface_t *
+_gdk_surface_ref_cairo_surface (GdkSurface *window)
+{
+ cairo_surface_t *surface;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ surface = ref_window_surface (window);
+
+ if (gdk_surface_has_impl (window))
+ {
+ return surface;
+ }
+ else
+ {
+ cairo_surface_t *subsurface;
+ subsurface = cairo_surface_create_for_rectangle (surface,
+ window->abs_x,
+ window->abs_y,
+ window->width,
+ window->height);
+ cairo_surface_destroy (surface);
+ return subsurface;
+ }
+}
+
+/* Code for dirty-region queueing
+ */
+static GSList *update_windows = NULL;
+
+static inline gboolean
+gdk_surface_is_ancestor (GdkSurface *window,
+ GdkSurface *ancestor)
+{
+ while (window)
+ {
+ GdkSurface *parent = window->parent;
+
+ if (parent == ancestor)
+ return TRUE;
+
+ window = parent;
+ }
+
+ return FALSE;
+}
+
+static void
+gdk_surface_add_update_window (GdkSurface *window)
+{
+ GSList *tmp;
+ GSList *prev = NULL;
+ gboolean has_ancestor_in_list = FALSE;
+
+ /* Check whether "window" is already in "update_windows" list.
+ * It could be added during execution of gtk_widget_destroy() when
+ * setting focus widget to NULL and redrawing old focus widget.
+ * See bug 711552.
+ */
+ tmp = g_slist_find (update_windows, window);
+ if (tmp != NULL)
+ return;
+
+ for (tmp = update_windows; tmp; tmp = tmp->next)
+ {
+ GdkSurface *parent = window->parent;
+
+ /* check if tmp is an ancestor of "window"; if it is, set a
+ * flag indicating that all following windows are either
+ * children of "window" or from a differen hierarchy
+ */
+ if (!has_ancestor_in_list && gdk_surface_is_ancestor (window, tmp->data))
+ has_ancestor_in_list = TRUE;
+
+ /* insert in reverse stacking order when adding around siblings,
+ * so processing updates properly paints over lower stacked windows
+ */
+ if (parent == GDK_SURFACE (tmp->data)->parent)
+ {
+ if (parent != NULL)
+ {
+ gint index = g_list_index (parent->children, window);
+ for (; tmp && parent == GDK_SURFACE (tmp->data)->parent; tmp = tmp->next)
+ {
+ gint sibling_index = g_list_index (parent->children, tmp->data);
+ if (index > sibling_index)
+ break;
+ prev = tmp;
+ }
+ }
+ /* here, tmp got advanced past all lower stacked siblings */
+ tmp = g_slist_prepend (tmp, g_object_ref (window));
+ if (prev)
+ prev->next = tmp;
+ else
+ update_windows = tmp;
+ return;
+ }
+
+ /* if "window" has an ancestor in the list and tmp is one of
+ * "window's" children, insert "window" before tmp
+ */
+ if (has_ancestor_in_list && gdk_surface_is_ancestor (tmp->data, window))
+ {
+ tmp = g_slist_prepend (tmp, g_object_ref (window));
+
+ if (prev)
+ prev->next = tmp;
+ else
+ update_windows = tmp;
+ return;
+ }
+
+ /* if we're at the end of the list and had an ancestor it it,
+ * append to the list
+ */
+ if (! tmp->next && has_ancestor_in_list)
+ {
+ tmp = g_slist_append (tmp, g_object_ref (window));
+ return;
+ }
+
+ prev = tmp;
+ }
+
+ /* if all above checks failed ("window" is from a different
+ * hierarchy than what is already in the list) or the list is
+ * empty, prepend
+ */
+ update_windows = g_slist_prepend (update_windows, g_object_ref (window));
+}
+
+static void
+gdk_surface_remove_update_window (GdkSurface *window)
+{
+ GSList *link;
+
+ link = g_slist_find (update_windows, window);
+ if (link != NULL)
+ {
+ update_windows = g_slist_delete_link (update_windows, link);
+ g_object_unref (window);
+ }
+}
+
+static gboolean
+gdk_surface_is_toplevel_frozen (GdkSurface *window)
+{
+ GdkSurface *toplevel;
+
+ toplevel = gdk_surface_get_toplevel (window);
+
+ return toplevel->update_and_descendants_freeze_count > 0;
+}
+
+static void
+gdk_surface_schedule_update (GdkSurface *window)
+{
+ GdkFrameClock *frame_clock;
+
+ if (window &&
+ (window->update_freeze_count ||
+ gdk_surface_is_toplevel_frozen (window)))
+ return;
+
+ /* If there's no frame clock (a foreign window), then the invalid
+ * region will just stick around unless gdk_surface_process_updates()
+ * is called. */
+ frame_clock = gdk_surface_get_frame_clock (window);
+ if (frame_clock)
+ gdk_frame_clock_request_phase (gdk_surface_get_frame_clock (window),
+ GDK_FRAME_CLOCK_PHASE_PAINT);
+}
+
+void
+_gdk_surface_process_updates_recurse (GdkSurface *window,
+ cairo_region_t *expose_region)
+{
+ cairo_region_t *clipped_expose_region;
+ GdkEvent *event;
+
+ if (window->destroyed)
+ return;
+
+ clipped_expose_region = cairo_region_copy (expose_region);
+
+ cairo_region_intersect (clipped_expose_region, window->clip_region);
+
+ if (cairo_region_is_empty (clipped_expose_region))
+ goto out;
+
+ /* Paint the window before the children, clipped to the window region */
+
+ event = gdk_event_new (GDK_EXPOSE);
+ event->any.window = g_object_ref (window);
+ event->any.send_event = FALSE;
+ event->expose.count = 0;
+ event->expose.region = cairo_region_reference (clipped_expose_region);
+ cairo_region_get_extents (clipped_expose_region, &event->expose.area);
+
+ _gdk_event_emit (event);
+ gdk_event_free (event);
+
+ out:
+ cairo_region_destroy (clipped_expose_region);
+}
+
+
+static void
+gdk_surface_update_native_shapes (GdkSurface *window)
+{
+ if (should_apply_clip_as_shape (window))
+ apply_clip_as_shape (window);
+}
+
+/* Process and remove any invalid area on the native window by creating
+ * expose events for the window and all non-native descendants.
+ */
+static void
+gdk_surface_process_updates_internal (GdkSurface *window)
+{
+ GdkSurfaceImplClass *impl_class;
+ GdkSurface *toplevel;
+
+ toplevel = gdk_surface_get_toplevel (window);
+ if (toplevel->geometry_dirty)
+ {
+ gdk_surface_update_native_shapes (toplevel);
+ toplevel->geometry_dirty = FALSE;
+ }
+
+ /* Ensure the window lives while updating it */
+ g_object_ref (window);
+
+ window->in_update = TRUE;
+
+ /* If an update got queued during update processing, we can get a
+ * window in the update queue that has an empty update_area.
+ * just ignore it.
+ */
+ if (window->update_area)
+ {
+ g_assert (window->active_update_area == NULL); /* No reentrancy */
+
+ window->active_update_area = window->update_area;
+ window->update_area = NULL;
+
+ if (gdk_surface_is_viewable (window))
+ {
+ cairo_region_t *expose_region;
+
+ expose_region = cairo_region_copy (window->active_update_area);
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ /* Clip to part visible in impl window */
+ cairo_region_intersect (expose_region, window->clip_region);
+
+ if (impl_class->queue_antiexpose)
+ impl_class->queue_antiexpose (window, expose_region);
+
+ impl_class->process_updates_recurse (window, expose_region);
+
+ gdk_surface_append_old_updated_area (window, window->active_update_area);
+
+ cairo_region_destroy (expose_region);
+ }
+
+ cairo_region_destroy (window->active_update_area);
+ window->active_update_area = NULL;
+ }
+
+ window->in_update = FALSE;
+
+ g_object_unref (window);
+}
+
+static void
+gdk_surface_paint_on_clock (GdkFrameClock *clock,
+ void *data)
+{
+ GdkSurface *window;
+
+ window = GDK_SURFACE (data);
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (window->impl_window == window);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ g_object_ref (window);
+
+ if (window->update_area &&
+ !window->update_freeze_count &&
+ !gdk_surface_is_toplevel_frozen (window) &&
+
+ /* Don't recurse into process_updates_internal, we'll
+ * do the update later when idle instead. */
+ !window->in_update)
+ {
+ gdk_surface_process_updates_internal (window);
+ gdk_surface_remove_update_window (window);
+ }
+
+ g_object_unref (window);
+}
+
+static void
+gdk_surface_invalidate_rect_full (GdkSurface *window,
+ const GdkRectangle *rect,
+ gboolean invalidate_children)
+{
+ GdkRectangle window_rect;
+ cairo_region_t *region;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (window->input_only || !window->viewable)
+ return;
+
+ if (!rect)
+ {
+ window_rect.x = 0;
+ window_rect.y = 0;
+ window_rect.width = window->width;
+ window_rect.height = window->height;
+ rect = &window_rect;
+ }
+
+ region = cairo_region_create_rectangle (rect);
+ gdk_surface_invalidate_region_full (window, region, invalidate_children);
+ cairo_region_destroy (region);
+}
+
+/**
+ * gdk_surface_invalidate_rect:
+ * @window: a #GdkSurface
+ * @rect: (allow-none): rectangle to invalidate or %NULL to invalidate the whole
+ * window
+ * @invalidate_children: whether to also invalidate child windows
+ *
+ * A convenience wrapper around gdk_surface_invalidate_region() which
+ * invalidates a rectangular region. See
+ * gdk_surface_invalidate_region() for details.
+ **/
+void
+gdk_surface_invalidate_rect (GdkSurface *window,
+ const GdkRectangle *rect,
+ gboolean invalidate_children)
+{
+ gdk_surface_invalidate_rect_full (window, rect, invalidate_children);
+}
+
+static void
+impl_window_add_update_area (GdkSurface *impl_window,
+ cairo_region_t *region)
+{
+ if (impl_window->update_area)
+ cairo_region_union (impl_window->update_area, region);
+ else
+ {
+ gdk_surface_add_update_window (impl_window);
+ impl_window->update_area = cairo_region_copy (region);
+ gdk_surface_schedule_update (impl_window);
+ }
+}
+
+static void
+gdk_surface_invalidate_maybe_recurse_full (GdkSurface *window,
+ const cairo_region_t *region,
+ GdkSurfaceChildFunc child_func,
+ gpointer user_data)
+{
+ cairo_region_t *visible_region;
+ cairo_rectangle_int_t r;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (window->input_only ||
+ !window->viewable ||
+ cairo_region_is_empty (region) ||
+ window->window_type == GDK_SURFACE_ROOT)
+ return;
+
+ r.x = 0;
+ r.y = 0;
+
+ visible_region = cairo_region_copy (region);
+
+ while (window != NULL &&
+ !cairo_region_is_empty (visible_region))
+ {
+ r.width = window->width;
+ r.height = window->height;
+ cairo_region_intersect_rectangle (visible_region, &r);
+
+ if (gdk_surface_has_impl (window))
+ {
+ impl_window_add_update_area (window, visible_region);
+ break;
+ }
+ else
+ {
+ cairo_region_translate (visible_region,
+ window->x, window->y);
+ window = window->parent;
+ }
+ }
+
+ cairo_region_destroy (visible_region);
+}
+
+/**
+ * gdk_surface_invalidate_maybe_recurse:
+ * @window: a #GdkSurface
+ * @region: a #cairo_region_t
+ * @child_func: (scope call) (allow-none): function to use to decide if to
+ * recurse to a child, %NULL means never recurse.
+ * @user_data: data passed to @child_func
+ *
+ * Adds @region to the update area for @window. The update area is the
+ * region that needs to be redrawn, or “dirty region.”
+ *
+ * GDK will process all updates whenever the frame clock schedules a redraw,
+ * so there’s no need to do forces redraws manually, you just need to
+ * invalidate regions that you know should be redrawn.
+ *
+ * The @child_func parameter controls whether the region of
+ * each child window that intersects @region will also be invalidated.
+ * Only children for which @child_func returns #TRUE will have the area
+ * invalidated.
+ **/
+void
+gdk_surface_invalidate_maybe_recurse (GdkSurface *window,
+ const cairo_region_t *region,
+ GdkSurfaceChildFunc child_func,
+ gpointer user_data)
+{
+ gdk_surface_invalidate_maybe_recurse_full (window, region,
+ child_func, user_data);
+}
+
+static gboolean
+true_predicate (GdkSurface *window,
+ gpointer user_data)
+{
+ return TRUE;
+}
+
+static void
+gdk_surface_invalidate_region_full (GdkSurface *window,
+ const cairo_region_t *region,
+ gboolean invalidate_children)
+{
+ gdk_surface_invalidate_maybe_recurse_full (window, region,
+ invalidate_children ?
+ true_predicate : (gboolean (*) (GdkSurface *, gpointer))NULL,
+ NULL);
+}
+
+/**
+ * gdk_surface_invalidate_region:
+ * @window: a #GdkSurface
+ * @region: a #cairo_region_t
+ * @invalidate_children: %TRUE to also invalidate child windows
+ *
+ * Adds @region to the update area for @window. The update area is the
+ * region that needs to be redrawn, or “dirty region.”
+ *
+ * GDK will process all updates whenever the frame clock schedules a redraw,
+ * so there’s no need to do forces redraws manually, you just need to
+ * invalidate regions that you know should be redrawn.
+ *
+ * The @invalidate_children parameter controls whether the region of
+ * each child window that intersects @region will also be invalidated.
+ * If %FALSE, then the update area for child windows will remain
+ * unaffected. See gdk_surface_invalidate_maybe_recurse if you need
+ * fine grained control over which children are invalidated.
+ **/
+void
+gdk_surface_invalidate_region (GdkSurface *window,
+ const cairo_region_t *region,
+ gboolean invalidate_children)
+{
+ gdk_surface_invalidate_maybe_recurse (window, region,
+ invalidate_children ?
+ true_predicate : (gboolean (*) (GdkSurface *, gpointer))NULL,
+ NULL);
+}
+
+/**
+ * _gdk_surface_invalidate_for_expose:
+ * @window: a #GdkSurface
+ * @region: a #cairo_region_t
+ *
+ * Adds @region to the update area for @window.
+ *
+ * GDK will process all updates whenever the frame clock schedules a redraw,
+ * so there’s no need to do forces redraws manually, you just need to
+ * invalidate regions that you know should be redrawn.
+ *
+ * This version of invalidation is used when you recieve expose events
+ * from the native window system. It exposes the native window, plus
+ * any non-native child windows.
+ **/
+void
+_gdk_surface_invalidate_for_expose (GdkSurface *window,
+ cairo_region_t *region)
+{
+ gdk_surface_invalidate_maybe_recurse_full (window, region,
+ (gboolean (*) (GdkSurface *, gpointer))gdk_surface_has_no_impl,
+ NULL);
+}
+
+
+/**
+ * gdk_surface_get_update_area:
+ * @window: a #GdkSurface
+ *
+ * Transfers ownership of the update area from @window to the caller
+ * of the function. That is, after calling this function, @window will
+ * no longer have an invalid/dirty region; the update area is removed
+ * from @window and handed to you. If a window has no update area,
+ * gdk_surface_get_update_area() returns %NULL. You are responsible for
+ * calling cairo_region_destroy() on the returned region if it’s non-%NULL.
+ *
+ * Returns: the update area for @window
+ **/
+cairo_region_t *
+gdk_surface_get_update_area (GdkSurface *window)
+{
+ GdkSurface *impl_window;
+ cairo_region_t *tmp_region, *to_remove;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ impl_window = gdk_surface_get_impl_window (window);
+
+ if (impl_window->update_area)
+ {
+ tmp_region = cairo_region_copy (window->clip_region);
+ /* Convert to impl coords */
+ cairo_region_translate (tmp_region, window->abs_x, window->abs_y);
+ cairo_region_intersect (tmp_region, impl_window->update_area);
+
+ if (cairo_region_is_empty (tmp_region))
+ {
+ cairo_region_destroy (tmp_region);
+ return NULL;
+ }
+ else
+ {
+ /* Convert from impl coords */
+ cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
+
+ /* Don't remove any update area that is overlapped by sibling windows
+ or child windows as these really need to be repainted independently of this window. */
+ to_remove = cairo_region_copy (tmp_region);
+
+ remove_child_area (window, FALSE, to_remove);
+ remove_sibling_overlapped_area (window, to_remove);
+
+ /* Remove from update_area */
+ cairo_region_translate (to_remove, window->abs_x, window->abs_y);
+ cairo_region_subtract (impl_window->update_area, to_remove);
+
+ cairo_region_destroy (to_remove);
+
+ if (cairo_region_is_empty (impl_window->update_area))
+ {
+ cairo_region_destroy (impl_window->update_area);
+ impl_window->update_area = NULL;
+
+ gdk_surface_remove_update_window ((GdkSurface *)impl_window);
+ }
+
+ return tmp_region;
+ }
+ }
+ else
+ return NULL;
+}
+
+/**
+ * _gdk_surface_clear_update_area:
+ * @window: a #GdkSurface.
+ *
+ * Internal function to clear the update area for a window. This
+ * is called when the window is hidden or destroyed.
+ **/
+void
+_gdk_surface_clear_update_area (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->update_area)
+ {
+ gdk_surface_remove_update_window (window);
+
+ cairo_region_destroy (window->update_area);
+ window->update_area = NULL;
+ }
+}
+
+/**
+ * gdk_surface_freeze_updates:
+ * @window: a #GdkSurface
+ *
+ * Temporarily freezes a window such that it won’t receive expose
+ * events. The window will begin receiving expose events again when
+ * gdk_surface_thaw_updates() is called. If gdk_surface_freeze_updates()
+ * has been called more than once, gdk_surface_thaw_updates() must be called
+ * an equal number of times to begin processing exposes.
+ **/
+void
+gdk_surface_freeze_updates (GdkSurface *window)
+{
+ GdkSurface *impl_window;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ impl_window = gdk_surface_get_impl_window (window);
+ impl_window->update_freeze_count++;
+}
+
+/**
+ * gdk_surface_thaw_updates:
+ * @window: a #GdkSurface
+ *
+ * Thaws a window frozen with gdk_surface_freeze_updates().
+ **/
+void
+gdk_surface_thaw_updates (GdkSurface *window)
+{
+ GdkSurface *impl_window;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ impl_window = gdk_surface_get_impl_window (window);
+
+ g_return_if_fail (impl_window->update_freeze_count > 0);
+
+ if (--impl_window->update_freeze_count == 0)
+ gdk_surface_schedule_update (GDK_SURFACE (impl_window));
+}
+
+void
+gdk_surface_freeze_toplevel_updates (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (window->window_type != GDK_SURFACE_CHILD);
+
+ window->update_and_descendants_freeze_count++;
+ _gdk_frame_clock_freeze (gdk_surface_get_frame_clock (window));
+}
+
+void
+gdk_surface_thaw_toplevel_updates (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (window->window_type != GDK_SURFACE_CHILD);
+ g_return_if_fail (window->update_and_descendants_freeze_count > 0);
+
+ window->update_and_descendants_freeze_count--;
+ _gdk_frame_clock_thaw (gdk_surface_get_frame_clock (window));
+
+ gdk_surface_schedule_update (window);
+}
+
+/**
+ * gdk_surface_constrain_size:
+ * @geometry: a #GdkGeometry structure
+ * @flags: a mask indicating what portions of @geometry are set
+ * @width: desired width of window
+ * @height: desired height of the window
+ * @new_width: (out): location to store resulting width
+ * @new_height: (out): location to store resulting height
+ *
+ * Constrains a desired width and height according to a
+ * set of geometry hints (such as minimum and maximum size).
+ */
+void
+gdk_surface_constrain_size (GdkGeometry *geometry,
+ GdkSurfaceHints flags,
+ gint width,
+ gint height,
+ gint *new_width,
+ gint *new_height)
+{
+ /* This routine is partially borrowed from fvwm.
+ *
+ * Copyright 1993, Robert Nation
+ * You may use this code for any purpose, as long as the original
+ * copyright remains in the source code and all documentation
+ *
+ * which in turn borrows parts of the algorithm from uwm
+ */
+ gint min_width = 0;
+ gint min_height = 0;
+ gint base_width = 0;
+ gint base_height = 0;
+ gint xinc = 1;
+ gint yinc = 1;
+ gint max_width = G_MAXINT;
+ gint max_height = G_MAXINT;
+
+#define FLOOR(value, base) ( ((gint) ((value) / (base))) * (base) )
+
+ if ((flags & GDK_HINT_BASE_SIZE) && (flags & GDK_HINT_MIN_SIZE))
+ {
+ base_width = geometry->base_width;
+ base_height = geometry->base_height;
+ min_width = geometry->min_width;
+ min_height = geometry->min_height;
+ }
+ else if (flags & GDK_HINT_BASE_SIZE)
+ {
+ base_width = geometry->base_width;
+ base_height = geometry->base_height;
+ min_width = geometry->base_width;
+ min_height = geometry->base_height;
+ }
+ else if (flags & GDK_HINT_MIN_SIZE)
+ {
+ base_width = geometry->min_width;
+ base_height = geometry->min_height;
+ min_width = geometry->min_width;
+ min_height = geometry->min_height;
+ }
+
+ if (flags & GDK_HINT_MAX_SIZE)
+ {
+ max_width = geometry->max_width ;
+ max_height = geometry->max_height;
+ }
+
+ if (flags & GDK_HINT_RESIZE_INC)
+ {
+ xinc = MAX (xinc, geometry->width_inc);
+ yinc = MAX (yinc, geometry->height_inc);
+ }
+
+ /* clamp width and height to min and max values
+ */
+ width = CLAMP (width, min_width, max_width);
+ height = CLAMP (height, min_height, max_height);
+
+ /* shrink to base + N * inc
+ */
+ width = base_width + FLOOR (width - base_width, xinc);
+ height = base_height + FLOOR (height - base_height, yinc);
+
+ /* constrain aspect ratio, according to:
+ *
+ * width
+ * min_aspect <= -------- <= max_aspect
+ * height
+ */
+
+ if (flags & GDK_HINT_ASPECT &&
+ geometry->min_aspect > 0 &&
+ geometry->max_aspect > 0)
+ {
+ gint delta;
+
+ if (geometry->min_aspect * height > width)
+ {
+ delta = FLOOR (height - width / geometry->min_aspect, yinc);
+ if (height - delta >= min_height)
+ height -= delta;
+ else
+ {
+ delta = FLOOR (height * geometry->min_aspect - width, xinc);
+ if (width + delta <= max_width)
+ width += delta;
+ }
+ }
+
+ if (geometry->max_aspect * height < width)
+ {
+ delta = FLOOR (width - height * geometry->max_aspect, xinc);
+ if (width - delta >= min_width)
+ width -= delta;
+ else
+ {
+ delta = FLOOR (width / geometry->max_aspect - height, yinc);
+ if (height + delta <= max_height)
+ height += delta;
+ }
+ }
+ }
+
+#undef FLOOR
+
+ *new_width = width;
+ *new_height = height;
+}
+
+/**
+ * gdk_surface_get_device_position_double:
+ * @window: a #GdkSurface.
+ * @device: pointer #GdkDevice to query to.
+ * @x: (out) (allow-none): return location for the X coordinate of @device, or %NULL.
+ * @y: (out) (allow-none): return location for the Y coordinate of @device, or %NULL.
+ * @mask: (out) (allow-none): return location for the modifier mask, or %NULL.
+ *
+ * Obtains the current device position in doubles and modifier state.
+ * The position is given in coordinates relative to the upper left
+ * corner of @window.
+ *
+ * Returns: (nullable) (transfer none): The window underneath @device
+ * (as with gdk_device_get_window_at_position()), or %NULL if the
+ * window is not known to GDK.
+ **/
+GdkSurface *
+gdk_surface_get_device_position_double (GdkSurface *window,
+ GdkDevice *device,
+ double *x,
+ double *y,
+ GdkModifierType *mask)
+{
+ gdouble tmp_x, tmp_y;
+ GdkModifierType tmp_mask;
+ gboolean normal_child;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
+
+ tmp_x = tmp_y = 0;
+ tmp_mask = 0;
+ normal_child = GDK_SURFACE_IMPL_GET_CLASS (window->impl)->get_device_state (window,
+ device,
+ &tmp_x, &tmp_y,
+ &tmp_mask);
+ /* We got the coords on the impl, convert to the window */
+ tmp_x -= window->abs_x;
+ tmp_y -= window->abs_y;
+
+ if (x)
+ *x = tmp_x;
+ if (y)
+ *y = tmp_y;
+ if (mask)
+ *mask = tmp_mask;
+
+ if (normal_child)
+ return _gdk_surface_find_child_at (window, tmp_x, tmp_y);
+ return NULL;
+}
+
+/**
+ * gdk_surface_get_device_position:
+ * @window: a #GdkSurface.
+ * @device: pointer #GdkDevice to query to.
+ * @x: (out) (allow-none): return location for the X coordinate of @device, or %NULL.
+ * @y: (out) (allow-none): return location for the Y coordinate of @device, or %NULL.
+ * @mask: (out) (allow-none): return location for the modifier mask, or %NULL.
+ *
+ * Obtains the current device position and modifier state.
+ * The position is given in coordinates relative to the upper left
+ * corner of @window.
+ *
+ * Use gdk_surface_get_device_position_double() if you need subpixel precision.
+ *
+ * Returns: (nullable) (transfer none): The window underneath @device
+ * (as with gdk_device_get_window_at_position()), or %NULL if the
+ * window is not known to GDK.
+ **/
+GdkSurface *
+gdk_surface_get_device_position (GdkSurface *window,
+ GdkDevice *device,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask)
+{
+ gdouble tmp_x, tmp_y;
+
+ window = gdk_surface_get_device_position_double (window, device,
+ &tmp_x, &tmp_y, mask);
+ if (x)
+ *x = round (tmp_x);
+ if (y)
+ *y = round (tmp_y);
+
+ return window;
+}
+
+static gboolean
+gdk_surface_raise_internal (GdkSurface *window)
+{
+ GdkSurface *parent = window->parent;
+ GdkSurfaceImplClass *impl_class;
+ gboolean did_raise = FALSE;
+
+ if (parent && parent->children->data != window)
+ {
+ parent->children = g_list_remove_link (parent->children, &window->children_list_node);
+ parent->children = g_list_concat (&window->children_list_node, parent->children);
+ did_raise = TRUE;
+ }
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ /* Just do native raise for toplevels */
+ if (gdk_surface_has_impl (window))
+ impl_class->raise (window);
+
+ return did_raise;
+}
+
+/* Returns TRUE If the native window was mapped or unmapped */
+static gboolean
+set_viewable (GdkSurface *w,
+ gboolean val)
+{
+ GdkSurface *child;
+ GList *l;
+
+ if (w->viewable == val)
+ return FALSE;
+
+ w->viewable = val;
+
+ if (val)
+ recompute_visible_regions (w, FALSE);
+
+ for (l = w->children; l != NULL; l = l->next)
+ {
+ child = l->data;
+
+ if (GDK_SURFACE_IS_MAPPED (child))
+ set_viewable (child, val);
+ }
+
+ return FALSE;
+}
+
+/* Returns TRUE If the native window was mapped or unmapped */
+gboolean
+_gdk_surface_update_viewable (GdkSurface *window)
+{
+ gboolean viewable;
+
+ if (window->window_type == GDK_SURFACE_FOREIGN ||
+ window->window_type == GDK_SURFACE_ROOT)
+ viewable = TRUE;
+ else if (gdk_surface_is_toplevel (window) ||
+ window->parent->viewable)
+ viewable = GDK_SURFACE_IS_MAPPED (window);
+ else
+ viewable = FALSE;
+
+ return set_viewable (window, viewable);
+}
+
+static void
+gdk_surface_show_internal (GdkSurface *window, gboolean raise)
+{
+ GdkSurfaceImplClass *impl_class;
+ gboolean was_mapped, was_viewable;
+ gboolean did_show, did_raise = FALSE;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->destroyed)
+ return;
+
+ was_mapped = GDK_SURFACE_IS_MAPPED (window);
+ was_viewable = window->viewable;
+
+ if (raise)
+ {
+ /* Keep children in (reverse) stacking order */
+ did_raise = gdk_surface_raise_internal (window);
+ }
+
+ if (gdk_surface_has_impl (window))
+ {
+ if (!was_mapped)
+ gdk_synthesize_window_state (window,
+ GDK_SURFACE_STATE_WITHDRAWN,
+ 0);
+ }
+ else
+ {
+ window->state = 0;
+ g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_STATE]);
+ }
+
+ did_show = _gdk_surface_update_viewable (window);
+
+ /* If it was already viewable the backend show op won't be called, call it
+ again to ensure things happen right if the mapped tracking was not right
+ for e.g. a foreign window.
+ Dunno if this is strictly needed but its what happened pre-csw.
+ Also show if not done by gdk_surface_update_viewable. */
+ if (gdk_surface_has_impl (window) && (was_viewable || !did_show))
+ {
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ impl_class->show (window, !did_show ? was_mapped : TRUE);
+ }
+
+ if (!was_mapped && !gdk_surface_has_impl (window))
+ {
+ if (window->event_mask & GDK_STRUCTURE_MASK)
+ _gdk_make_event (window, GDK_MAP, NULL, FALSE);
+
+ if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
+ _gdk_make_event (window, GDK_MAP, NULL, FALSE);
+ }
+
+ if (!was_mapped || did_raise)
+ {
+ recompute_visible_regions (window, FALSE);
+
+ if (gdk_surface_is_viewable (window))
+ gdk_surface_invalidate_rect_full (window, NULL, TRUE);
+ }
+}
+
+/**
+ * gdk_surface_show_unraised:
+ * @window: a #GdkSurface
+ *
+ * Shows a #GdkSurface onscreen, but does not modify its stacking
+ * order. In contrast, gdk_surface_show() will raise the window
+ * to the top of the window stack.
+ *
+ * On the X11 platform, in Xlib terms, this function calls
+ * XMapWindow() (it also updates some internal GDK state, which means
+ * that you can’t really use XMapWindow() directly on a GDK window).
+ */
+void
+gdk_surface_show_unraised (GdkSurface *window)
+{
+ gdk_surface_show_internal (window, FALSE);
+}
+
+/**
+ * gdk_surface_raise:
+ * @window: a #GdkSurface
+ *
+ * Raises @window to the top of the Z-order (stacking order), so that
+ * other windows with the same parent window appear below @window.
+ * This is true whether or not the windows are visible.
+ *
+ * If @window is a toplevel, the window manager may choose to deny the
+ * request to move the window in the Z-order, gdk_surface_raise() only
+ * requests the restack, does not guarantee it.
+ */
+void
+gdk_surface_raise (GdkSurface *window)
+{
+ gboolean did_raise;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->destroyed)
+ return;
+
+ /* Keep children in (reverse) stacking order */
+ did_raise = gdk_surface_raise_internal (window);
+
+ if (did_raise &&
+ !gdk_surface_is_toplevel (window) &&
+ gdk_surface_is_viewable (window) &&
+ !window->input_only)
+ gdk_surface_invalidate_region_full (window, window->clip_region, TRUE);
+}
+
+static void
+gdk_surface_lower_internal (GdkSurface *window)
+{
+ GdkSurface *parent = window->parent;
+ GdkSurfaceImplClass *impl_class;
+
+ if (parent)
+ {
+ parent->children = g_list_remove_link (parent->children, &window->children_list_node);
+ parent->children = g_list_concat (parent->children, &window->children_list_node);
+ }
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ /* Just do native lower for toplevels */
+ if (gdk_surface_has_impl (window))
+ impl_class->lower (window);
+}
+
+static void
+gdk_surface_invalidate_in_parent (GdkSurface *private)
+{
+ GdkRectangle r, child;
+
+ if (gdk_surface_is_toplevel (private))
+ return;
+
+ /* get the visible rectangle of the parent */
+ r.x = r.y = 0;
+ r.width = private->parent->width;
+ r.height = private->parent->height;
+
+ child.x = private->x;
+ child.y = private->y;
+ child.width = private->width;
+ child.height = private->height;
+ gdk_rectangle_intersect (&r, &child, &r);
+
+ gdk_surface_invalidate_rect_full (private->parent, &r, TRUE);
+}
+
+
+/**
+ * gdk_surface_lower:
+ * @window: a #GdkSurface
+ *
+ * Lowers @window to the bottom of the Z-order (stacking order), so that
+ * other windows with the same parent window appear above @window.
+ * This is true whether or not the other windows are visible.
+ *
+ * If @window is a toplevel, the window manager may choose to deny the
+ * request to move the window in the Z-order, gdk_surface_lower() only
+ * requests the restack, does not guarantee it.
+ *
+ * Note that gdk_surface_show() raises the window again, so don’t call this
+ * function before gdk_surface_show(). (Try gdk_surface_show_unraised().)
+ */
+void
+gdk_surface_lower (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->destroyed)
+ return;
+
+ /* Keep children in (reverse) stacking order */
+ gdk_surface_lower_internal (window);
+
+ gdk_surface_invalidate_in_parent (window);
+}
+
+/**
+ * gdk_surface_restack:
+ * @window: a #GdkSurface
+ * @sibling: (allow-none): a #GdkSurface that is a sibling of @window, or %NULL
+ * @above: a boolean
+ *
+ * Changes the position of @window in the Z-order (stacking order), so that
+ * it is above @sibling (if @above is %TRUE) or below @sibling (if @above is
+ * %FALSE).
+ *
+ * If @sibling is %NULL, then this either raises (if @above is %TRUE) or
+ * lowers the window.
+ *
+ * If @window is a toplevel, the window manager may choose to deny the
+ * request to move the window in the Z-order, gdk_surface_restack() only
+ * requests the restack, does not guarantee it.
+ */
+void
+gdk_surface_restack (GdkSurface *window,
+ GdkSurface *sibling,
+ gboolean above)
+{
+ GdkSurfaceImplClass *impl_class;
+ GdkSurface *parent;
+ GList *sibling_link;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (sibling == NULL || GDK_IS_SURFACE (sibling));
+
+ if (window->destroyed)
+ return;
+
+ if (sibling == NULL)
+ {
+ if (above)
+ gdk_surface_raise (window);
+ else
+ gdk_surface_lower (window);
+ return;
+ }
+
+ if (gdk_surface_is_toplevel (window))
+ {
+ g_return_if_fail (gdk_surface_is_toplevel (sibling));
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ impl_class->restack_toplevel (window, sibling, above);
+ return;
+ }
+
+ parent = window->parent;
+ if (parent)
+ {
+ sibling_link = g_list_find (parent->children, sibling);
+ g_return_if_fail (sibling_link != NULL);
+ if (sibling_link == NULL)
+ return;
+
+ parent->children = g_list_remove_link (parent->children, &window->children_list_node);
+ if (above)
+ parent->children = list_insert_link_before (parent->children,
+ sibling_link,
+ &window->children_list_node);
+ else
+ parent->children = list_insert_link_before (parent->children,
+ sibling_link->next,
+ &window->children_list_node);
+ }
+
+ gdk_surface_invalidate_in_parent (window);
+}
+
+
+/**
+ * gdk_surface_show:
+ * @window: a #GdkSurface
+ *
+ * Like gdk_surface_show_unraised(), but also raises the window to the
+ * top of the window stack (moves the window to the front of the
+ * Z-order).
+ *
+ * This function maps a window so it’s visible onscreen. Its opposite
+ * is gdk_surface_hide().
+ *
+ * When implementing a #GtkWidget, you should call this function on the widget's
+ * #GdkSurface as part of the “map” method.
+ */
+void
+gdk_surface_show (GdkSurface *window)
+{
+ gdk_surface_show_internal (window, TRUE);
+}
+
+/**
+ * gdk_surface_hide:
+ * @window: a #GdkSurface
+ *
+ * For toplevel windows, withdraws them, so they will no longer be
+ * known to the window manager; for all windows, unmaps them, so
+ * they won’t be displayed. Normally done automatically as
+ * part of gtk_widget_hide().
+ */
+void
+gdk_surface_hide (GdkSurface *window)
+{
+ GdkSurfaceImplClass *impl_class;
+ gboolean was_mapped, did_hide;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->destroyed)
+ return;
+
+ was_mapped = GDK_SURFACE_IS_MAPPED (window);
+
+ if (gdk_surface_has_impl (window))
+ {
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_SURFACE_STATE_WITHDRAWN);
+ }
+ else if (was_mapped)
+ {
+ window->state = GDK_SURFACE_STATE_WITHDRAWN;
+ g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_STATE]);
+ }
+
+ if (was_mapped)
+ {
+ GdkDisplay *display;
+ GdkSeat *seat;
+ GList *devices, *d;
+
+ /* May need to break grabs on children */
+ display = gdk_surface_get_display (window);
+ seat = gdk_display_get_default_seat (display);
+
+ devices = gdk_seat_get_slaves (seat, GDK_SEAT_CAPABILITY_ALL);
+ devices = g_list_prepend (devices, gdk_seat_get_keyboard (seat));
+ devices = g_list_prepend (devices, gdk_seat_get_pointer (seat));
+
+ for (d = devices; d; d = d->next)
+ {
+ GdkDevice *device = d->data;
+
+ if (_gdk_display_end_device_grab (display,
+ device,
+ _gdk_display_get_next_serial (display),
+ window,
+ TRUE))
+ {
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ gdk_device_ungrab (device, GDK_CURRENT_TIME);
+G_GNUC_END_IGNORE_DEPRECATIONS
+ }
+ }
+
+ g_list_free (devices);
+ }
+
+ did_hide = _gdk_surface_update_viewable (window);
+
+ /* Hide foreign window as those are not handled by update_viewable. */
+ if (gdk_surface_has_impl (window) && (!did_hide))
+ {
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ impl_class->hide (window);
+ }
+
+ gdk_surface_clear_old_updated_area (window);
+ recompute_visible_regions (window, FALSE);
+
+ if (was_mapped && !gdk_surface_has_impl (window))
+ {
+ if (window->event_mask & GDK_STRUCTURE_MASK)
+ _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
+
+ if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
+ _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
+ }
+
+ /* Invalidate the rect */
+ if (was_mapped)
+ gdk_surface_invalidate_in_parent (window);
+}
+
+/**
+ * gdk_surface_withdraw:
+ * @window: a toplevel #GdkSurface
+ *
+ * Withdraws a window (unmaps it and asks the window manager to forget about it).
+ * This function is not really useful as gdk_surface_hide() automatically
+ * withdraws toplevel windows before hiding them.
+ **/
+void
+gdk_surface_withdraw (GdkSurface *window)
+{
+ GdkSurfaceImplClass *impl_class;
+ gboolean was_mapped;
+ GdkGLContext *current_context;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->destroyed)
+ return;
+
+ was_mapped = GDK_SURFACE_IS_MAPPED (window);
+
+ if (gdk_surface_has_impl (window))
+ {
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ impl_class->withdraw (window);
+
+ if (was_mapped)
+ {
+ if (window->event_mask & GDK_STRUCTURE_MASK)
+ _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
+
+ if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
+ _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
+ }
+
+ current_context = gdk_gl_context_get_current ();
+ if (current_context != NULL && gdk_gl_context_get_window (current_context) == window)
+ gdk_gl_context_clear_current ();
+
+ recompute_visible_regions (window, FALSE);
+ gdk_surface_clear_old_updated_area (window);
+ }
+}
+
+/**
+ * gdk_surface_set_events:
+ * @window: a #GdkSurface
+ * @event_mask: event mask for @window
+ *
+ * The event mask for a window determines which events will be reported
+ * for that window from all master input devices. For example, an event mask
+ * including #GDK_BUTTON_PRESS_MASK means the window should report button
+ * press events. The event mask is the bitwise OR of values from the
+ * #GdkEventMask enumeration.
+ *
+ * See the [input handling overview][event-masks] for details.
+ **/
+void
+gdk_surface_set_events (GdkSurface *window,
+ GdkEventMask event_mask)
+{
+ GdkSurfaceImplClass *impl_class;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->destroyed)
+ return;
+
+ window->event_mask = event_mask;
+
+ if (gdk_surface_has_impl (window))
+ {
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ impl_class->set_events (window,
+ get_native_event_mask (window));
+ }
+
+}
+
+/**
+ * gdk_surface_get_events:
+ * @window: a #GdkSurface
+ *
+ * Gets the event mask for @window for all master input devices. See
+ * gdk_surface_set_events().
+ *
+ * Returns: event mask for @window
+ **/
+GdkEventMask
+gdk_surface_get_events (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
+
+ if (window->destroyed)
+ return 0;
+
+ return window->event_mask;
+}
+
+/**
+ * gdk_surface_set_device_events:
+ * @window: a #GdkSurface
+ * @device: #GdkDevice to enable events for.
+ * @event_mask: event mask for @window
+ *
+ * Sets the event mask for a given device (Normally a floating device, not
+ * attached to any visible pointer) to @window. For example, an event mask
+ * including #GDK_BUTTON_PRESS_MASK means the window should report button
+ * press events. The event mask is the bitwise OR of values from the
+ * #GdkEventMask enumeration.
+ *
+ * See the [input handling overview][event-masks] for details.
+ **/
+void
+gdk_surface_set_device_events (GdkSurface *window,
+ GdkDevice *device,
+ GdkEventMask event_mask)
+{
+ GdkEventMask device_mask;
+ GdkSurface *native;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (G_UNLIKELY (!window->device_events))
+ window->device_events = g_hash_table_new (NULL, NULL);
+
+ if (event_mask == 0)
+ {
+ /* FIXME: unsetting events on a master device
+ * would restore window->event_mask
+ */
+ g_hash_table_remove (window->device_events, device);
+ }
+ else
+ g_hash_table_insert (window->device_events, device,
+ GINT_TO_POINTER (event_mask));
+
+ native = gdk_surface_get_toplevel (window);
+
+ device_mask = get_native_device_event_mask (window, device);
+ GDK_DEVICE_GET_CLASS (device)->select_window_events (device, native, device_mask);
+}
+
+/**
+ * gdk_surface_get_device_events:
+ * @window: a #GdkSurface.
+ * @device: a #GdkDevice.
+ *
+ * Returns the event mask for @window corresponding to an specific device.
+ *
+ * Returns: device event mask for @window
+ **/
+GdkEventMask
+gdk_surface_get_device_events (GdkSurface *window,
+ GdkDevice *device)
+{
+ GdkEventMask mask;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return 0;
+
+ if (!window->device_events)
+ return 0;
+
+ mask = GPOINTER_TO_INT (g_hash_table_lookup (window->device_events, device));
+
+ /* FIXME: device could be controlled by window->event_mask */
+
+ return mask;
+}
+
+static void
+gdk_surface_move_resize_toplevel (GdkSurface *window,
+ gboolean with_move,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ cairo_region_t *old_region, *new_region;
+ GdkSurfaceImplClass *impl_class;
+ gboolean expose;
+ gboolean is_resize;
+
+ expose = FALSE;
+ old_region = NULL;
+
+ is_resize = (width != -1) || (height != -1);
+
+ if (gdk_surface_is_viewable (window) &&
+ !window->input_only)
+ {
+ expose = TRUE;
+ old_region = cairo_region_copy (window->clip_region);
+ }
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ impl_class->move_resize (window, with_move, x, y, width, height);
+
+ /* Avoid recomputing for pure toplevel moves, for performance reasons */
+ if (is_resize)
+ recompute_visible_regions (window, FALSE);
+
+ if (expose)
+ {
+ new_region = cairo_region_copy (window->clip_region);
+
+ /* This is the newly exposed area (due to any resize),
+ * X will expose it, but lets do that without the roundtrip
+ */
+ cairo_region_subtract (new_region, old_region);
+ gdk_surface_invalidate_region_full (window, new_region, TRUE);
+
+ cairo_region_destroy (old_region);
+ cairo_region_destroy (new_region);
+ }
+}
+
+
+static void
+gdk_surface_move_resize_internal (GdkSurface *window,
+ gboolean with_move,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ cairo_region_t *old_region, *new_region;
+ gboolean expose;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->destroyed)
+ return;
+
+ if (gdk_surface_is_toplevel (window))
+ {
+ gdk_surface_move_resize_toplevel (window, with_move, x, y, width, height);
+ return;
+ }
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ /* Bail early if no change */
+ if (window->width == width &&
+ window->height == height &&
+ (!with_move ||
+ (window->x == x &&
+ window->y == y)))
+ return;
+
+ /* Handle child windows */
+
+ expose = FALSE;
+ old_region = NULL;
+
+ if (gdk_surface_is_viewable (window) &&
+ !window->input_only)
+ {
+ GdkRectangle r;
+
+ expose = TRUE;
+
+ r.x = window->x;
+ r.y = window->y;
+ r.width = window->width;
+ r.height = window->height;
+
+ old_region = cairo_region_create_rectangle (&r);
+ }
+
+ /* Set the new position and size */
+ if (with_move)
+ {
+ window->x = x;
+ window->y = y;
+ }
+ if (!(width < 0 && height < 0))
+ {
+ window->width = width;
+ window->height = height;
+ }
+
+ recompute_visible_regions (window, FALSE);
+
+ if (expose)
+ {
+ GdkRectangle r;
+
+ r.x = window->x;
+ r.y = window->y;
+ r.width = window->width;
+ r.height = window->height;
+
+ new_region = cairo_region_create_rectangle (&r);
+
+ cairo_region_union (new_region, old_region);
+
+ gdk_surface_invalidate_region_full (window->parent, new_region, TRUE);
+
+ cairo_region_destroy (old_region);
+ cairo_region_destroy (new_region);
+ }
+}
+
+
+
+/**
+ * gdk_surface_move:
+ * @window: a #GdkSurface
+ * @x: X coordinate relative to window’s parent
+ * @y: Y coordinate relative to window’s parent
+ *
+ * Repositions a window relative to its parent window.
+ * For toplevel windows, window managers may ignore or modify the move;
+ * you should probably use gtk_window_move() on a #GtkWindow widget
+ * anyway, instead of using GDK functions. For child windows,
+ * the move will reliably succeed.
+ *
+ * If you’re also planning to resize the window, use gdk_surface_move_resize()
+ * to both move and resize simultaneously, for a nicer visual effect.
+ **/
+void
+gdk_surface_move (GdkSurface *window,
+ gint x,
+ gint y)
+{
+ gdk_surface_move_resize_internal (window, TRUE, x, y, -1, -1);
+}
+
+/**
+ * gdk_surface_resize:
+ * @window: a #GdkSurface
+ * @width: new width of the window
+ * @height: new height of the window
+ *
+ * Resizes @window; for toplevel windows, asks the window manager to resize
+ * the window. The window manager may not allow the resize. When using GTK+,
+ * use gtk_window_resize() instead of this low-level GDK function.
+ *
+ * Windows may not be resized below 1x1.
+ *
+ * If you’re also planning to move the window, use gdk_surface_move_resize()
+ * to both move and resize simultaneously, for a nicer visual effect.
+ **/
+void
+gdk_surface_resize (GdkSurface *window,
+ gint width,
+ gint height)
+{
+ gdk_surface_move_resize_internal (window, FALSE, 0, 0, width, height);
+}
+
+
+/**
+ * gdk_surface_move_resize:
+ * @window: a #GdkSurface
+ * @x: new X position relative to window’s parent
+ * @y: new Y position relative to window’s parent
+ * @width: new width
+ * @height: new height
+ *
+ * Equivalent to calling gdk_surface_move() and gdk_surface_resize(),
+ * except that both operations are performed at once, avoiding strange
+ * visual effects. (i.e. the user may be able to see the window first
+ * move, then resize, if you don’t use gdk_surface_move_resize().)
+ **/
+void
+gdk_surface_move_resize (GdkSurface *window,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ gdk_surface_move_resize_internal (window, TRUE, x, y, width, height);
+}
+
+/**
+ * gdk_surface_move_to_rect:
+ * @window: the #GdkSurface to move
+ * @rect: (not nullable): the destination #GdkRectangle to align @window with
+ * @rect_anchor: the point on @rect to align with @window's anchor point
+ * @window_anchor: the point on @window to align with @rect's anchor point
+ * @anchor_hints: positioning hints to use when limited on space
+ * @rect_anchor_dx: horizontal offset to shift @window, i.e. @rect's anchor
+ * point
+ * @rect_anchor_dy: vertical offset to shift @window, i.e. @rect's anchor point
+ *
+ * Moves @window to @rect, aligning their anchor points.
+ *
+ * @rect is relative to the top-left corner of the window that @window is
+ * transient for. @rect_anchor and @window_anchor determine anchor points on
+ * @rect and @window to pin together. @rect's anchor point can optionally be
+ * offset by @rect_anchor_dx and @rect_anchor_dy, which is equivalent to
+ * offsetting the position of @window.
+ *
+ * @anchor_hints determines how @window will be moved if the anchor points cause
+ * it to move off-screen. For example, %GDK_ANCHOR_FLIP_X will replace
+ * %GDK_GRAVITY_NORTH_WEST with %GDK_GRAVITY_NORTH_EAST and vice versa if
+ * @window extends beyond the left or right edges of the monitor.
+ *
+ * Connect to the #GdkSurface::moved-to-rect signal to find out how it was
+ * actually positioned.
+ *
+ * Stability: Private
+ */
+void
+gdk_surface_move_to_rect (GdkSurface *window,
+ const GdkRectangle *rect,
+ GdkGravity rect_anchor,
+ GdkGravity window_anchor,
+ GdkAnchorHints anchor_hints,
+ gint rect_anchor_dx,
+ gint rect_anchor_dy)
+{
+ GdkSurfaceImplClass *impl_class;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (window->transient_for);
+ g_return_if_fail (rect);
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ impl_class->move_to_rect (window,
+ rect,
+ rect_anchor,
+ window_anchor,
+ anchor_hints,
+ rect_anchor_dx,
+ rect_anchor_dy);
+}
+
+/**
+ * gdk_surface_scroll:
+ * @window: a #GdkSurface
+ * @dx: Amount to scroll in the X direction
+ * @dy: Amount to scroll in the Y direction
+ *
+ * Scroll the contents of @window, both pixels and children, by the
+ * given amount. @window itself does not move. Portions of the window
+ * that the scroll operation brings in from offscreen areas are
+ * invalidated. The invalidated region may be bigger than what would
+ * strictly be necessary.
+ *
+ * For X11, a minimum area will be invalidated if the window has no
+ * subwindows, or if the edges of the window’s parent do not extend
+ * beyond the edges of the window. In other cases, a multi-step process
+ * is used to scroll the window which may produce temporary visual
+ * artifacts and unnecessary invalidations.
+ **/
+void
+gdk_surface_scroll (GdkSurface *window,
+ gint dx,
+ gint dy)
+{
+ GList *tmp_list;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (dx == 0 && dy == 0)
+ return;
+
+ if (window->destroyed)
+ return;
+
+ /* First move all child windows, without causing invalidation */
+
+ tmp_list = window->children;
+ while (tmp_list)
+ {
+ GdkSurface *child = GDK_SURFACE (tmp_list->data);
+
+ /* Just update the positions, the bits will move with the copy */
+ child->x += dx;
+ child->y += dy;
+
+ tmp_list = tmp_list->next;
+ }
+
+ recompute_visible_regions (window, TRUE);
+
+ gdk_surface_invalidate_rect_full (window, NULL, TRUE);
+}
+
+/**
+ * gdk_surface_move_region:
+ * @window: a #GdkSurface
+ * @region: The #cairo_region_t to move
+ * @dx: Amount to move in the X direction
+ * @dy: Amount to move in the Y direction
+ *
+ * Move the part of @window indicated by @region by @dy pixels in the Y
+ * direction and @dx pixels in the X direction. The portions of @region
+ * that not covered by the new position of @region are invalidated.
+ *
+ * Child windows are not moved.
+ */
+void
+gdk_surface_move_region (GdkSurface *window,
+ const cairo_region_t *region,
+ gint dx,
+ gint dy)
+{
+ cairo_region_t *expose_area;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (region != NULL);
+
+ if (dx == 0 && dy == 0)
+ return;
+
+ if (window->destroyed)
+ return;
+
+ expose_area = cairo_region_copy (region);
+ cairo_region_translate (expose_area, dx, dy);
+ cairo_region_union (expose_area, region);
+
+ gdk_surface_invalidate_region_full (window, expose_area, FALSE);
+ cairo_region_destroy (expose_area);
+}
+
+static void
+gdk_surface_set_cursor_internal (GdkSurface *window,
+ GdkDevice *device,
+ GdkCursor *cursor)
+{
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ g_assert (gdk_surface_get_display (window) == gdk_device_get_display (device));
+
+ if (window->window_type == GDK_SURFACE_ROOT ||
+ window->window_type == GDK_SURFACE_FOREIGN)
+ GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
+ else
+ {
+ GdkPointerSurfaceInfo *pointer_info;
+ GdkDisplay *display;
+
+ display = gdk_surface_get_display (window);
+ pointer_info = _gdk_display_get_pointer_info (display, device);
+
+ if (_gdk_surface_event_parent_of (window, pointer_info->window_under_pointer))
+ update_cursor (display, device);
+ }
+}
+
+/**
+ * gdk_surface_get_cursor:
+ * @window: a #GdkSurface
+ *
+ * Retrieves a #GdkCursor pointer for the cursor currently set on the
+ * specified #GdkSurface, or %NULL. If the return value is %NULL then
+ * there is no custom cursor set on the specified window, and it is
+ * using the cursor for its parent window.
+ *
+ * Returns: (nullable) (transfer none): a #GdkCursor, or %NULL. The
+ * returned object is owned by the #GdkSurface and should not be
+ * unreferenced directly. Use gdk_surface_set_cursor() to unset the
+ * cursor of the window
+ */
+GdkCursor *
+gdk_surface_get_cursor (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ return window->cursor;
+}
+
+/**
+ * gdk_surface_set_cursor:
+ * @window: a #GdkSurface
+ * @cursor: (allow-none): a cursor
+ *
+ * Sets the default mouse pointer for a #GdkSurface.
+ *
+ * Note that @cursor must be for the same display as @window.
+ *
+ * Use gdk_cursor_new_for_display() or gdk_cursor_new_from_texture() to
+ * create the cursor. To make the cursor invisible, use %GDK_BLANK_CURSOR.
+ * Passing %NULL for the @cursor argument to gdk_surface_set_cursor() means
+ * that @window will use the cursor of its parent window. Most windows
+ * should use this default.
+ */
+void
+gdk_surface_set_cursor (GdkSurface *window,
+ GdkCursor *cursor)
+{
+ GdkDisplay *display;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ display = gdk_surface_get_display (window);
+
+ if (window->cursor)
+ {
+ g_object_unref (window->cursor);
+ window->cursor = NULL;
+ }
+
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ GdkDevice *device;
+ GList *seats, *s;
+
+ if (cursor)
+ window->cursor = g_object_ref (cursor);
+
+ seats = gdk_display_list_seats (display);
+
+ for (s = seats; s; s = s->next)
+ {
+ GList *devices, *d;
+
+ device = gdk_seat_get_pointer (s->data);
+ gdk_surface_set_cursor_internal (window, device, window->cursor);
+
+ devices = gdk_seat_get_slaves (s->data, GDK_SEAT_CAPABILITY_TABLET_STYLUS);
+ for (d = devices; d; d = d->next)
+ {
+ device = gdk_device_get_associated_device (d->data);
+ gdk_surface_set_cursor_internal (window, device, window->cursor);
+ }
+ g_list_free (devices);
+ }
+
+ g_list_free (seats);
+ g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_CURSOR]);
+ }
+}
+
+/**
+ * gdk_surface_get_device_cursor:
+ * @window: a #GdkSurface.
+ * @device: a master, pointer #GdkDevice.
+ *
+ * Retrieves a #GdkCursor pointer for the @device currently set on the
+ * specified #GdkSurface, or %NULL. If the return value is %NULL then
+ * there is no custom cursor set on the specified window, and it is
+ * using the cursor for its parent window.
+ *
+ * Returns: (nullable) (transfer none): a #GdkCursor, or %NULL. The
+ * returned object is owned by the #GdkSurface and should not be
+ * unreferenced directly. Use gdk_surface_set_cursor() to unset the
+ * cursor of the window
+ **/
+GdkCursor *
+gdk_surface_get_device_cursor (GdkSurface *window,
+ GdkDevice *device)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
+ g_return_val_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER, NULL);
+
+ return g_hash_table_lookup (window->device_cursor, device);
+}
+
+/**
+ * gdk_surface_set_device_cursor:
+ * @window: a #GdkSurface
+ * @device: a master, pointer #GdkDevice
+ * @cursor: a #GdkCursor
+ *
+ * Sets a specific #GdkCursor for a given device when it gets inside @window.
+ * Use gdk_cursor_new_for_display() or gdk_cursor_new_from_texture() to create
+ * the cursor. To make the cursor invisible, use %GDK_BLANK_CURSOR. Passing
+ * %NULL for the @cursor argument to gdk_surface_set_cursor() means that
+ * @window will use the cursor of its parent window. Most windows should
+ * use this default.
+ **/
+void
+gdk_surface_set_device_cursor (GdkSurface *window,
+ GdkDevice *device,
+ GdkCursor *cursor)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (GDK_IS_DEVICE (device));
+ g_return_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD);
+ g_return_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER);
+
+ if (!cursor)
+ g_hash_table_remove (window->device_cursor, device);
+ else
+ g_hash_table_replace (window->device_cursor, device, g_object_ref (cursor));
+
+ gdk_surface_set_cursor_internal (window, device, cursor);
+}
+
+/**
+ * gdk_surface_get_geometry:
+ * @window: a #GdkSurface
+ * @x: (out) (allow-none): return location for X coordinate of window (relative to its parent)
+ * @y: (out) (allow-none): return location for Y coordinate of window (relative to its parent)
+ * @width: (out) (allow-none): return location for width of window
+ * @height: (out) (allow-none): return location for height of window
+ *
+ * Any of the return location arguments to this function may be %NULL,
+ * if you aren’t interested in getting the value of that field.
+ *
+ * The X and Y coordinates returned are relative to the parent window
+ * of @window, which for toplevels usually means relative to the
+ * window decorations (titlebar, etc.) rather than relative to the
+ * root window (screen-size background window).
+ *
+ * On the X11 platform, the geometry is obtained from the X server,
+ * so reflects the latest position of @window; this may be out-of-sync
+ * with the position of @window delivered in the most-recently-processed
+ * #GdkEventConfigure. gdk_surface_get_position() in contrast gets the
+ * position from the most recent configure event.
+ *
+ * Note: If @window is not a toplevel, it is much better
+ * to call gdk_surface_get_position(), gdk_surface_get_width() and
+ * gdk_surface_get_height() instead, because it avoids the roundtrip to
+ * the X server and because these functions support the full 32-bit
+ * coordinate space, whereas gdk_surface_get_geometry() is restricted to
+ * the 16-bit coordinates of X11.
+ */
+void
+gdk_surface_get_geometry (GdkSurface *window,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height)
+{
+ GdkSurface *parent;
+ GdkSurfaceImplClass *impl_class;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ if (gdk_surface_has_impl (window))
+ {
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ impl_class->get_geometry (window, x, y,
+ width, height);
+ /* This reports the position wrt to the native parent, we need to convert
+ it to be relative to the client side parent */
+ parent = window->parent;
+ if (parent && !gdk_surface_has_impl (parent))
+ {
+ if (x)
+ *x -= parent->abs_x;
+ if (y)
+ *y -= parent->abs_y;
+ }
+ }
+ else
+ {
+ if (x)
+ *x = window->x;
+ if (y)
+ *y = window->y;
+ if (width)
+ *width = window->width;
+ if (height)
+ *height = window->height;
+ }
+ }
+}
+
+/**
+ * gdk_surface_get_width:
+ * @window: a #GdkSurface
+ *
+ * Returns the width of the given @window.
+ *
+ * On the X11 platform the returned size is the size reported in the
+ * most-recently-processed configure event, rather than the current
+ * size on the X server.
+ *
+ * Returns: The width of @window
+ */
+int
+gdk_surface_get_width (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
+
+ return window->width;
+}
+
+/**
+ * gdk_surface_get_height:
+ * @window: a #GdkSurface
+ *
+ * Returns the height of the given @window.
+ *
+ * On the X11 platform the returned size is the size reported in the
+ * most-recently-processed configure event, rather than the current
+ * size on the X server.
+ *
+ * Returns: The height of @window
+ */
+int
+gdk_surface_get_height (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
+
+ return window->height;
+}
+
+/**
+ * gdk_surface_get_origin:
+ * @window: a #GdkSurface
+ * @x: (out) (allow-none): return location for X coordinate
+ * @y: (out) (allow-none): return location for Y coordinate
+ *
+ * Obtains the position of a window in root window coordinates.
+ * (Compare with gdk_surface_get_position() and
+ * gdk_surface_get_geometry() which return the position of a window
+ * relative to its parent window.)
+ *
+ * Returns: not meaningful, ignore
+ */
+gint
+gdk_surface_get_origin (GdkSurface *window,
+ gint *x,
+ gint *y)
+{
+ gint dummy_x, dummy_y;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
+
+ gdk_surface_get_root_coords (window,
+ 0, 0,
+ x ? x : &dummy_x,
+ y ? y : &dummy_y);
+
+ return TRUE;
+}
+
+/**
+ * gdk_surface_get_root_coords:
+ * @window: a #GdkSurface
+ * @x: X coordinate in window
+ * @y: Y coordinate in window
+ * @root_x: (out): return location for X coordinate
+ * @root_y: (out): return location for Y coordinate
+ *
+ * Obtains the position of a window position in root
+ * window coordinates. This is similar to
+ * gdk_surface_get_origin() but allows you to pass
+ * in any position in the window, not just the origin.
+ */
+void
+gdk_surface_get_root_coords (GdkSurface *window,
+ gint x,
+ gint y,
+ gint *root_x,
+ gint *root_y)
+{
+ GdkSurfaceImplClass *impl_class;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ {
+ *root_x = 0;
+ *root_y = 0;
+ return;
+ }
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ impl_class->get_root_coords (window->impl_window,
+ x + window->abs_x,
+ y + window->abs_y,
+ root_x, root_y);
+}
+
+/**
+ * gdk_surface_coords_to_parent:
+ * @window: a child window
+ * @x: X coordinate in child’s coordinate system
+ * @y: Y coordinate in child’s coordinate system
+ * @parent_x: (out) (allow-none): return location for X coordinate
+ * in parent’s coordinate system, or %NULL
+ * @parent_y: (out) (allow-none): return location for Y coordinate
+ * in parent’s coordinate system, or %NULL
+ *
+ * Transforms window coordinates from a child window to its parent
+ * window. Calling this function is equivalent to adding the return
+ * values of gdk_surface_get_position() to the child coordinates.
+ *
+ * See also: gdk_surface_coords_from_parent()
+ **/
+void
+gdk_surface_coords_to_parent (GdkSurface *window,
+ gdouble x,
+ gdouble y,
+ gdouble *parent_x,
+ gdouble *parent_y)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (parent_x)
+ *parent_x = x + window->x;
+
+ if (parent_y)
+ *parent_y = y + window->y;
+}
+
+/**
+ * gdk_surface_coords_from_parent:
+ * @window: a child window
+ * @parent_x: X coordinate in parent’s coordinate system
+ * @parent_y: Y coordinate in parent’s coordinate system
+ * @x: (out) (allow-none): return location for X coordinate in child’s coordinate system
+ * @y: (out) (allow-none): return location for Y coordinate in child’s coordinate system
+ *
+ * Transforms window coordinates from a parent window to a child
+ * window.
+ *
+ * Calling this function is equivalent to subtracting the return
+ * values of gdk_surface_get_position() from the parent coordinates.
+ *
+ * See also: gdk_surface_coords_to_parent()
+ **/
+void
+gdk_surface_coords_from_parent (GdkSurface *window,
+ gdouble parent_x,
+ gdouble parent_y,
+ gdouble *x,
+ gdouble *y)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (x)
+ *x = parent_x - window->x;
+
+ if (y)
+ *y = parent_y - window->y;
+}
+
+/**
+ * gdk_surface_shape_combine_region:
+ * @window: a #GdkSurface
+ * @shape_region: (allow-none): region of window to be non-transparent
+ * @offset_x: X position of @shape_region in @window coordinates
+ * @offset_y: Y position of @shape_region in @window coordinates
+ *
+ * Makes pixels in @window outside @shape_region be transparent,
+ * so that the window may be nonrectangular.
+ *
+ * If @shape_region is %NULL, the shape will be unset, so the whole
+ * window will be opaque again. @offset_x and @offset_y are ignored
+ * if @shape_region is %NULL.
+ *
+ * On the X11 platform, this uses an X server extension which is
+ * widely available on most common platforms, but not available on
+ * very old X servers, and occasionally the implementation will be
+ * buggy. On servers without the shape extension, this function
+ * will do nothing.
+ *
+ * This function works on both toplevel and child windows.
+ */
+void
+gdk_surface_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+ cairo_region_t *old_region, *new_region, *diff;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (!window->shape && shape_region == NULL)
+ return;
+
+ window->shaped = (shape_region != NULL);
+
+ if (window->shape)
+ cairo_region_destroy (window->shape);
+
+ old_region = NULL;
+ if (GDK_SURFACE_IS_MAPPED (window))
+ old_region = cairo_region_copy (window->clip_region);
+
+ if (shape_region)
+ {
+ window->shape = cairo_region_copy (shape_region);
+ cairo_region_translate (window->shape, offset_x, offset_y);
+ }
+ else
+ window->shape = NULL;
+
+ recompute_visible_regions (window, FALSE);
+
+ if (old_region)
+ {
+ new_region = cairo_region_copy (window->clip_region);
+
+ /* New area in the window, needs invalidation */
+ diff = cairo_region_copy (new_region);
+ cairo_region_subtract (diff, old_region);
+
+ gdk_surface_invalidate_region_full (window, diff, TRUE);
+
+ cairo_region_destroy (diff);
+
+ if (!gdk_surface_is_toplevel (window))
+ {
+ /* New area in the non-root parent window, needs invalidation */
+ diff = cairo_region_copy (old_region);
+ cairo_region_subtract (diff, new_region);
+
+ /* Adjust region to parent window coords */
+ cairo_region_translate (diff, window->x, window->y);
+
+ gdk_surface_invalidate_region_full (window->parent, diff, TRUE);
+
+ cairo_region_destroy (diff);
+ }
+
+ cairo_region_destroy (new_region);
+ cairo_region_destroy (old_region);
+ }
+}
+
+static void
+do_child_shapes (GdkSurface *window,
+ gboolean merge)
+{
+ GdkRectangle r;
+ cairo_region_t *region;
+
+ r.x = 0;
+ r.y = 0;
+ r.width = window->width;
+ r.height = window->height;
+
+ region = cairo_region_create_rectangle (&r);
+ remove_child_area (window, FALSE, region);
+
+ if (merge && window->shape)
+ cairo_region_subtract (region, window->shape);
+
+ cairo_region_xor_rectangle (region, &r);
+
+ gdk_surface_shape_combine_region (window, region, 0, 0);
+
+ cairo_region_destroy (region);
+}
+
+/**
+ * gdk_surface_set_child_shapes:
+ * @window: a #GdkSurface
+ *
+ * Sets the shape mask of @window to the union of shape masks
+ * for all children of @window, ignoring the shape mask of @window
+ * itself. Contrast with gdk_surface_merge_child_shapes() which includes
+ * the shape mask of @window in the masks to be merged.
+ **/
+void
+gdk_surface_set_child_shapes (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ do_child_shapes (window, FALSE);
+}
+
+/**
+ * gdk_surface_merge_child_shapes:
+ * @window: a #GdkSurface
+ *
+ * Merges the shape masks for any child windows into the
+ * shape mask for @window. i.e. the union of all masks
+ * for @window and its children will become the new mask
+ * for @window. See gdk_surface_shape_combine_region().
+ *
+ * This function is distinct from gdk_surface_set_child_shapes()
+ * because it includes @window’s shape mask in the set of shapes to
+ * be merged.
+ */
+void
+gdk_surface_merge_child_shapes (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ do_child_shapes (window, TRUE);
+}
+
+/**
+ * gdk_surface_input_shape_combine_region:
+ * @window: a #GdkSurface
+ * @shape_region: region of window to be non-transparent
+ * @offset_x: X position of @shape_region in @window coordinates
+ * @offset_y: Y position of @shape_region in @window coordinates
+ *
+ * Like gdk_surface_shape_combine_region(), but the shape applies
+ * only to event handling. Mouse events which happen while
+ * the pointer position corresponds to an unset bit in the
+ * mask will be passed on the window below @window.
+ *
+ * An input shape is typically used with RGBA windows.
+ * The alpha channel of the window defines which pixels are
+ * invisible and allows for nicely antialiased borders,
+ * and the input shape controls where the window is
+ * “clickable”.
+ *
+ * On the X11 platform, this requires version 1.1 of the
+ * shape extension.
+ *
+ * On the Win32 platform, this functionality is not present and the
+ * function does nothing.
+ */
+void
+gdk_surface_input_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+ GdkSurfaceImplClass *impl_class;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (window->input_shape)
+ cairo_region_destroy (window->input_shape);
+
+ if (shape_region)
+ {
+ window->input_shape = cairo_region_copy (shape_region);
+ cairo_region_translate (window->input_shape, offset_x, offset_y);
+ }
+ else
+ window->input_shape = NULL;
+
+ if (gdk_surface_has_impl (window))
+ {
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ impl_class->input_shape_combine_region (window, window->input_shape, 0, 0);
+ }
+}
+
+static void
+do_child_input_shapes (GdkSurface *window,
+ gboolean merge)
+{
+ GdkRectangle r;
+ cairo_region_t *region;
+
+ r.x = 0;
+ r.y = 0;
+ r.width = window->width;
+ r.height = window->height;
+
+ region = cairo_region_create_rectangle (&r);
+ remove_child_area (window, TRUE, region);
+
+ if (merge && window->shape)
+ cairo_region_subtract (region, window->shape);
+ if (merge && window->input_shape)
+ cairo_region_subtract (region, window->input_shape);
+
+ cairo_region_xor_rectangle (region, &r);
+
+ gdk_surface_input_shape_combine_region (window, region, 0, 0);
+}
+
+
+/**
+ * gdk_surface_set_child_input_shapes:
+ * @window: a #GdkSurface
+ *
+ * Sets the input shape mask of @window to the union of input shape masks
+ * for all children of @window, ignoring the input shape mask of @window
+ * itself. Contrast with gdk_surface_merge_child_input_shapes() which includes
+ * the input shape mask of @window in the masks to be merged.
+ **/
+void
+gdk_surface_set_child_input_shapes (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ do_child_input_shapes (window, FALSE);
+}
+
+/**
+ * gdk_surface_set_pass_through:
+ * @window: a #GdkSurface
+ * @pass_through: a boolean
+ *
+ * Sets whether input to the window is passed through to the window
+ * below.
+ *
+ * The default value of this is %FALSE, which means that pointer
+ * events that happen inside the window are send first to the window,
+ * but if the event is not selected by the event mask then the event
+ * is sent to the parent window, and so on up the hierarchy.
+ *
+ * If @pass_through is %TRUE then such pointer events happen as if the
+ * window wasn't there at all, and thus will be sent first to any
+ * windows below @window. This is useful if the window is used in a
+ * transparent fashion. In the terminology of the web this would be called
+ * "pointer-events: none".
+ *
+ * Note that a window with @pass_through %TRUE can still have a subwindow
+ * without pass through, so you can get events on a subset of a window. And in
+ * that cases you would get the in-between related events such as the pointer
+ * enter/leave events on its way to the destination window.
+ **/
+void
+gdk_surface_set_pass_through (GdkSurface *window,
+ gboolean pass_through)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ window->pass_through = !!pass_through;
+}
+
+/**
+ * gdk_surface_get_pass_through:
+ * @window: a #GdkSurface
+ *
+ * Returns whether input to the window is passed through to the window
+ * below.
+ *
+ * See gdk_surface_set_pass_through() for details
+ **/
+gboolean
+gdk_surface_get_pass_through (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ return window->pass_through;
+}
+
+/**
+ * gdk_surface_merge_child_input_shapes:
+ * @window: a #GdkSurface
+ *
+ * Merges the input shape masks for any child windows into the
+ * input shape mask for @window. i.e. the union of all input masks
+ * for @window and its children will become the new input mask
+ * for @window. See gdk_surface_input_shape_combine_region().
+ *
+ * This function is distinct from gdk_surface_set_child_input_shapes()
+ * because it includes @window’s input shape mask in the set of
+ * shapes to be merged.
+ **/
+void
+gdk_surface_merge_child_input_shapes (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ do_child_input_shapes (window, TRUE);
+}
+
+
+/**
+ * gdk_surface_get_modal_hint:
+ * @window: A toplevel #GdkSurface.
+ *
+ * Determines whether or not the window manager is hinted that @window
+ * has modal behaviour.
+ *
+ * Returns: whether or not the window has the modal hint set.
+ */
+gboolean
+gdk_surface_get_modal_hint (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ return window->modal_hint;
+}
+
+/**
+ * gdk_surface_get_accept_focus:
+ * @window: a toplevel #GdkSurface.
+ *
+ * Determines whether or not the desktop environment shuld be hinted that
+ * the window does not want to receive input focus.
+ *
+ * Returns: whether or not the window should receive input focus.
+ */
+gboolean
+gdk_surface_get_accept_focus (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ return window->accept_focus;
+}
+
+/**
+ * gdk_surface_get_focus_on_map:
+ * @window: a toplevel #GdkSurface.
+ *
+ * Determines whether or not the desktop environment should be hinted that the
+ * window does not want to receive input focus when it is mapped.
+ *
+ * Returns: whether or not the window wants to receive input focus when
+ * it is mapped.
+ */
+gboolean
+gdk_surface_get_focus_on_map (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ return window->focus_on_map;
+}
+
+/**
+ * gdk_surface_is_input_only:
+ * @window: a toplevel #GdkSurface
+ *
+ * Determines whether or not the window is an input only window.
+ *
+ * Returns: %TRUE if @window is input only
+ */
+gboolean
+gdk_surface_is_input_only (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ return window->input_only;
+}
+
+/**
+ * gdk_surface_is_shaped:
+ * @window: a toplevel #GdkSurface
+ *
+ * Determines whether or not the window is shaped.
+ *
+ * Returns: %TRUE if @window is shaped
+ */
+gboolean
+gdk_surface_is_shaped (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ return window->shaped;
+}
+
+/* Gets the toplevel for a window as used for events,
+ i.e. including offscreen parents going up to the native
+ toplevel */
+static GdkSurface *
+get_event_toplevel (GdkSurface *window)
+{
+ GdkSurface *parent;
+
+ while ((parent = window->parent) != NULL &&
+ (parent->window_type != GDK_SURFACE_ROOT))
+ window = parent;
+
+ return window;
+}
+
+gboolean
+_gdk_surface_event_parent_of (GdkSurface *parent,
+ GdkSurface *child)
+{
+ GdkSurface *w;
+
+ w = child;
+ while (w != NULL)
+ {
+ if (w == parent)
+ return TRUE;
+
+ w = w->parent;
+ }
+
+ return FALSE;
+}
+
+static void
+update_cursor (GdkDisplay *display,
+ GdkDevice *device)
+{
+ GdkSurface *cursor_window, *parent, *toplevel;
+ GdkSurface *pointer_window;
+ GdkPointerSurfaceInfo *pointer_info;
+ GdkDeviceGrabInfo *grab;
+ GdkCursor *cursor;
+
+ pointer_info = _gdk_display_get_pointer_info (display, device);
+ pointer_window = pointer_info->window_under_pointer;
+
+ /* We ignore the serials here and just pick the last grab
+ we've sent, as that would shortly be used anyway. */
+ grab = _gdk_display_get_last_device_grab (display, device);
+ if (/* have grab */
+ grab != NULL &&
+ /* the pointer is not in a descendant of the grab window */
+ !_gdk_surface_event_parent_of (grab->window, pointer_window))
+ {
+ /* use the cursor from the grab window */
+ cursor_window = grab->window;
+ }
+ else
+ {
+ /* otherwise use the cursor from the pointer window */
+ cursor_window = pointer_window;
+ }
+
+ /* Find the first window with the cursor actually set, as
+ the cursor is inherited from the parent */
+ while (cursor_window->cursor == NULL &&
+ !g_hash_table_contains (cursor_window->device_cursor, device) &&
+ (parent = cursor_window->parent) != NULL &&
+ parent->window_type != GDK_SURFACE_ROOT)
+ cursor_window = parent;
+
+ cursor = g_hash_table_lookup (cursor_window->device_cursor, device);
+
+ if (!cursor)
+ cursor = cursor_window->cursor;
+
+ /* Set all cursors on toplevel, otherwise its tricky to keep track of
+ * which native window has what cursor set. */
+ toplevel = get_event_toplevel (pointer_window);
+ GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, toplevel, cursor);
+}
+
+static gboolean
+point_in_window (GdkSurface *window,
+ gdouble x,
+ gdouble y)
+{
+ return
+ x >= 0 && x < window->width &&
+ y >= 0 && y < window->height &&
+ (window->shape == NULL ||
+ cairo_region_contains_point (window->shape,
+ x, y)) &&
+ (window->input_shape == NULL ||
+ cairo_region_contains_point (window->input_shape,
+ x, y));
+}
+
+/* Same as point_in_window, except it also takes pass_through and its
+ interaction with child windows into account */
+static gboolean
+point_in_input_window (GdkSurface *window,
+ gdouble x,
+ gdouble y,
+ GdkSurface **input_window,
+ gdouble *input_window_x,
+ gdouble *input_window_y)
+{
+ GdkSurface *sub;
+ double child_x, child_y;
+ GList *l;
+
+ if (!point_in_window (window, x, y))
+ return FALSE;
+
+ if (!window->pass_through)
+ {
+ if (input_window)
+ {
+ *input_window = window;
+ *input_window_x = x;
+ *input_window_y = y;
+ }
+ return TRUE;
+ }
+
+ /* For pass-through, must be over a child input window */
+
+ /* Children is ordered in reverse stack order, i.e. first is topmost */
+ for (l = window->children; l != NULL; l = l->next)
+ {
+ sub = l->data;
+
+ if (!GDK_SURFACE_IS_MAPPED (sub))
+ continue;
+
+ gdk_surface_coords_from_parent ((GdkSurface *)sub,
+ x, y,
+ &child_x, &child_y);
+ if (point_in_input_window (sub, child_x, child_y,
+ input_window, input_window_x, input_window_y))
+ {
+ if (input_window)
+ gdk_surface_coords_to_parent (sub,
+ *input_window_x,
+ *input_window_y,
+ input_window_x,
+ input_window_y);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+GdkSurface *
+_gdk_surface_find_child_at (GdkSurface *window,
+ double x,
+ double y)
+{
+ GdkSurface *sub;
+ double child_x, child_y;
+ GList *l;
+
+ if (point_in_window (window, x, y))
+ {
+ /* Children is ordered in reverse stack order, i.e. first is topmost */
+ for (l = window->children; l != NULL; l = l->next)
+ {
+ sub = l->data;
+
+ if (!GDK_SURFACE_IS_MAPPED (sub))
+ continue;
+
+ gdk_surface_coords_from_parent ((GdkSurface *)sub,
+ x, y,
+ &child_x, &child_y);
+ if (point_in_input_window (sub, child_x, child_y,
+ NULL, NULL, NULL))
+ return (GdkSurface *)sub;
+ }
+ }
+
+ return NULL;
+}
+
+GdkSurface *
+_gdk_surface_find_descendant_at (GdkSurface *window,
+ gdouble x,
+ gdouble y,
+ gdouble *found_x,
+ gdouble *found_y)
+{
+ GdkSurface *sub, *input_window;
+ gdouble child_x, child_y;
+ GList *l;
+ gboolean found;
+
+ if (point_in_window (window, x, y))
+ {
+ do
+ {
+ found = FALSE;
+ /* Children is ordered in reverse stack order, i.e. first is topmost */
+ for (l = window->children; l != NULL; l = l->next)
+ {
+ sub = l->data;
+
+ if (!GDK_SURFACE_IS_MAPPED (sub))
+ continue;
+
+ gdk_surface_coords_from_parent ((GdkSurface *)sub,
+ x, y,
+ &child_x, &child_y);
+ if (point_in_input_window (sub, child_x, child_y,
+ &input_window, &child_x, &child_y))
+ {
+ x = child_x;
+ y = child_y;
+ window = input_window;
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ while (found);
+ }
+ else
+ {
+ /* Not in window at all */
+ window = NULL;
+ }
+
+ if (found_x)
+ *found_x = x;
+ if (found_y)
+ *found_y = y;
+
+ return window;
+}
+
+/**
+ * gdk_surface_beep:
+ * @window: a toplevel #GdkSurface
+ *
+ * Emits a short beep associated to @window in the appropriate
+ * display, if supported. Otherwise, emits a short beep on
+ * the display just as gdk_display_beep().
+ **/
+void
+gdk_surface_beep (GdkSurface *window)
+{
+ GdkDisplay *display;
+ GdkSurface *toplevel;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ toplevel = get_event_toplevel (window);
+ display = gdk_surface_get_display (window);
+
+ if (toplevel)
+ {
+ if (GDK_SURFACE_IMPL_GET_CLASS (toplevel->impl)->beep (toplevel))
+ return;
+ }
+
+ /* If windows fail to beep, we beep the display. */
+ gdk_display_beep (display);
+}
+
+/**
+ * gdk_surface_set_support_multidevice:
+ * @window: a #GdkSurface.
+ * @support_multidevice: %TRUE to enable multidevice support in @window.
+ *
+ * This function will enable multidevice features in @window.
+ *
+ * Multidevice aware windows will need to handle properly multiple,
+ * per device enter/leave events, device grabs and grab ownerships.
+ **/
+void
+gdk_surface_set_support_multidevice (GdkSurface *window,
+ gboolean support_multidevice)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (window->support_multidevice == support_multidevice)
+ return;
+
+ window->support_multidevice = support_multidevice;
+
+ /* FIXME: What to do if called when some pointers are inside the window ? */
+}
+
+/**
+ * gdk_surface_get_support_multidevice:
+ * @window: a #GdkSurface.
+ *
+ * Returns %TRUE if the window is aware of the existence of multiple
+ * devices.
+ *
+ * Returns: %TRUE if the window handles multidevice features.
+ **/
+gboolean
+gdk_surface_get_support_multidevice (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return FALSE;
+
+ return window->support_multidevice;
+}
+
+/* send motion events if the right buttons are down */
+
+GdkEvent *
+_gdk_make_event (GdkSurface *window,
+ GdkEventType type,
+ GdkEvent *event_in_queue,
+ gboolean before_event)
+{
+ GdkEvent *event = gdk_event_new (type);
+ guint32 the_time;
+ GdkModifierType the_state;
+
+ the_time = gdk_event_get_time (event_in_queue);
+ gdk_event_get_state (event_in_queue, &the_state);
+
+ event->any.window = g_object_ref (window);
+ event->any.send_event = FALSE;
+ if (event_in_queue && event_in_queue->any.send_event)
+ event->any.send_event = TRUE;
+
+ switch ((guint) type)
+ {
+ case GDK_MOTION_NOTIFY:
+ event->motion.time = the_time;
+ event->motion.axes = NULL;
+ event->motion.state = the_state;
+ break;
+
+ case GDK_BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ event->button.time = the_time;
+ event->button.axes = NULL;
+ event->button.state = the_state;
+ break;
+
+ case GDK_TOUCH_BEGIN:
+ case GDK_TOUCH_UPDATE:
+ case GDK_TOUCH_END:
+ case GDK_TOUCH_CANCEL:
+ event->touch.time = the_time;
+ event->touch.axes = NULL;
+ event->touch.state = the_state;
+ break;
+
+ case GDK_SCROLL:
+ event->scroll.time = the_time;
+ event->scroll.state = the_state;
+ break;
+
+ case GDK_KEY_PRESS:
+ case GDK_KEY_RELEASE:
+ event->key.time = the_time;
+ event->key.state = the_state;
+ break;
+
+ case GDK_ENTER_NOTIFY:
+ case GDK_LEAVE_NOTIFY:
+ event->crossing.time = the_time;
+ event->crossing.state = the_state;
+ break;
+
+ case GDK_PROXIMITY_IN:
+ case GDK_PROXIMITY_OUT:
+ event->proximity.time = the_time;
+ break;
+
+ case GDK_DRAG_ENTER:
+ case GDK_DRAG_LEAVE:
+ case GDK_DRAG_MOTION:
+ case GDK_DROP_START:
+ event->dnd.time = the_time;
+ break;
+
+ case GDK_TOUCHPAD_SWIPE:
+ event->touchpad_swipe.time = the_time;
+ event->touchpad_swipe.state = the_state;
+ break;
+
+ case GDK_TOUCHPAD_PINCH:
+ event->touchpad_pinch.time = the_time;
+ event->touchpad_pinch.state = the_state;
+ break;
+
+ case GDK_FOCUS_CHANGE:
+ case GDK_CONFIGURE:
+ case GDK_MAP:
+ case GDK_UNMAP:
+ case GDK_DELETE:
+ case GDK_DESTROY:
+ case GDK_EXPOSE:
+ default:
+ break;
+ }
+
+ if (event_in_queue)
+ {
+ if (before_event)
+ _gdk_event_queue_insert_before (gdk_surface_get_display (window), event_in_queue, event);
+ else
+ _gdk_event_queue_insert_after (gdk_surface_get_display (window), event_in_queue, event);
+ }
+ else
+ _gdk_event_queue_append (gdk_surface_get_display (window), event);
+
+ return event;
+}
+
+void
+_gdk_display_set_window_under_pointer (GdkDisplay *display,
+ GdkDevice *device,
+ GdkSurface *window)
+{
+ GdkPointerSurfaceInfo *device_info;
+
+ device_info = _gdk_display_get_pointer_info (display, device);
+
+ if (device_info->window_under_pointer)
+ g_object_unref (device_info->window_under_pointer);
+ device_info->window_under_pointer = window;
+
+ if (window)
+ {
+ g_object_ref (window);
+ update_cursor (display, device);
+ }
+}
+
+#define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \
+ GDK_BUTTON2_MASK | \
+ GDK_BUTTON3_MASK | \
+ GDK_BUTTON4_MASK | \
+ GDK_BUTTON5_MASK)
+
+#ifdef DEBUG_WINDOW_PRINTING
+
+#ifdef GDK_WINDOWING_X11
+#include "x11/gdkx.h"
+#endif
+
+static void
+gdk_surface_print (GdkSurface *window,
+ int indent)
+{
+ char *s;
+ const char *window_types[] = {
+ "root",
+ "toplevel",
+ "child",
+ "dialog",
+ "temp",
+ "foreign",
+ "subsurface"
+ };
+
+ g_print ("%*s%p: [%s] %d,%d %dx%d", indent, "", window,
+ window->user_data ? g_type_name_from_instance (window->user_data) : "no widget",
+ window->x, window->y,
+ window->width, window->height
+ );
+
+ if (gdk_surface_has_impl (window))
+ {
+#ifdef GDK_WINDOWING_X11
+ g_print (" impl(0x%lx)", gdk_x11_surface_get_xid (window));
+#endif
+ }
+
+ if (window->window_type != GDK_SURFACE_CHILD)
+ g_print (" %s", window_types[window->window_type]);
+
+ if (window->input_only)
+ g_print (" input-only");
+
+ if (window->shaped)
+ g_print (" shaped");
+
+ if (!gdk_surface_is_visible ((GdkSurface *)window))
+ g_print (" hidden");
+
+ g_print (" abs[%d,%d]",
+ window->abs_x, window->abs_y);
+
+ if (window->alpha != 255)
+ g_print (" alpha[%d]",
+ window->alpha);
+
+ s = print_region (window->clip_region);
+ g_print (" clipbox[%s]", s);
+
+ g_print ("\n");
+}
+
+
+static void
+gdk_surface_print_tree (GdkSurface *window,
+ int indent,
+ gboolean include_input_only)
+{
+ GList *l;
+
+ if (window->input_only && !include_input_only)
+ return;
+
+ gdk_surface_print (window, indent);
+
+ for (l = window->children; l != NULL; l = l->next)
+ gdk_surface_print_tree (l->data, indent + 4, include_input_only);
+}
+
+#endif /* DEBUG_WINDOW_PRINTING */
+
+void
+_gdk_windowing_got_event (GdkDisplay *display,
+ GList *event_link,
+ GdkEvent *event,
+ gulong serial)
+{
+ GdkSurface *event_window;
+ gboolean unlink_event = FALSE;
+ GdkDeviceGrabInfo *button_release_grab;
+ GdkPointerSurfaceInfo *pointer_info = NULL;
+ GdkDevice *device, *source_device;
+
+ _gdk_display_update_last_event (display, event);
+
+ device = gdk_event_get_device (event);
+ source_device = gdk_event_get_source_device (event);
+
+ if (device)
+ {
+ if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD &&
+ gdk_device_get_source (device) != GDK_SOURCE_TABLET_PAD)
+ {
+ pointer_info = _gdk_display_get_pointer_info (display, device);
+
+ if (source_device != pointer_info->last_slave &&
+ gdk_device_get_device_type (source_device) == GDK_DEVICE_TYPE_SLAVE)
+ pointer_info->last_slave = source_device;
+ else if (pointer_info->last_slave)
+ source_device = pointer_info->last_slave;
+ }
+
+ _gdk_display_device_grab_update (display, device, source_device, serial);
+
+ if (gdk_device_get_input_mode (device) == GDK_MODE_DISABLED ||
+ !_gdk_display_check_grab_ownership (display, device, serial))
+ {
+ /* Device events are blocked by another
+ * device grab, or the device is disabled
+ */
+ unlink_event = TRUE;
+ goto out;
+ }
+ }
+
+ event_window = event->any.window;
+ if (!event_window)
+ goto out;
+
+#ifdef DEBUG_WINDOW_PRINTING
+ if (event->any.type == GDK_KEY_PRESS &&
+ (event->key.keyval == 0xa7 ||
+ event->key.keyval == 0xbd))
+ {
+ gdk_surface_print_tree (event_window, 0, event->key.keyval == 0xbd);
+ }
+#endif
+
+ if (event_window->window_type == GDK_SURFACE_ROOT)
+ goto out;
+
+ if (event->any.type == GDK_ENTER_NOTIFY)
+ _gdk_display_set_window_under_pointer (display, device, event_window);
+ else if (event->any.type == GDK_LEAVE_NOTIFY)
+ _gdk_display_set_window_under_pointer (display, device, NULL);
+
+ if ((event->any.type == GDK_BUTTON_RELEASE ||
+ event->any.type == GDK_TOUCH_CANCEL ||
+ event->any.type == GDK_TOUCH_END) &&
+ !event->any.send_event)
+ {
+ if (event->any.type == GDK_BUTTON_RELEASE ||
+ gdk_event_get_pointer_emulated (event))
+ {
+ button_release_grab =
+ _gdk_display_has_device_grab (display, device, serial);
+
+ if (button_release_grab &&
+ button_release_grab->implicit &&
+ (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
+ {
+ button_release_grab->serial_end = serial;
+ button_release_grab->implicit_ungrab = FALSE;
+ _gdk_display_device_grab_update (display, device, source_device, serial);
+ }
+ }
+ }
+
+ out:
+ if (unlink_event)
+ {
+ _gdk_event_queue_remove_link (display, event_link);
+ g_list_free_1 (event_link);
+ gdk_event_free (event);
+ }
+
+ /* This does two things - first it sees if there are motions at the
+ * end of the queue that can be compressed. Second, if there is just
+ * a single motion that won't be dispatched because it is a compression
+ * candidate it queues up flushing the event queue.
+ */
+ _gdk_event_queue_handle_motion_compression (display);
+}
+
+/**
+ * gdk_surface_create_similar_surface:
+ * @window: window to make new surface similar to
+ * @content: the content for the new surface
+ * @width: width of the new surface
+ * @height: height of the new surface
+ *
+ * Create a new surface that is as compatible as possible with the
+ * given @window. For example the new surface will have the same
+ * fallback resolution and font options as @window. Generally, the new
+ * surface will also use the same backend as @window, unless that is
+ * not possible for some reason. The type of the returned surface may
+ * be examined with cairo_surface_get_type().
+ *
+ * Initially the surface contents are all 0 (transparent if contents
+ * have transparency, black otherwise.)
+ *
+ * Returns: a pointer to the newly allocated surface. The caller
+ * owns the surface and should call cairo_surface_destroy() when done
+ * with it.
+ *
+ * This function always returns a valid pointer, but it will return a
+ * pointer to a “nil” surface if @other is already in an error state
+ * or any other error occurs.
+ **/
+cairo_surface_t *
+gdk_surface_create_similar_surface (GdkSurface * window,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_surface_t *window_surface, *surface;
+ double sx, sy;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ window_surface = gdk_surface_ref_impl_surface (window);
+ sx = sy = 1;
+ cairo_surface_get_device_scale (window_surface, &sx, &sy);
+
+ if (GDK_DISPLAY_DEBUG_CHECK (window->display, CAIRO_IMAGE))
+ {
+ surface = cairo_image_surface_create (content == CAIRO_CONTENT_COLOR ? CAIRO_FORMAT_RGB24 :
+ content == CAIRO_CONTENT_ALPHA ? CAIRO_FORMAT_A8 : CAIRO_FORMAT_ARGB32,
+ width * sx, height * sy);
+ cairo_surface_set_device_scale (surface, sx, sy);
+ }
+ else
+ {
+ surface = cairo_surface_create_similar (window_surface,
+ content,
+ width, height);
+ }
+
+ cairo_surface_destroy (window_surface);
+
+ return surface;
+}
+
+
+/**
+ * gdk_surface_create_similar_image_surface:
+ * @window: (nullable): window to make new surface similar to, or
+ * %NULL if none
+ * @format: (type int): the format for the new surface
+ * @width: width of the new surface
+ * @height: height of the new surface
+ * @scale: the scale of the new surface, or 0 to use same as @window
+ *
+ * Create a new image surface that is efficient to draw on the
+ * given @window.
+ *
+ * Initially the surface contents are all 0 (transparent if contents
+ * have transparency, black otherwise.)
+ *
+ * The @width and @height of the new surface are not affected by
+ * the scaling factor of the @window, or by the @scale argument; they
+ * are the size of the surface in device pixels. If you wish to create
+ * an image surface capable of holding the contents of @window you can
+ * use:
+ *
+ * |[<!-- language="C" -->
+ * int scale = gdk_surface_get_scale_factor (window);
+ * int width = gdk_surface_get_width (window) * scale;
+ * int height = gdk_surface_get_height (window) * scale;
+ *
+ * // format is set elsewhere
+ * cairo_surface_t *surface =
+ * gdk_surface_create_similar_image_surface (window,
+ * format,
+ * width, height,
+ * scale);
+ * ]|
+ *
+ * Note that unlike cairo_surface_create_similar_image(), the new
+ * surface's device scale is set to @scale, or to the scale factor of
+ * @window if @scale is 0.
+ *
+ * Returns: a pointer to the newly allocated surface. The caller
+ * owns the surface and should call cairo_surface_destroy() when done
+ * with it.
+ *
+ * This function always returns a valid pointer, but it will return a
+ * pointer to a “nil” surface if @other is already in an error state
+ * or any other error occurs.
+ **/
+cairo_surface_t *
+gdk_surface_create_similar_image_surface (GdkSurface * window,
+ cairo_format_t format,
+ int width,
+ int height,
+ int scale)
+{
+ cairo_surface_t *surface;
+
+ g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), NULL);
+
+ if (window == NULL)
+ {
+ surface = cairo_image_surface_create (format, width, height);
+ }
+ else if (GDK_SURFACE_IMPL_GET_CLASS (window->impl)->create_similar_image_surface)
+ {
+ surface =
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->create_similar_image_surface (window, format, width, height);
+ }
+ else
+ {
+ cairo_surface_t *window_surface;
+
+ window_surface = gdk_surface_ref_impl_surface (window);
+ surface =
+ cairo_surface_create_similar_image (window_surface,
+ format,
+ width,
+ height);
+ cairo_surface_destroy (window_surface);
+ }
+
+ if (scale == 0)
+ scale = gdk_surface_get_scale_factor (window);
+
+ cairo_surface_set_device_scale (surface, scale, scale);
+
+ return surface;
+}
+
+
+/**
+ * gdk_surface_focus:
+ * @window: a #GdkSurface
+ * @timestamp: timestamp of the event triggering the window focus
+ *
+ * Sets keyboard focus to @window. In most cases, gtk_window_present()
+ * should be used on a #GtkWindow, rather than calling this function.
+ *
+ **/
+void
+gdk_surface_focus (GdkSurface *window,
+ guint32 timestamp)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->focus (window, timestamp);
+}
+
+/**
+ * gdk_surface_set_type_hint:
+ * @window: A toplevel #GdkSurface
+ * @hint: A hint of the function this window will have
+ *
+ * The application can use this call to provide a hint to the window
+ * manager about the functionality of a window. The window manager
+ * can use this information when determining the decoration and behaviour
+ * of the window.
+ *
+ * The hint must be set before the window is mapped.
+ **/
+void
+gdk_surface_set_type_hint (GdkSurface *window,
+ GdkSurfaceTypeHint hint)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_type_hint (window, hint);
+}
+
+/**
+ * gdk_surface_get_type_hint:
+ * @window: A toplevel #GdkSurface
+ *
+ * This function returns the type hint set for a window.
+ *
+ * Returns: The type hint set for @window
+ **/
+GdkSurfaceTypeHint
+gdk_surface_get_type_hint (GdkSurface *window)
+{
+ return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->get_type_hint (window);
+}
+
+/**
+ * gdk_surface_set_modal_hint:
+ * @window: A toplevel #GdkSurface
+ * @modal: %TRUE if the window is modal, %FALSE otherwise.
+ *
+ * The application can use this hint to tell the window manager
+ * that a certain window has modal behaviour. The window manager
+ * can use this information to handle modal windows in a special
+ * way.
+ *
+ * You should only use this on windows for which you have
+ * previously called gdk_surface_set_transient_for()
+ **/
+void
+gdk_surface_set_modal_hint (GdkSurface *window,
+ gboolean modal)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_modal_hint (window, modal);
+}
+
+/**
+ * gdk_surface_set_skip_taskbar_hint:
+ * @window: a toplevel #GdkSurface
+ * @skips_taskbar: %TRUE to skip the taskbar
+ *
+ * Toggles whether a window should appear in a task list or window
+ * list. If a window’s semantic type as specified with
+ * gdk_surface_set_type_hint() already fully describes the window, this
+ * function should not be called in addition,
+ * instead you should allow the window to be treated according to
+ * standard policy for its semantic type.
+ **/
+void
+gdk_surface_set_skip_taskbar_hint (GdkSurface *window,
+ gboolean skips_taskbar)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_skip_taskbar_hint (window, skips_taskbar);
+}
+
+/**
+ * gdk_surface_set_skip_pager_hint:
+ * @window: a toplevel #GdkSurface
+ * @skips_pager: %TRUE to skip the pager
+ *
+ * Toggles whether a window should appear in a pager (workspace
+ * switcher, or other desktop utility program that displays a small
+ * thumbnail representation of the windows on the desktop). If a
+ * window’s semantic type as specified with gdk_surface_set_type_hint()
+ * already fully describes the window, this function should
+ * not be called in addition, instead you should
+ * allow the window to be treated according to standard policy for
+ * its semantic type.
+ **/
+void
+gdk_surface_set_skip_pager_hint (GdkSurface *window,
+ gboolean skips_pager)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_skip_pager_hint (window, skips_pager);
+}
+
+/**
+ * gdk_surface_set_urgency_hint:
+ * @window: a toplevel #GdkSurface
+ * @urgent: %TRUE if the window is urgent
+ *
+ * Toggles whether a window needs the user's
+ * urgent attention.
+ **/
+void
+gdk_surface_set_urgency_hint (GdkSurface *window,
+ gboolean urgent)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_urgency_hint (window, urgent);
+}
+
+/**
+ * gdk_surface_set_geometry_hints:
+ * @window: a toplevel #GdkSurface
+ * @geometry: geometry hints
+ * @geom_mask: bitmask indicating fields of @geometry to pay attention to
+ *
+ * Sets the geometry hints for @window. Hints flagged in @geom_mask
+ * are set, hints not flagged in @geom_mask are unset.
+ * To unset all hints, use a @geom_mask of 0 and a @geometry of %NULL.
+ *
+ * This function provides hints to the windowing system about
+ * acceptable sizes for a toplevel window. The purpose of
+ * this is to constrain user resizing, but the windowing system
+ * will typically (but is not required to) also constrain the
+ * current size of the window to the provided values and
+ * constrain programatic resizing via gdk_surface_resize() or
+ * gdk_surface_move_resize().
+ *
+ * Note that on X11, this effect has no effect on windows
+ * of type %GDK_SURFACE_TEMP since these windows are not resizable
+ * by the user.
+ *
+ * Since you can’t count on the windowing system doing the
+ * constraints for programmatic resizes, you should generally
+ * call gdk_surface_constrain_size() yourself to determine
+ * appropriate sizes.
+ *
+ **/
+void
+gdk_surface_set_geometry_hints (GdkSurface *window,
+ const GdkGeometry *geometry,
+ GdkSurfaceHints geom_mask)
+{
+ g_return_if_fail (geometry != NULL || geom_mask == 0);
+
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_geometry_hints (window, geometry, geom_mask);
+}
+
+/**
+ * gdk_surface_set_title:
+ * @window: a toplevel #GdkSurface
+ * @title: title of @window
+ *
+ * Sets the title of a toplevel window, to be displayed in the titlebar.
+ * If you haven’t explicitly set the icon name for the window
+ * (using gdk_surface_set_icon_name()), the icon name will be set to
+ * @title as well. @title must be in UTF-8 encoding (as with all
+ * user-readable strings in GDK/GTK+). @title may not be %NULL.
+ **/
+void
+gdk_surface_set_title (GdkSurface *window,
+ const gchar *title)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_title (window, title);
+}
+
+/**
+ * gdk_surface_set_role:
+ * @window: a toplevel #GdkSurface
+ * @role: a string indicating its role
+ *
+ * When using GTK+, typically you should use gtk_window_set_role() instead
+ * of this low-level function.
+ *
+ * The window manager and session manager use a window’s role to
+ * distinguish it from other kinds of window in the same application.
+ * When an application is restarted after being saved in a previous
+ * session, all windows with the same title and role are treated as
+ * interchangeable. So if you have two windows with the same title
+ * that should be distinguished for session management purposes, you
+ * should set the role on those windows. It doesn’t matter what string
+ * you use for the role, as long as you have a different role for each
+ * non-interchangeable kind of window.
+ *
+ **/
+void
+gdk_surface_set_role (GdkSurface *window,
+ const gchar *role)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_role (window, role);
+}
+
+/**
+ * gdk_surface_set_startup_id:
+ * @window: a toplevel #GdkSurface
+ * @startup_id: a string with startup-notification identifier
+ *
+ * When using GTK+, typically you should use gtk_window_set_startup_id()
+ * instead of this low-level function.
+ **/
+void
+gdk_surface_set_startup_id (GdkSurface *window,
+ const gchar *startup_id)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_startup_id (window, startup_id);
+}
+
+/**
+ * gdk_surface_set_transient_for:
+ * @window: a toplevel #GdkSurface
+ * @parent: another toplevel #GdkSurface
+ *
+ * Indicates to the window manager that @window is a transient dialog
+ * associated with the application window @parent. This allows the
+ * window manager to do things like center @window on @parent and
+ * keep @window above @parent.
+ *
+ * See gtk_window_set_transient_for() if you’re using #GtkWindow or
+ * #GtkDialog.
+ **/
+void
+gdk_surface_set_transient_for (GdkSurface *window,
+ GdkSurface *parent)
+{
+ window->transient_for = parent;
+
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_transient_for (window, parent);
+}
+
+/**
+ * gdk_surface_get_root_origin:
+ * @window: a toplevel #GdkSurface
+ * @x: (out): return location for X position of window frame
+ * @y: (out): return location for Y position of window frame
+ *
+ * Obtains the top-left corner of the window manager frame in root
+ * window coordinates.
+ *
+ **/
+void
+gdk_surface_get_root_origin (GdkSurface *window,
+ gint *x,
+ gint *y)
+{
+ GdkRectangle rect;
+
+ gdk_surface_get_frame_extents (window, &rect);
+
+ if (x)
+ *x = rect.x;
+
+ if (y)
+ *y = rect.y;
+}
+
+/**
+ * gdk_surface_get_frame_extents:
+ * @window: a toplevel #GdkSurface
+ * @rect: (out): rectangle to fill with bounding box of the window frame
+ *
+ * Obtains the bounding box of the window, including window manager
+ * titlebar/borders if any. The frame position is given in root window
+ * coordinates. To get the position of the window itself (rather than
+ * the frame) in root window coordinates, use gdk_surface_get_origin().
+ *
+ **/
+void
+gdk_surface_get_frame_extents (GdkSurface *window,
+ GdkRectangle *rect)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->get_frame_extents (window, rect);
+}
+
+/**
+ * gdk_surface_set_accept_focus:
+ * @window: a toplevel #GdkSurface
+ * @accept_focus: %TRUE if the window should receive input focus
+ *
+ * Setting @accept_focus to %FALSE hints the desktop environment that the
+ * window doesn’t want to receive input focus.
+ *
+ * On X, it is the responsibility of the window manager to interpret this
+ * hint. ICCCM-compliant window manager usually respect it.
+ **/
+void
+gdk_surface_set_accept_focus (GdkSurface *window,
+ gboolean accept_focus)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_accept_focus (window, accept_focus);
+}
+
+/**
+ * gdk_surface_set_focus_on_map:
+ * @window: a toplevel #GdkSurface
+ * @focus_on_map: %TRUE if the window should receive input focus when mapped
+ *
+ * Setting @focus_on_map to %FALSE hints the desktop environment that the
+ * window doesn’t want to receive input focus when it is mapped.
+ * focus_on_map should be turned off for windows that aren’t triggered
+ * interactively (such as popups from network activity).
+ *
+ * On X, it is the responsibility of the window manager to interpret
+ * this hint. Window managers following the freedesktop.org window
+ * manager extension specification should respect it.
+ **/
+void
+gdk_surface_set_focus_on_map (GdkSurface *window,
+ gboolean focus_on_map)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_focus_on_map (window, focus_on_map);
+}
+
+/**
+ * gdk_surface_set_icon_list:
+ * @window: The #GdkSurface toplevel window to set the icon of.
+ * @surfaces: (transfer none) (element-type GdkTexture):
+ * A list of image surfaces, of different sizes.
+ *
+ * Sets a list of icons for the window. One of these will be used
+ * to represent the window when it has been iconified. The icon is
+ * usually shown in an icon box or some sort of task bar. Which icon
+ * size is shown depends on the window manager. The window manager
+ * can scale the icon but setting several size icons can give better
+ * image quality since the window manager may only need to scale the
+ * icon by a small amount or not at all.
+ *
+ * Note that some platforms don't support window icons.
+ */
+void
+gdk_surface_set_icon_list (GdkSurface *window,
+ GList *textures)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_icon_list (window, textures);
+}
+
+/**
+ * gdk_surface_set_icon_name:
+ * @window: a toplevel #GdkSurface
+ * @name: (allow-none): name of window while iconified (minimized)
+ *
+ * Windows may have a name used while minimized, distinct from the
+ * name they display in their titlebar. Most of the time this is a bad
+ * idea from a user interface standpoint. But you can set such a name
+ * with this function, if you like.
+ *
+ * After calling this with a non-%NULL @name, calls to gdk_surface_set_title()
+ * will not update the icon title.
+ *
+ * Using %NULL for @name unsets the icon title; further calls to
+ * gdk_surface_set_title() will again update the icon title as well.
+ *
+ * Note that some platforms don't support window icons.
+ **/
+void
+gdk_surface_set_icon_name (GdkSurface *window,
+ const gchar *name)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_icon_name (window, name);
+}
+
+/**
+ * gdk_surface_iconify:
+ * @window: a toplevel #GdkSurface
+ *
+ * Asks to iconify (minimize) @window. The window manager may choose
+ * to ignore the request, but normally will honor it. Using
+ * gtk_window_iconify() is preferred, if you have a #GtkWindow widget.
+ *
+ * This function only makes sense when @window is a toplevel window.
+ *
+ **/
+void
+gdk_surface_iconify (GdkSurface *window)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->iconify (window);
+}
+
+/**
+ * gdk_surface_deiconify:
+ * @window: a toplevel #GdkSurface
+ *
+ * Attempt to deiconify (unminimize) @window. On X11 the window manager may
+ * choose to ignore the request to deiconify. When using GTK+,
+ * use gtk_window_deiconify() instead of the #GdkSurface variant. Or better yet,
+ * you probably want to use gtk_window_present(), which raises the window, focuses it,
+ * unminimizes it, and puts it on the current desktop.
+ *
+ **/
+void
+gdk_surface_deiconify (GdkSurface *window)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->deiconify (window);
+}
+
+/**
+ * gdk_surface_stick:
+ * @window: a toplevel #GdkSurface
+ *
+ * “Pins” a window such that it’s on all workspaces and does not scroll
+ * with viewports, for window managers that have scrollable viewports.
+ * (When using #GtkWindow, gtk_window_stick() may be more useful.)
+ *
+ * On the X11 platform, this function depends on window manager
+ * support, so may have no effect with many window managers. However,
+ * GDK will do the best it can to convince the window manager to stick
+ * the window. For window managers that don’t support this operation,
+ * there’s nothing you can do to force it to happen.
+ *
+ **/
+void
+gdk_surface_stick (GdkSurface *window)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->stick (window);
+}
+
+/**
+ * gdk_surface_unstick:
+ * @window: a toplevel #GdkSurface
+ *
+ * Reverse operation for gdk_surface_stick(); see gdk_surface_stick(),
+ * and gtk_window_unstick().
+ *
+ **/
+void
+gdk_surface_unstick (GdkSurface *window)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->unstick (window);
+}
+
+/**
+ * gdk_surface_maximize:
+ * @window: a toplevel #GdkSurface
+ *
+ * Maximizes the window. If the window was already maximized, then
+ * this function does nothing.
+ *
+ * On X11, asks the window manager to maximize @window, if the window
+ * manager supports this operation. Not all window managers support
+ * this, and some deliberately ignore it or don’t have a concept of
+ * “maximized”; so you can’t rely on the maximization actually
+ * happening. But it will happen with most standard window managers,
+ * and GDK makes a best effort to get it to happen.
+ *
+ * On Windows, reliably maximizes the window.
+ *
+ **/
+void
+gdk_surface_maximize (GdkSurface *window)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->maximize (window);
+}
+
+/**
+ * gdk_surface_unmaximize:
+ * @window: a toplevel #GdkSurface
+ *
+ * Unmaximizes the window. If the window wasn’t maximized, then this
+ * function does nothing.
+ *
+ * On X11, asks the window manager to unmaximize @window, if the
+ * window manager supports this operation. Not all window managers
+ * support this, and some deliberately ignore it or don’t have a
+ * concept of “maximized”; so you can’t rely on the unmaximization
+ * actually happening. But it will happen with most standard window
+ * managers, and GDK makes a best effort to get it to happen.
+ *
+ * On Windows, reliably unmaximizes the window.
+ *
+ **/
+void
+gdk_surface_unmaximize (GdkSurface *window)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->unmaximize (window);
+}
+
+/**
+ * gdk_surface_fullscreen:
+ * @window: a toplevel #GdkSurface
+ *
+ * Moves the window into fullscreen mode. This means the
+ * window covers the entire screen and is above any panels
+ * or task bars.
+ *
+ * If the window was already fullscreen, then this function does nothing.
+ *
+ * On X11, asks the window manager to put @window in a fullscreen
+ * state, if the window manager supports this operation. Not all
+ * window managers support this, and some deliberately ignore it or
+ * don’t have a concept of “fullscreen”; so you can’t rely on the
+ * fullscreenification actually happening. But it will happen with
+ * most standard window managers, and GDK makes a best effort to get
+ * it to happen.
+ **/
+void
+gdk_surface_fullscreen (GdkSurface *window)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->fullscreen (window);
+}
+
+/**
+ * gdk_surface_fullscreen_on_monitor:
+ * @window: a toplevel #GdkSurface
+ * @monitor: Which monitor to display fullscreen on.
+ *
+ * Moves the window into fullscreen mode on the given monitor. This means
+ * the window covers the entire screen and is above any panels or task bars.
+ *
+ * If the window was already fullscreen, then this function does nothing.
+ **/
+void
+gdk_surface_fullscreen_on_monitor (GdkSurface *window,
+ GdkMonitor *monitor)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (GDK_IS_MONITOR (monitor));
+ g_return_if_fail (gdk_monitor_get_display (monitor) == gdk_surface_get_display (window));
+ g_return_if_fail (gdk_monitor_is_valid (monitor));
+
+ if (GDK_SURFACE_IMPL_GET_CLASS (window->impl)->fullscreen_on_monitor != NULL)
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->fullscreen_on_monitor (window, monitor);
+ else
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->fullscreen (window);
+}
+
+/**
+ * gdk_surface_set_fullscreen_mode:
+ * @window: a toplevel #GdkSurface
+ * @mode: fullscreen mode
+ *
+ * Specifies whether the @window should span over all monitors (in a multi-head
+ * setup) or only the current monitor when in fullscreen mode.
+ *
+ * The @mode argument is from the #GdkFullscreenMode enumeration.
+ * If #GDK_FULLSCREEN_ON_ALL_MONITORS is specified, the fullscreen @window will
+ * span over all monitors of the display.
+ *
+ * On X11, searches through the list of monitors display the ones
+ * which delimit the 4 edges of the entire display and will ask the window
+ * manager to span the @window over these monitors.
+ *
+ * If the XINERAMA extension is not available or not usable, this function
+ * has no effect.
+ *
+ * Not all window managers support this, so you can’t rely on the fullscreen
+ * window to span over the multiple monitors when #GDK_FULLSCREEN_ON_ALL_MONITORS
+ * is specified.
+ **/
+void
+gdk_surface_set_fullscreen_mode (GdkSurface *window,
+ GdkFullscreenMode mode)
+{
+ GdkSurfaceImplClass *impl_class;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->fullscreen_mode != mode)
+ {
+ window->fullscreen_mode = mode;
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+ if (impl_class->apply_fullscreen_mode != NULL)
+ impl_class->apply_fullscreen_mode (window);
+ }
+}
+
+/**
+ * gdk_surface_get_fullscreen_mode:
+ * @window: a toplevel #GdkSurface
+ *
+ * Obtains the #GdkFullscreenMode of the @window.
+ *
+ * Returns: The #GdkFullscreenMode applied to the window when fullscreen.
+ **/
+GdkFullscreenMode
+gdk_surface_get_fullscreen_mode (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), GDK_FULLSCREEN_ON_CURRENT_MONITOR);
+
+ return window->fullscreen_mode;
+}
+
+/**
+ * gdk_surface_unfullscreen:
+ * @window: a toplevel #GdkSurface
+ *
+ * Moves the window out of fullscreen mode. If the window was not
+ * fullscreen, does nothing.
+ *
+ * On X11, asks the window manager to move @window out of the fullscreen
+ * state, if the window manager supports this operation. Not all
+ * window managers support this, and some deliberately ignore it or
+ * don’t have a concept of “fullscreen”; so you can’t rely on the
+ * unfullscreenification actually happening. But it will happen with
+ * most standard window managers, and GDK makes a best effort to get
+ * it to happen.
+ **/
+void
+gdk_surface_unfullscreen (GdkSurface *window)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->unfullscreen (window);
+}
+
+/**
+ * gdk_surface_set_keep_above:
+ * @window: a toplevel #GdkSurface
+ * @setting: whether to keep @window above other windows
+ *
+ * Set if @window must be kept above other windows. If the
+ * window was already above, then this function does nothing.
+ *
+ * On X11, asks the window manager to keep @window above, if the window
+ * manager supports this operation. Not all window managers support
+ * this, and some deliberately ignore it or don’t have a concept of
+ * “keep above”; so you can’t rely on the window being kept above.
+ * But it will happen with most standard window managers,
+ * and GDK makes a best effort to get it to happen.
+ **/
+void
+gdk_surface_set_keep_above (GdkSurface *window,
+ gboolean setting)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_keep_above (window, setting);
+}
+
+/**
+ * gdk_surface_set_keep_below:
+ * @window: a toplevel #GdkSurface
+ * @setting: whether to keep @window below other windows
+ *
+ * Set if @window must be kept below other windows. If the
+ * window was already below, then this function does nothing.
+ *
+ * On X11, asks the window manager to keep @window below, if the window
+ * manager supports this operation. Not all window managers support
+ * this, and some deliberately ignore it or don’t have a concept of
+ * “keep below”; so you can’t rely on the window being kept below.
+ * But it will happen with most standard window managers,
+ * and GDK makes a best effort to get it to happen.
+ **/
+void
+gdk_surface_set_keep_below (GdkSurface *window, gboolean setting)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_keep_below (window, setting);
+}
+
+/**
+ * gdk_surface_get_group:
+ * @window: a toplevel #GdkSurface
+ *
+ * Returns the group leader window for @window. See gdk_surface_set_group().
+ *
+ * Returns: (transfer none): the group leader window for @window
+ **/
+GdkSurface *
+gdk_surface_get_group (GdkSurface *window)
+{
+ return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->get_group (window);
+}
+
+/**
+ * gdk_surface_set_group:
+ * @window: a toplevel #GdkSurface
+ * @leader: (allow-none): group leader window, or %NULL to restore the default group leader window
+ *
+ * Sets the group leader window for @window. By default,
+ * GDK sets the group leader for all toplevel windows
+ * to a global window implicitly created by GDK. With this function
+ * you can override this default.
+ *
+ * The group leader window allows the window manager to distinguish
+ * all windows that belong to a single application. It may for example
+ * allow users to minimize/unminimize all windows belonging to an
+ * application at once. You should only set a non-default group window
+ * if your application pretends to be multiple applications.
+ **/
+void
+gdk_surface_set_group (GdkSurface *window,
+ GdkSurface *leader)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_group (window, leader);
+}
+
+/**
+ * gdk_surface_set_decorations:
+ * @window: a toplevel #GdkSurface
+ * @decorations: decoration hint mask
+ *
+ * “Decorations” are the features the window manager adds to a toplevel #GdkSurface.
+ * This function sets the traditional Motif window manager hints that tell the
+ * window manager which decorations you would like your window to have.
+ * Usually you should use gtk_window_set_decorated() on a #GtkWindow instead of
+ * using the GDK function directly.
+ *
+ * The @decorations argument is the logical OR of the fields in
+ * the #GdkWMDecoration enumeration. If #GDK_DECOR_ALL is included in the
+ * mask, the other bits indicate which decorations should be turned off.
+ * If #GDK_DECOR_ALL is not included, then the other bits indicate
+ * which decorations should be turned on.
+ *
+ * Most window managers honor a decorations hint of 0 to disable all decorations,
+ * but very few honor all possible combinations of bits.
+ *
+ **/
+void
+gdk_surface_set_decorations (GdkSurface *window,
+ GdkWMDecoration decorations)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_decorations (window, decorations);
+}
+
+/**
+ * gdk_surface_get_decorations:
+ * @window: The toplevel #GdkSurface to get the decorations from
+ * @decorations: (out): The window decorations will be written here
+ *
+ * Returns the decorations set on the GdkSurface with
+ * gdk_surface_set_decorations().
+ *
+ * Returns: %TRUE if the window has decorations set, %FALSE otherwise.
+ **/
+gboolean
+gdk_surface_get_decorations(GdkSurface *window,
+ GdkWMDecoration *decorations)
+{
+ return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->get_decorations (window, decorations);
+}
+
+/**
+ * gdk_surface_set_functions:
+ * @window: a toplevel #GdkSurface
+ * @functions: bitmask of operations to allow on @window
+ *
+ * Sets hints about the window management functions to make available
+ * via buttons on the window frame.
+ *
+ * On the X backend, this function sets the traditional Motif window
+ * manager hint for this purpose. However, few window managers do
+ * anything reliable or interesting with this hint. Many ignore it
+ * entirely.
+ *
+ * The @functions argument is the logical OR of values from the
+ * #GdkWMFunction enumeration. If the bitmask includes #GDK_FUNC_ALL,
+ * then the other bits indicate which functions to disable; if
+ * it doesn’t include #GDK_FUNC_ALL, it indicates which functions to
+ * enable.
+ *
+ **/
+void
+gdk_surface_set_functions (GdkSurface *window,
+ GdkWMFunction functions)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_functions (window, functions);
+}
+
+/**
+ * gdk_surface_begin_resize_drag_for_device:
+ * @window: a toplevel #GdkSurface
+ * @edge: the edge or corner from which the drag is started
+ * @device: the device used for the operation
+ * @button: the button being used to drag, or 0 for a keyboard-initiated drag
+ * @root_x: root window X coordinate of mouse click that began the drag
+ * @root_y: root window Y coordinate of mouse click that began the drag
+ * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
+ *
+ * Begins a window resize operation (for a toplevel window).
+ * You might use this function to implement a “window resize grip,” for
+ * example; in fact #GtkStatusbar uses it. The function works best
+ * with window managers that support the
+ * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec)
+ * but has a fallback implementation for other window managers.
+ */
+void
+gdk_surface_begin_resize_drag_for_device (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->begin_resize_drag (window, edge, device, button, root_x, root_y, timestamp);
+}
+
+/**
+ * gdk_surface_begin_resize_drag:
+ * @window: a toplevel #GdkSurface
+ * @edge: the edge or corner from which the drag is started
+ * @button: the button being used to drag, or 0 for a keyboard-initiated drag
+ * @root_x: root window X coordinate of mouse click that began the drag
+ * @root_y: root window Y coordinate of mouse click that began the drag
+ * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
+ *
+ * Begins a window resize operation (for a toplevel window).
+ *
+ * This function assumes that the drag is controlled by the
+ * client pointer device, use gdk_surface_begin_resize_drag_for_device()
+ * to begin a drag with a different device.
+ */
+void
+gdk_surface_begin_resize_drag (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GdkDisplay *display;
+ GdkDevice *device;
+
+ display = gdk_surface_get_display (window);
+ device = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
+ gdk_surface_begin_resize_drag_for_device (window, edge,
+ device, button, root_x, root_y, timestamp);
+}
+
+/**
+ * gdk_surface_begin_move_drag_for_device:
+ * @window: a toplevel #GdkSurface
+ * @device: the device used for the operation
+ * @button: the button being used to drag, or 0 for a keyboard-initiated drag
+ * @root_x: root window X coordinate of mouse click that began the drag
+ * @root_y: root window Y coordinate of mouse click that began the drag
+ * @timestamp: timestamp of mouse click that began the drag
+ *
+ * Begins a window move operation (for a toplevel window).
+ * You might use this function to implement a “window move grip,” for
+ * example. The function works best with window managers that support the
+ * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec)
+ * but has a fallback implementation for other window managers.
+ */
+void
+gdk_surface_begin_move_drag_for_device (GdkSurface *window,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->begin_move_drag (window,
+ device, button, root_x, root_y, timestamp);
+}
+
+/**
+ * gdk_surface_begin_move_drag:
+ * @window: a toplevel #GdkSurface
+ * @button: the button being used to drag, or 0 for a keyboard-initiated drag
+ * @root_x: root window X coordinate of mouse click that began the drag
+ * @root_y: root window Y coordinate of mouse click that began the drag
+ * @timestamp: timestamp of mouse click that began the drag
+ *
+ * Begins a window move operation (for a toplevel window).
+ *
+ * This function assumes that the drag is controlled by the
+ * client pointer device, use gdk_surface_begin_move_drag_for_device()
+ * to begin a drag with a different device.
+ */
+void
+gdk_surface_begin_move_drag (GdkSurface *window,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GdkDisplay *display;
+ GdkDevice *device;
+
+ display = gdk_surface_get_display (window);
+ device = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
+ gdk_surface_begin_move_drag_for_device (window, device, button, root_x, root_y, timestamp);
+}
+
+/**
+ * gdk_surface_set_opacity:
+ * @window: a top-level or non-native #GdkSurface
+ * @opacity: opacity
+ *
+ * Set @window to render as partially transparent,
+ * with opacity 0 being fully transparent and 1 fully opaque. (Values
+ * of the opacity parameter are clamped to the [0,1] range.)
+ *
+ * For toplevel windows this depends on support from the windowing system
+ * that may not always be there. For instance, On X11, this works only on
+ * X screens with a compositing manager running. On Wayland, there is no
+ * per-window opacity value that the compositor would apply. Instead, use
+ * `gdk_surface_set_opaque_region (window, NULL)` to tell the compositor
+ * that the entire window is (potentially) non-opaque, and draw your content
+ * with alpha, or use gtk_widget_set_opacity() to set an overall opacity
+ * for your widgets.
+ *
+ * Support for non-toplevel windows was added in 3.8.
+ */
+void
+gdk_surface_set_opacity (GdkSurface *window,
+ gdouble opacity)
+{
+ if (opacity < 0)
+ opacity = 0;
+ else if (opacity > 1)
+ opacity = 1;
+
+ window->alpha = round (opacity * 255);
+
+ if (window->destroyed)
+ return;
+
+ if (gdk_surface_has_impl (window))
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_opacity (window, opacity);
+ else
+ {
+ recompute_visible_regions (window, FALSE);
+ gdk_surface_invalidate_rect_full (window, NULL, TRUE);
+ }
+}
+
+/* This function is called when the XWindow is really gone.
+ */
+void
+gdk_surface_destroy_notify (GdkSurface *window)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->destroy_notify (window);
+}
+
+/**
+ * gdk_surface_register_dnd:
+ * @window: a #GdkSurface.
+ *
+ * Registers a window as a potential drop destination.
+ */
+void
+gdk_surface_register_dnd (GdkSurface *window)
+{
+ GDK_SURFACE_IMPL_GET_CLASS (window->impl)->register_dnd (window);
+}
+
+/**
+ * gdk_drag_begin:
+ * @window: the source window for this drag
+ * @device: the device that controls this drag
+ * @content: (transfer none): the offered content
+ * @actions: the actions supported by this drag
+ * @dx: the x offset to @device's position where the drag nominally started
+ * @dy: the y offset to @device's position where the drag nominally started
+ *
+ * Starts a drag and creates a new drag context for it.
+ *
+ * This function is called by the drag source.
+ *
+ * Returns: (transfer full) (nullable): a newly created #GdkDragContext or
+ * %NULL on error.
+ */
+GdkDragContext *
+gdk_drag_begin (GdkSurface *window,
+ GdkDevice *device,
+ GdkContentProvider *content,
+ GdkDragAction actions,
+ gint dx,
+ gint dy)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+ g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (gdk_surface_get_display (window) == gdk_device_get_display (device), NULL);
+ g_return_val_if_fail (GDK_IS_CONTENT_PROVIDER (content), NULL);
+
+ return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->drag_begin (window, device, content, actions, dx, dy);
+}
+
+static void
+gdk_surface_flush_events (GdkFrameClock *clock,
+ void *data)
+{
+ GdkSurface *window;
+ GdkDisplay *display;
+
+ window = GDK_SURFACE (data);
+
+ display = gdk_surface_get_display (window);
+ _gdk_event_queue_flush (display);
+ _gdk_display_pause_events (display);
+
+ gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS);
+
+ window->frame_clock_events_paused = TRUE;
+}
+
+static void
+gdk_surface_resume_events (GdkFrameClock *clock,
+ void *data)
+{
+ GdkSurface *window;
+ GdkDisplay *display;
+
+ window = GDK_SURFACE (data);
+
+ display = gdk_surface_get_display (window);
+ _gdk_display_unpause_events (display);
+
+ window->frame_clock_events_paused = FALSE;
+}
+
+static void
+gdk_surface_set_frame_clock (GdkSurface *window,
+ GdkFrameClock *clock)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (clock == NULL || GDK_IS_FRAME_CLOCK (clock));
+ g_return_if_fail (clock == NULL || gdk_surface_is_toplevel (window));
+
+ if (clock == window->frame_clock)
+ return;
+
+ if (clock)
+ {
+ g_object_ref (clock);
+ g_signal_connect (G_OBJECT (clock),
+ "flush-events",
+ G_CALLBACK (gdk_surface_flush_events),
+ window);
+ g_signal_connect (G_OBJECT (clock),
+ "paint",
+ G_CALLBACK (gdk_surface_paint_on_clock),
+ window);
+ g_signal_connect (G_OBJECT (clock),
+ "resume-events",
+ G_CALLBACK (gdk_surface_resume_events),
+ window);
+ }
+
+ if (window->frame_clock)
+ {
+ if (window->frame_clock_events_paused)
+ gdk_surface_resume_events (window->frame_clock, G_OBJECT (window));
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
+ G_CALLBACK (gdk_surface_flush_events),
+ window);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
+ G_CALLBACK (gdk_surface_paint_on_clock),
+ window);
+ g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
+ G_CALLBACK (gdk_surface_resume_events),
+ window);
+ g_object_unref (window->frame_clock);
+ }
+
+ window->frame_clock = clock;
+}
+
+/**
+ * gdk_surface_get_frame_clock:
+ * @window: window to get frame clock for
+ *
+ * Gets the frame clock for the window. The frame clock for a window
+ * never changes unless the window is reparented to a new toplevel
+ * window.
+ *
+ * Returns: (transfer none): the frame clock
+ */
+GdkFrameClock*
+gdk_surface_get_frame_clock (GdkSurface *window)
+{
+ GdkSurface *toplevel;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ toplevel = gdk_surface_get_toplevel (window);
+
+ return toplevel->frame_clock;
+}
+
+/**
+ * gdk_surface_get_scale_factor:
+ * @window: window to get scale factor for
+ *
+ * Returns the internal scale factor that maps from window coordiantes
+ * to the actual device pixels. On traditional systems this is 1, but
+ * on very high density outputs this can be a higher value (often 2).
+ *
+ * A higher value means that drawing is automatically scaled up to
+ * a higher resolution, so any code doing drawing will automatically look
+ * nicer. However, if you are supplying pixel-based data the scale
+ * value can be used to determine whether to use a pixel resource
+ * with higher resolution data.
+ *
+ * The scale of a window may change during runtime, if this happens
+ * a configure event will be sent to the toplevel window.
+ *
+ * Returns: the scale factor
+ */
+gint
+gdk_surface_get_scale_factor (GdkSurface *window)
+{
+ GdkSurfaceImplClass *impl_class;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), 1);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return 1;
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ if (impl_class->get_scale_factor)
+ return impl_class->get_scale_factor (window);
+
+ return 1;
+}
+
+/* Returns the *real* unscaled size, which may be a fractional size
+ in window scale coordinates. We need this to properly handle GL
+ coordinates which are y-flipped in the real coordinates. */
+void
+gdk_surface_get_unscaled_size (GdkSurface *window,
+ int *unscaled_width,
+ int *unscaled_height)
+{
+ GdkSurfaceImplClass *impl_class;
+ gint scale;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->impl_window == window)
+ {
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ if (impl_class->get_unscaled_size)
+ {
+ impl_class->get_unscaled_size (window, unscaled_width, unscaled_height);
+ return;
+ }
+ }
+
+ scale = gdk_surface_get_scale_factor (window);
+
+ if (unscaled_width)
+ *unscaled_width = window->width * scale;
+
+ if (unscaled_height)
+ *unscaled_height = window->height * scale;
+}
+
+
+/**
+ * gdk_surface_set_opaque_region:
+ * @window: a top-level or non-native #GdkSurface
+ * @region: (allow-none): a region, or %NULL
+ *
+ * For optimisation purposes, compositing window managers may
+ * like to not draw obscured regions of windows, or turn off blending
+ * during for these regions. With RGB windows with no transparency,
+ * this is just the shape of the window, but with ARGB32 windows, the
+ * compositor does not know what regions of the window are transparent
+ * or not.
+ *
+ * This function only works for toplevel windows.
+ *
+ * GTK+ will update this property automatically if
+ * the @window background is opaque, as we know where the opaque regions
+ * are. If your window background is not opaque, please update this
+ * property in your #GtkWidget::style-updated handler.
+ */
+void
+gdk_surface_set_opaque_region (GdkSurface *window,
+ cairo_region_t *region)
+{
+ GdkSurfaceImplClass *impl_class;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (!GDK_SURFACE_DESTROYED (window));
+
+ if (cairo_region_equal (window->opaque_region, region))
+ return;
+
+ g_clear_pointer (&window->opaque_region, cairo_region_destroy);
+
+ if (region != NULL)
+ window->opaque_region = cairo_region_reference (region);
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ if (impl_class->set_opaque_region)
+ impl_class->set_opaque_region (window, region);
+}
+
+/**
+ * gdk_surface_set_shadow_width:
+ * @window: a #GdkSurface
+ * @left: The left extent
+ * @right: The right extent
+ * @top: The top extent
+ * @bottom: The bottom extent
+ *
+ * Newer GTK+ windows using client-side decorations use extra geometry
+ * around their frames for effects like shadows and invisible borders.
+ * Window managers that want to maximize windows or snap to edges need
+ * to know where the extents of the actual frame lie, so that users
+ * don’t feel like windows are snapping against random invisible edges.
+ *
+ * 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.
+ */
+void
+gdk_surface_set_shadow_width (GdkSurface *window,
+ gint left,
+ gint right,
+ gint top,
+ gint bottom)
+{
+ GdkSurfaceImplClass *impl_class;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (!GDK_SURFACE_DESTROYED (window));
+ g_return_if_fail (left >= 0 && right >= 0 && top >= 0 && bottom >= 0);
+
+ window->shadow_top = top;
+ window->shadow_left = left;
+ window->shadow_right = right;
+ window->shadow_bottom = bottom;
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ if (impl_class->set_shadow_width)
+ impl_class->set_shadow_width (window, left, right, top, bottom);
+}
+
+/**
+ * gdk_surface_show_window_menu:
+ * @window: a #GdkSurface
+ * @event: a #GdkEvent to show the menu for
+ *
+ * Asks the windowing system to show the window menu. The window menu
+ * is the menu shown when right-clicking the titlebar on traditional
+ * windows managed by the window manager. This is useful for windows
+ * using client-side decorations, activating it with a right-click
+ * on the window decorations.
+ *
+ * Returns: %TRUE if the window menu was shown and %FALSE otherwise.
+ */
+gboolean
+gdk_surface_show_window_menu (GdkSurface *window,
+ GdkEvent *event)
+{
+ GdkSurfaceImplClass *impl_class;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+ g_return_val_if_fail (!GDK_SURFACE_DESTROYED (window), FALSE);
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ if (impl_class->show_window_menu)
+ return impl_class->show_window_menu (window, event);
+ else
+ return FALSE;
+}
+
+gboolean
+gdk_surface_supports_edge_constraints (GdkSurface *window)
+{
+ GdkSurfaceImplClass *impl_class;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+ g_return_val_if_fail (!GDK_SURFACE_DESTROYED (window), FALSE);
+
+ impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
+
+ if (impl_class->supports_edge_constraints)
+ return impl_class->supports_edge_constraints (window);
+ else
+ return FALSE;
+}
+
+void
+gdk_surface_set_state (GdkSurface *window,
+ GdkSurfaceState new_state)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (new_state == window->state)
+ return; /* No actual work to do, nothing changed. */
+
+ /* Actually update the field in GdkSurface, this is sort of an odd
+ * place to do it, but seems like the safest since it ensures we expose no
+ * inconsistent state to the user.
+ */
+
+ window->state = new_state;
+
+ _gdk_surface_update_viewable (window);
+
+ /* We only really send the event to toplevels, since
+ * all the window states don't apply to non-toplevels.
+ * Non-toplevels do use the GDK_SURFACE_STATE_WITHDRAWN flag
+ * internally so we needed to update window->state.
+ */
+ switch (window->window_type)
+ {
+ case GDK_SURFACE_TOPLEVEL:
+ case GDK_SURFACE_TEMP: /* ? */
+ g_object_notify (G_OBJECT (window), "state");
+ break;
+ case GDK_SURFACE_FOREIGN:
+ case GDK_SURFACE_ROOT:
+ case GDK_SURFACE_CHILD:
+ default:
+ break;
+ }
+}
+
+void
+gdk_synthesize_window_state (GdkSurface *window,
+ GdkSurfaceState unset_flags,
+ GdkSurfaceState set_flags)
+{
+ gdk_surface_set_state (window, (window->state | set_flags) & ~unset_flags);
+}
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GDK_SURFACE_H__
+#define __GDK_SURFACE_H__
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#include <gdk/gdkversionmacros.h>
+#include <gdk/gdktypes.h>
+#include <gdk/gdkdrawingcontext.h>
+#include <gdk/gdkevents.h>
+#include <gdk/gdkframeclock.h>
+#include <gdk/gdkmonitor.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkGeometry GdkGeometry;
+
+/**
+ * GdkSurfaceType:
+ * @GDK_SURFACE_ROOT: root window; this window has no parent, covers the entire
+ * screen, and is created by the window system
+ * @GDK_SURFACE_TOPLEVEL: toplevel window (used to implement #GtkWindow)
+ * @GDK_SURFACE_CHILD: child window (used to implement e.g. #GtkEntry)
+ * @GDK_SURFACE_TEMP: override redirect temporary window (used to implement
+ * #GtkMenu)
+ * @GDK_SURFACE_FOREIGN: foreign window (see gdk_surface_foreign_new())
+ * @GDK_SURFACE_SUBSURFACE: subsurface-based window; This window is visually
+ * tied to a toplevel, and is moved/stacked with it. Currently this window
+ * type is only implemented in Wayland. Since 3.14
+ *
+ * Describes the kind of window.
+ */
+typedef enum
+{
+ GDK_SURFACE_ROOT,
+ GDK_SURFACE_TOPLEVEL,
+ GDK_SURFACE_CHILD,
+ GDK_SURFACE_TEMP,
+ GDK_SURFACE_FOREIGN,
+ GDK_SURFACE_SUBSURFACE
+} GdkSurfaceType;
+
+/* Size restriction enumeration.
+ */
+/**
+ * GdkSurfaceHints:
+ * @GDK_HINT_POS: indicates that the program has positioned the window
+ * @GDK_HINT_MIN_SIZE: min size fields are set
+ * @GDK_HINT_MAX_SIZE: max size fields are set
+ * @GDK_HINT_BASE_SIZE: base size fields are set
+ * @GDK_HINT_ASPECT: aspect ratio fields are set
+ * @GDK_HINT_RESIZE_INC: resize increment fields are set
+ * @GDK_HINT_WIN_GRAVITY: window gravity field is set
+ * @GDK_HINT_USER_POS: indicates that the window’s position was explicitly set
+ * by the user
+ * @GDK_HINT_USER_SIZE: indicates that the window’s size was explicitly set by
+ * the user
+ *
+ * Used to indicate which fields of a #GdkGeometry struct should be paid
+ * attention to. Also, the presence/absence of @GDK_HINT_POS,
+ * @GDK_HINT_USER_POS, and @GDK_HINT_USER_SIZE is significant, though they don't
+ * directly refer to #GdkGeometry fields. @GDK_HINT_USER_POS will be set
+ * automatically by #GtkWindow if you call gtk_window_move().
+ * @GDK_HINT_USER_POS and @GDK_HINT_USER_SIZE should be set if the user
+ * specified a size/position using a --geometry command-line argument;
+ * gtk_window_parse_geometry() automatically sets these flags.
+ */
+typedef enum
+{
+ GDK_HINT_POS = 1 << 0,
+ GDK_HINT_MIN_SIZE = 1 << 1,
+ GDK_HINT_MAX_SIZE = 1 << 2,
+ GDK_HINT_BASE_SIZE = 1 << 3,
+ GDK_HINT_ASPECT = 1 << 4,
+ GDK_HINT_RESIZE_INC = 1 << 5,
+ GDK_HINT_WIN_GRAVITY = 1 << 6,
+ GDK_HINT_USER_POS = 1 << 7,
+ GDK_HINT_USER_SIZE = 1 << 8
+} GdkSurfaceHints;
+
+/* The next two enumeration values current match the
+ * Motif constants. If this is changed, the implementation
+ * of gdk_surface_set_decorations/gdk_surface_set_functions
+ * will need to change as well.
+ */
+/**
+ * GdkWMDecoration:
+ * @GDK_DECOR_ALL: all decorations should be applied.
+ * @GDK_DECOR_BORDER: a frame should be drawn around the window.
+ * @GDK_DECOR_RESIZEH: the frame should have resize handles.
+ * @GDK_DECOR_TITLE: a titlebar should be placed above the window.
+ * @GDK_DECOR_MENU: a button for opening a menu should be included.
+ * @GDK_DECOR_MINIMIZE: a minimize button should be included.
+ * @GDK_DECOR_MAXIMIZE: a maximize button should be included.
+ *
+ * These are hints originally defined by the Motif toolkit.
+ * The window manager can use them when determining how to decorate
+ * the window. The hint must be set before mapping the window.
+ */
+typedef enum
+{
+ GDK_DECOR_ALL = 1 << 0,
+ GDK_DECOR_BORDER = 1 << 1,
+ GDK_DECOR_RESIZEH = 1 << 2,
+ GDK_DECOR_TITLE = 1 << 3,
+ GDK_DECOR_MENU = 1 << 4,
+ GDK_DECOR_MINIMIZE = 1 << 5,
+ GDK_DECOR_MAXIMIZE = 1 << 6
+} GdkWMDecoration;
+
+/**
+ * GdkWMFunction:
+ * @GDK_FUNC_ALL: all functions should be offered.
+ * @GDK_FUNC_RESIZE: the window should be resizable.
+ * @GDK_FUNC_MOVE: the window should be movable.
+ * @GDK_FUNC_MINIMIZE: the window should be minimizable.
+ * @GDK_FUNC_MAXIMIZE: the window should be maximizable.
+ * @GDK_FUNC_CLOSE: the window should be closable.
+ *
+ * These are hints originally defined by the Motif toolkit. The window manager
+ * can use them when determining the functions to offer for the window. The
+ * hint must be set before mapping the window.
+ */
+typedef enum
+{
+ GDK_FUNC_ALL = 1 << 0,
+ GDK_FUNC_RESIZE = 1 << 1,
+ GDK_FUNC_MOVE = 1 << 2,
+ GDK_FUNC_MINIMIZE = 1 << 3,
+ GDK_FUNC_MAXIMIZE = 1 << 4,
+ GDK_FUNC_CLOSE = 1 << 5
+} GdkWMFunction;
+
+/* Currently, these are the same values numerically as in the
+ * X protocol. If you change that, gdksurface-x11.c/gdk_surface_set_geometry_hints()
+ * will need fixing.
+ */
+/**
+ * GdkGravity:
+ * @GDK_GRAVITY_NORTH_WEST: the reference point is at the top left corner.
+ * @GDK_GRAVITY_NORTH: the reference point is in the middle of the top edge.
+ * @GDK_GRAVITY_NORTH_EAST: the reference point is at the top right corner.
+ * @GDK_GRAVITY_WEST: the reference point is at the middle of the left edge.
+ * @GDK_GRAVITY_CENTER: the reference point is at the center of the window.
+ * @GDK_GRAVITY_EAST: the reference point is at the middle of the right edge.
+ * @GDK_GRAVITY_SOUTH_WEST: the reference point is at the lower left corner.
+ * @GDK_GRAVITY_SOUTH: the reference point is at the middle of the lower edge.
+ * @GDK_GRAVITY_SOUTH_EAST: the reference point is at the lower right corner.
+ * @GDK_GRAVITY_STATIC: the reference point is at the top left corner of the
+ * window itself, ignoring window manager decorations.
+ *
+ * Defines the reference point of a window and the meaning of coordinates
+ * passed to gtk_window_move(). See gtk_window_move() and the "implementation
+ * notes" section of the
+ * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec)
+ * specification for more details.
+ */
+typedef enum
+{
+ GDK_GRAVITY_NORTH_WEST = 1,
+ GDK_GRAVITY_NORTH,
+ GDK_GRAVITY_NORTH_EAST,
+ GDK_GRAVITY_WEST,
+ GDK_GRAVITY_CENTER,
+ GDK_GRAVITY_EAST,
+ GDK_GRAVITY_SOUTH_WEST,
+ GDK_GRAVITY_SOUTH,
+ GDK_GRAVITY_SOUTH_EAST,
+ GDK_GRAVITY_STATIC
+} GdkGravity;
+
+/**
+ * GdkAnchorHints:
+ * @GDK_ANCHOR_FLIP_X: allow flipping anchors horizontally
+ * @GDK_ANCHOR_FLIP_Y: allow flipping anchors vertically
+ * @GDK_ANCHOR_SLIDE_X: allow sliding window horizontally
+ * @GDK_ANCHOR_SLIDE_Y: allow sliding window vertically
+ * @GDK_ANCHOR_RESIZE_X: allow resizing window horizontally
+ * @GDK_ANCHOR_RESIZE_Y: allow resizing window vertically
+ * @GDK_ANCHOR_FLIP: allow flipping anchors on both axes
+ * @GDK_ANCHOR_SLIDE: allow sliding window on both axes
+ * @GDK_ANCHOR_RESIZE: allow resizing window on both axes
+ *
+ * Positioning hints for aligning a window relative to a rectangle.
+ *
+ * These hints determine how the window should be positioned in the case that
+ * the window would fall off-screen if placed in its ideal position.
+ *
+ * For example, %GDK_ANCHOR_FLIP_X will replace %GDK_GRAVITY_NORTH_WEST with
+ * %GDK_GRAVITY_NORTH_EAST and vice versa if the window extends beyond the left
+ * or right edges of the monitor.
+ *
+ * If %GDK_ANCHOR_SLIDE_X is set, the window can be shifted horizontally to fit
+ * on-screen. If %GDK_ANCHOR_RESIZE_X is set, the window can be shrunken
+ * horizontally to fit.
+ *
+ * In general, when multiple flags are set, flipping should take precedence over
+ * sliding, which should take precedence over resizing.
+ *
+ * Since: 3.22
+ * Stability: Unstable
+ */
+typedef enum
+{
+ GDK_ANCHOR_FLIP_X = 1 << 0,
+ GDK_ANCHOR_FLIP_Y = 1 << 1,
+ GDK_ANCHOR_SLIDE_X = 1 << 2,
+ GDK_ANCHOR_SLIDE_Y = 1 << 3,
+ GDK_ANCHOR_RESIZE_X = 1 << 4,
+ GDK_ANCHOR_RESIZE_Y = 1 << 5,
+ GDK_ANCHOR_FLIP = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_FLIP_Y,
+ GDK_ANCHOR_SLIDE = GDK_ANCHOR_SLIDE_X | GDK_ANCHOR_SLIDE_Y,
+ GDK_ANCHOR_RESIZE = GDK_ANCHOR_RESIZE_X | GDK_ANCHOR_RESIZE_Y
+} GdkAnchorHints;
+
+/**
+ * GdkSurfaceEdge:
+ * @GDK_SURFACE_EDGE_NORTH_WEST: the top left corner.
+ * @GDK_SURFACE_EDGE_NORTH: the top edge.
+ * @GDK_SURFACE_EDGE_NORTH_EAST: the top right corner.
+ * @GDK_SURFACE_EDGE_WEST: the left edge.
+ * @GDK_SURFACE_EDGE_EAST: the right edge.
+ * @GDK_SURFACE_EDGE_SOUTH_WEST: the lower left corner.
+ * @GDK_SURFACE_EDGE_SOUTH: the lower edge.
+ * @GDK_SURFACE_EDGE_SOUTH_EAST: the lower right corner.
+ *
+ * Determines a window edge or corner.
+ */
+typedef enum
+{
+ GDK_SURFACE_EDGE_NORTH_WEST,
+ GDK_SURFACE_EDGE_NORTH,
+ GDK_SURFACE_EDGE_NORTH_EAST,
+ GDK_SURFACE_EDGE_WEST,
+ GDK_SURFACE_EDGE_EAST,
+ GDK_SURFACE_EDGE_SOUTH_WEST,
+ GDK_SURFACE_EDGE_SOUTH,
+ GDK_SURFACE_EDGE_SOUTH_EAST
+} GdkSurfaceEdge;
+
+/**
+ * GdkFullscreenMode:
+ * @GDK_FULLSCREEN_ON_CURRENT_MONITOR: Fullscreen on current monitor only.
+ * @GDK_FULLSCREEN_ON_ALL_MONITORS: Span across all monitors when fullscreen.
+ *
+ * Indicates which monitor (in a multi-head setup) a window should span over
+ * when in fullscreen mode.
+ *
+ * Since: 3.8
+ **/
+typedef enum
+{
+ GDK_FULLSCREEN_ON_CURRENT_MONITOR,
+ GDK_FULLSCREEN_ON_ALL_MONITORS
+} GdkFullscreenMode;
+
+/**
+ * GdkGeometry:
+ * @min_width: minimum width of window (or -1 to use requisition, with
+ * #GtkWindow only)
+ * @min_height: minimum height of window (or -1 to use requisition, with
+ * #GtkWindow only)
+ * @max_width: maximum width of window (or -1 to use requisition, with
+ * #GtkWindow only)
+ * @max_height: maximum height of window (or -1 to use requisition, with
+ * #GtkWindow only)
+ * @base_width: allowed window widths are @base_width + @width_inc * N where N
+ * is any integer (-1 allowed with #GtkWindow)
+ * @base_height: allowed window widths are @base_height + @height_inc * N where
+ * N is any integer (-1 allowed with #GtkWindow)
+ * @width_inc: width resize increment
+ * @height_inc: height resize increment
+ * @min_aspect: minimum width/height ratio
+ * @max_aspect: maximum width/height ratio
+ * @win_gravity: window gravity, see gtk_window_set_gravity()
+ *
+ * The #GdkGeometry struct gives the window manager information about
+ * a window’s geometry constraints. Normally you would set these on
+ * the GTK+ level using gtk_window_set_geometry_hints(). #GtkWindow
+ * then sets the hints on the #GdkSurface it creates.
+ *
+ * gdk_surface_set_geometry_hints() expects the hints to be fully valid already
+ * and simply passes them to the window manager; in contrast,
+ * gtk_window_set_geometry_hints() performs some interpretation. For example,
+ * #GtkWindow will apply the hints to the geometry widget instead of the
+ * toplevel window, if you set a geometry widget. Also, the
+ * @min_width/@min_height/@max_width/@max_height fields may be set to -1, and
+ * #GtkWindow will substitute the size request of the window or geometry widget.
+ * If the minimum size hint is not provided, #GtkWindow will use its requisition
+ * as the minimum size. If the minimum size is provided and a geometry widget is
+ * set, #GtkWindow will take the minimum size as the minimum size of the
+ * geometry widget rather than the entire window. The base size is treated
+ * similarly.
+ *
+ * The canonical use-case for gtk_window_set_geometry_hints() is to get a
+ * terminal widget to resize properly. Here, the terminal text area should be
+ * the geometry widget; #GtkWindow will then automatically set the base size to
+ * the size of other widgets in the terminal window, such as the menubar and
+ * scrollbar. Then, the @width_inc and @height_inc fields should be set to the
+ * size of one character in the terminal. Finally, the base size should be set
+ * to the size of one character. The net effect is that the minimum size of the
+ * terminal will have a 1x1 character terminal area, and only terminal sizes on
+ * the “character grid” will be allowed.
+ *
+ * Here’s an example of how the terminal example would be implemented, assuming
+ * a terminal area widget called “terminal” and a toplevel window “toplevel”:
+ *
+ * |[<!-- language="C" -->
+ * GdkGeometry hints;
+ *
+ * hints.base_width = terminal->char_width;
+ * hints.base_height = terminal->char_height;
+ * hints.min_width = terminal->char_width;
+ * hints.min_height = terminal->char_height;
+ * hints.width_inc = terminal->char_width;
+ * hints.height_inc = terminal->char_height;
+ *
+ * gtk_window_set_geometry_hints (GTK_WINDOW (toplevel),
+ * GTK_WIDGET (terminal),
+ * &hints,
+ * GDK_HINT_RESIZE_INC |
+ * GDK_HINT_MIN_SIZE |
+ * GDK_HINT_BASE_SIZE);
+ * ]|
+ *
+ * The other useful fields are the @min_aspect and @max_aspect fields; these
+ * contain a width/height ratio as a floating point number. If a geometry widget
+ * is set, the aspect applies to the geometry widget rather than the entire
+ * window. The most common use of these hints is probably to set @min_aspect and
+ * @max_aspect to the same value, thus forcing the window to keep a constant
+ * aspect ratio.
+ */
+struct _GdkGeometry
+{
+ gint min_width;
+ gint min_height;
+ gint max_width;
+ gint max_height;
+ gint base_width;
+ gint base_height;
+ gint width_inc;
+ gint height_inc;
+ gdouble min_aspect;
+ gdouble max_aspect;
+ GdkGravity win_gravity;
+};
+
+/**
+ * GdkSurfaceState:
+ * @GDK_SURFACE_STATE_WITHDRAWN: the window is not shown.
+ * @GDK_SURFACE_STATE_ICONIFIED: the window is minimized.
+ * @GDK_SURFACE_STATE_MAXIMIZED: the window is maximized.
+ * @GDK_SURFACE_STATE_STICKY: the window is sticky.
+ * @GDK_SURFACE_STATE_FULLSCREEN: the window is maximized without
+ * decorations.
+ * @GDK_SURFACE_STATE_ABOVE: the window is kept above other windows.
+ * @GDK_SURFACE_STATE_BELOW: the window is kept below other windows.
+ * @GDK_SURFACE_STATE_FOCUSED: the window is presented as focused (with active decorations).
+ * @GDK_SURFACE_STATE_TILED: the window is in a tiled state, Since 3.10. Since 3.91.2, this
+ * is deprecated in favor of per-edge information.
+ * @GDK_SURFACE_STATE_TOP_TILED: whether the top edge is tiled, Since 3.91.2
+ * @GDK_SURFACE_STATE_TOP_RESIZABLE: whether the top edge is resizable, Since 3.91.2
+ * @GDK_SURFACE_STATE_RIGHT_TILED: whether the right edge is tiled, Since 3.91.2
+ * @GDK_SURFACE_STATE_RIGHT_RESIZABLE: whether the right edge is resizable, Since 3.91.2
+ * @GDK_SURFACE_STATE_BOTTOM_TILED: whether the bottom edge is tiled, Since 3.91.2
+ * @GDK_SURFACE_STATE_BOTTOM_RESIZABLE: whether the bottom edge is resizable, Since 3.91.2
+ * @GDK_SURFACE_STATE_LEFT_TILED: whether the left edge is tiled, Since 3.91.2
+ * @GDK_SURFACE_STATE_LEFT_RESIZABLE: whether the left edge is resizable, Since 3.91.2
+ *
+ * Specifies the state of a toplevel window.
+ */
+typedef enum
+{
+ GDK_SURFACE_STATE_WITHDRAWN = 1 << 0,
+ GDK_SURFACE_STATE_ICONIFIED = 1 << 1,
+ GDK_SURFACE_STATE_MAXIMIZED = 1 << 2,
+ GDK_SURFACE_STATE_STICKY = 1 << 3,
+ GDK_SURFACE_STATE_FULLSCREEN = 1 << 4,
+ GDK_SURFACE_STATE_ABOVE = 1 << 5,
+ GDK_SURFACE_STATE_BELOW = 1 << 6,
+ GDK_SURFACE_STATE_FOCUSED = 1 << 7,
+ GDK_SURFACE_STATE_TILED = 1 << 8,
+ GDK_SURFACE_STATE_TOP_TILED = 1 << 9,
+ GDK_SURFACE_STATE_TOP_RESIZABLE = 1 << 10,
+ GDK_SURFACE_STATE_RIGHT_TILED = 1 << 11,
+ GDK_SURFACE_STATE_RIGHT_RESIZABLE = 1 << 12,
+ GDK_SURFACE_STATE_BOTTOM_TILED = 1 << 13,
+ GDK_SURFACE_STATE_BOTTOM_RESIZABLE = 1 << 14,
+ GDK_SURFACE_STATE_LEFT_TILED = 1 << 15,
+ GDK_SURFACE_STATE_LEFT_RESIZABLE = 1 << 16
+} GdkSurfaceState;
+
+
+typedef struct _GdkSurfaceClass GdkSurfaceClass;
+
+#define GDK_TYPE_SURFACE (gdk_surface_get_type ())
+#define GDK_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE, GdkSurface))
+#define GDK_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE, GdkSurfaceClass))
+#define GDK_IS_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE))
+#define GDK_IS_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE))
+#define GDK_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE, GdkSurfaceClass))
+
+
+struct _GdkSurfaceClass
+{
+ GObjectClass parent_class;
+
+ /* Padding for future expansion */
+ void (*_gdk_reserved1) (void);
+ void (*_gdk_reserved2) (void);
+ void (*_gdk_reserved3) (void);
+ void (*_gdk_reserved4) (void);
+ void (*_gdk_reserved5) (void);
+ void (*_gdk_reserved6) (void);
+ void (*_gdk_reserved7) (void);
+ void (*_gdk_reserved8) (void);
+};
+
+/* Windows
+ */
+GDK_AVAILABLE_IN_ALL
+GType gdk_surface_get_type (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_ALL
+GdkSurface * gdk_surface_new_toplevel (GdkDisplay *display,
+ int width,
+ int height);
+GDK_AVAILABLE_IN_ALL
+GdkSurface * gdk_surface_new_popup (GdkDisplay *display,
+ const GdkRectangle *position);
+GDK_AVAILABLE_IN_ALL
+GdkSurface * gdk_surface_new_temp (GdkDisplay *display);
+GDK_AVAILABLE_IN_ALL
+GdkSurface * gdk_surface_new_child (GdkSurface *parent,
+ const GdkRectangle *position);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_destroy (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+GdkSurfaceType gdk_surface_get_window_type (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_is_destroyed (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+GdkDisplay * gdk_surface_get_display (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_show (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_hide (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_withdraw (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_show_unraised (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_move (GdkSurface *window,
+ gint x,
+ gint y);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_resize (GdkSurface *window,
+ gint width,
+ gint height);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_move_resize (GdkSurface *window,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_raise (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_lower (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_restack (GdkSurface *window,
+ GdkSurface *sibling,
+ gboolean above);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_focus (GdkSurface *window,
+ guint32 timestamp);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_user_data (GdkSurface *window,
+ gpointer user_data);
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_get_accept_focus (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_accept_focus (GdkSurface *window,
+ gboolean accept_focus);
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_get_focus_on_map (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_focus_on_map (GdkSurface *window,
+ gboolean focus_on_map);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_scroll (GdkSurface *window,
+ gint dx,
+ gint dy);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_move_region (GdkSurface *window,
+ const cairo_region_t *region,
+ gint dx,
+ gint dy);
+
+/*
+ * This allows for making shaped (partially transparent) windows
+ * - cool feature, needed for Drag and Drag for example.
+ */
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y);
+
+/*
+ * This routine allows you to quickly take the shapes of all the child windows
+ * of a window and use their shapes as the shape mask for this window - useful
+ * for container windows that dont want to look like a big box
+ *
+ * - Raster
+ */
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_child_shapes (GdkSurface *window);
+
+/*
+ * This routine allows you to merge (ie ADD) child shapes to your
+ * own window’s shape keeping its current shape and ADDING the child
+ * shapes to it.
+ *
+ * - Raster
+ */
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_merge_child_shapes (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_input_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_child_input_shapes (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_merge_child_input_shapes (GdkSurface *window);
+
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_pass_through (GdkSurface *window,
+ gboolean pass_through);
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_get_pass_through (GdkSurface *window);
+
+/*
+ * Check if a window has been shown, and whether all its
+ * parents up to a toplevel have been shown, respectively.
+ * Note that a window that is_viewable below is not necessarily
+ * viewable in the X sense.
+ */
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_is_visible (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_is_viewable (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_is_input_only (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_is_shaped (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+GdkSurfaceState gdk_surface_get_state (GdkSurface *window);
+
+
+/* GdkSurface */
+
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_has_native (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_type_hint (GdkSurface *window,
+ GdkSurfaceTypeHint hint);
+GDK_AVAILABLE_IN_ALL
+GdkSurfaceTypeHint gdk_surface_get_type_hint (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_get_modal_hint (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_modal_hint (GdkSurface *window,
+ gboolean modal);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_skip_taskbar_hint (GdkSurface *window,
+ gboolean skips_taskbar);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_skip_pager_hint (GdkSurface *window,
+ gboolean skips_pager);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_urgency_hint (GdkSurface *window,
+ gboolean urgent);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_geometry_hints (GdkSurface *window,
+ const GdkGeometry *geometry,
+ GdkSurfaceHints geom_mask);
+
+GDK_AVAILABLE_IN_ALL
+cairo_region_t *gdk_surface_get_clip_region (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+cairo_region_t *gdk_surface_get_visible_region(GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+GdkDrawingContext *gdk_surface_begin_draw_frame (GdkSurface *window,
+ GdkDrawContext *context,
+ const cairo_region_t *region);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_end_draw_frame (GdkSurface *window,
+ GdkDrawingContext *context);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_title (GdkSurface *window,
+ const gchar *title);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_role (GdkSurface *window,
+ const gchar *role);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_startup_id (GdkSurface *window,
+ const gchar *startup_id);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_transient_for (GdkSurface *window,
+ GdkSurface *parent);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_cursor (GdkSurface *window,
+ GdkCursor *cursor);
+GDK_AVAILABLE_IN_ALL
+GdkCursor *gdk_surface_get_cursor (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_device_cursor (GdkSurface *window,
+ GdkDevice *device,
+ GdkCursor *cursor);
+GDK_AVAILABLE_IN_ALL
+GdkCursor *gdk_surface_get_device_cursor (GdkSurface *window,
+ GdkDevice *device);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_get_user_data (GdkSurface *window,
+ gpointer *data);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_get_geometry (GdkSurface *window,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height);
+GDK_AVAILABLE_IN_ALL
+int gdk_surface_get_width (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+int gdk_surface_get_height (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_get_position (GdkSurface *window,
+ gint *x,
+ gint *y);
+GDK_AVAILABLE_IN_ALL
+gint gdk_surface_get_origin (GdkSurface *window,
+ gint *x,
+ gint *y);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_get_root_coords (GdkSurface *window,
+ gint x,
+ gint y,
+ gint *root_x,
+ gint *root_y);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_coords_to_parent (GdkSurface *window,
+ gdouble x,
+ gdouble y,
+ gdouble *parent_x,
+ gdouble *parent_y);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_coords_from_parent (GdkSurface *window,
+ gdouble parent_x,
+ gdouble parent_y,
+ gdouble *x,
+ gdouble *y);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_get_root_origin (GdkSurface *window,
+ gint *x,
+ gint *y);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_get_frame_extents (GdkSurface *window,
+ GdkRectangle *rect);
+
+GDK_AVAILABLE_IN_ALL
+gint gdk_surface_get_scale_factor (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+GdkSurface * gdk_surface_get_device_position (GdkSurface *window,
+ GdkDevice *device,
+ gint *x,
+ gint *y,
+ GdkModifierType *mask);
+GDK_AVAILABLE_IN_ALL
+GdkSurface * gdk_surface_get_device_position_double (GdkSurface *window,
+ GdkDevice *device,
+ gdouble *x,
+ gdouble *y,
+ GdkModifierType *mask);
+GDK_AVAILABLE_IN_ALL
+GdkSurface * gdk_surface_get_parent (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+GdkSurface * gdk_surface_get_toplevel (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+GList * gdk_surface_get_children (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+GList * gdk_surface_peek_children (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+GList * gdk_surface_get_children_with_user_data (GdkSurface *window,
+ gpointer user_data);
+
+GDK_AVAILABLE_IN_ALL
+GdkEventMask gdk_surface_get_events (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_events (GdkSurface *window,
+ GdkEventMask event_mask);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_device_events (GdkSurface *window,
+ GdkDevice *device,
+ GdkEventMask event_mask);
+GDK_AVAILABLE_IN_ALL
+GdkEventMask gdk_surface_get_device_events (GdkSurface *window,
+ GdkDevice *device);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_icon_list (GdkSurface *window,
+ GList *surfaces);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_icon_name (GdkSurface *window,
+ const gchar *name);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_group (GdkSurface *window,
+ GdkSurface *leader);
+GDK_AVAILABLE_IN_ALL
+GdkSurface* gdk_surface_get_group (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_decorations (GdkSurface *window,
+ GdkWMDecoration decorations);
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_get_decorations (GdkSurface *window,
+ GdkWMDecoration *decorations);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_functions (GdkSurface *window,
+ GdkWMFunction functions);
+
+GDK_AVAILABLE_IN_ALL
+cairo_surface_t *
+ gdk_surface_create_similar_surface (GdkSurface *window,
+ cairo_content_t content,
+ int width,
+ int height);
+GDK_AVAILABLE_IN_ALL
+cairo_surface_t *
+ gdk_surface_create_similar_image_surface (GdkSurface *window,
+ cairo_format_t format,
+ int width,
+ int height,
+ int scale);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_beep (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_iconify (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_deiconify (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_stick (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_unstick (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_maximize (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_unmaximize (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_fullscreen (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_fullscreen_on_monitor (GdkSurface *window,
+ GdkMonitor *monitor);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_fullscreen_mode (GdkSurface *window,
+ GdkFullscreenMode mode);
+GDK_AVAILABLE_IN_ALL
+GdkFullscreenMode
+ gdk_surface_get_fullscreen_mode (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_unfullscreen (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_keep_above (GdkSurface *window,
+ gboolean setting);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_keep_below (GdkSurface *window,
+ gboolean setting);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_opacity (GdkSurface *window,
+ gdouble opacity);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_register_dnd (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_begin_resize_drag (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_begin_resize_drag_for_device (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_begin_move_drag (GdkSurface *window,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_begin_move_drag_for_device (GdkSurface *window,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp);
+
+/* Interface for dirty-region queueing */
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_invalidate_rect (GdkSurface *window,
+ const GdkRectangle *rect,
+ gboolean invalidate_children);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_invalidate_region (GdkSurface *window,
+ const cairo_region_t *region,
+ gboolean invalidate_children);
+
+/**
+ * GdkSurfaceChildFunc:
+ * @window: a #GdkSurface
+ * @user_data: user data
+ *
+ * A function of this type is passed to gdk_surface_invalidate_maybe_recurse().
+ * It gets called for each child of the window to determine whether to
+ * recursively invalidate it or now.
+ *
+ * Returns: %TRUE to invalidate @window recursively
+ */
+typedef gboolean (*GdkSurfaceChildFunc) (GdkSurface *window,
+ gpointer user_data);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_invalidate_maybe_recurse (GdkSurface *window,
+ const cairo_region_t *region,
+ GdkSurfaceChildFunc child_func,
+ gpointer user_data);
+GDK_AVAILABLE_IN_ALL
+cairo_region_t *gdk_surface_get_update_area (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_freeze_updates (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_thaw_updates (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_constrain_size (GdkGeometry *geometry,
+ GdkSurfaceHints flags,
+ gint width,
+ gint height,
+ gint *new_width,
+ gint *new_height);
+
+/* Multidevice support */
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_support_multidevice (GdkSurface *window,
+ gboolean support_multidevice);
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_get_support_multidevice (GdkSurface *window);
+
+/* Frame clock */
+GDK_AVAILABLE_IN_ALL
+GdkFrameClock* gdk_surface_get_frame_clock (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_opaque_region (GdkSurface *window,
+ cairo_region_t *region);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_surface_set_shadow_width (GdkSurface *window,
+ gint left,
+ gint right,
+ gint top,
+ gint bottom);
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_surface_show_window_menu (GdkSurface *window,
+ GdkEvent *event);
+
+GDK_AVAILABLE_IN_ALL
+GdkGLContext * gdk_surface_create_gl_context (GdkSurface *window,
+ GError **error);
+GDK_AVAILABLE_IN_ALL
+GdkVulkanContext *
+ gdk_surface_create_vulkan_context(GdkSurface *window,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __GDK_SURFACE_H__ */
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gdksurfaceimpl.h"
+
+#include "gdkinternals.h"
+
+
+G_DEFINE_TYPE (GdkSurfaceImpl, gdk_surface_impl, G_TYPE_OBJECT);
+
+static gboolean
+gdk_surface_impl_beep (GdkSurface *window)
+{
+ /* FALSE means windows can't beep, so the display will be
+ * made to beep instead. */
+ return FALSE;
+}
+
+static GdkDisplay *
+get_display_for_window (GdkSurface *primary,
+ GdkSurface *secondary)
+{
+ GdkDisplay *display = gdk_surface_get_display (primary);
+
+ if (display)
+ return display;
+
+ display = gdk_surface_get_display (secondary);
+
+ if (display)
+ return display;
+
+ g_warning ("no display for window, using default");
+ return gdk_display_get_default ();
+}
+
+static GdkMonitor *
+get_monitor_for_rect (GdkDisplay *display,
+ const GdkRectangle *rect)
+{
+ gint biggest_area = G_MININT;
+ GdkMonitor *best_monitor = NULL;
+ GdkMonitor *monitor;
+ GdkRectangle workarea;
+ GdkRectangle intersection;
+ gint x;
+ gint y;
+ gint i;
+
+ for (i = 0; i < gdk_display_get_n_monitors (display); i++)
+ {
+ monitor = gdk_display_get_monitor (display, i);
+ gdk_monitor_get_workarea (monitor, &workarea);
+
+ if (gdk_rectangle_intersect (&workarea, rect, &intersection))
+ {
+ if (intersection.width * intersection.height > biggest_area)
+ {
+ biggest_area = intersection.width * intersection.height;
+ best_monitor = monitor;
+ }
+ }
+ }
+
+ if (best_monitor)
+ return best_monitor;
+
+ x = rect->x + rect->width / 2;
+ y = rect->y + rect->height / 2;
+
+ return gdk_display_get_monitor_at_point (display, x, y);
+}
+
+static gint
+get_anchor_x_sign (GdkGravity anchor)
+{
+ switch (anchor)
+ {
+ case GDK_GRAVITY_STATIC:
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_WEST:
+ case GDK_GRAVITY_SOUTH_WEST:
+ return -1;
+
+ default:
+ case GDK_GRAVITY_NORTH:
+ case GDK_GRAVITY_CENTER:
+ case GDK_GRAVITY_SOUTH:
+ return 0;
+
+ case GDK_GRAVITY_NORTH_EAST:
+ case GDK_GRAVITY_EAST:
+ case GDK_GRAVITY_SOUTH_EAST:
+ return 1;
+ }
+}
+
+static gint
+get_anchor_y_sign (GdkGravity anchor)
+{
+ switch (anchor)
+ {
+ case GDK_GRAVITY_STATIC:
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_NORTH:
+ case GDK_GRAVITY_NORTH_EAST:
+ return -1;
+
+ default:
+ case GDK_GRAVITY_WEST:
+ case GDK_GRAVITY_CENTER:
+ case GDK_GRAVITY_EAST:
+ return 0;
+
+ case GDK_GRAVITY_SOUTH_WEST:
+ case GDK_GRAVITY_SOUTH:
+ case GDK_GRAVITY_SOUTH_EAST:
+ return 1;
+ }
+}
+
+static gint
+maybe_flip_position (gint bounds_pos,
+ gint bounds_size,
+ gint rect_pos,
+ gint rect_size,
+ gint window_size,
+ gint rect_sign,
+ gint window_sign,
+ gint offset,
+ gboolean flip,
+ gboolean *flipped)
+{
+ gint primary;
+ gint secondary;
+
+ *flipped = FALSE;
+ primary = rect_pos + (1 + rect_sign) * rect_size / 2 + offset - (1 + window_sign) * window_size / 2;
+
+ if (!flip || (primary >= bounds_pos && primary + window_size <= bounds_pos + bounds_size))
+ return primary;
+
+ *flipped = TRUE;
+ secondary = rect_pos + (1 - rect_sign) * rect_size / 2 - offset - (1 - window_sign) * window_size / 2;
+
+ if (secondary >= bounds_pos && secondary + window_size <= bounds_pos + bounds_size)
+ return secondary;
+
+ *flipped = FALSE;
+ return primary;
+}
+
+static GdkSurface *
+traverse_to_toplevel (GdkSurface *window,
+ gint x,
+ gint y,
+ gint *toplevel_x,
+ gint *toplevel_y)
+{
+ GdkSurface *parent;
+ gdouble xf = x;
+ gdouble yf = y;
+
+ while ((parent = window->parent) != NULL &&
+ (gdk_surface_get_window_type (parent) != GDK_SURFACE_ROOT))
+ {
+ gdk_surface_coords_to_parent (window, xf, yf, &xf, &yf);
+ window = parent;
+ }
+
+ *toplevel_x = (gint) xf;
+ *toplevel_y = (gint) yf;
+ return window;
+}
+
+static void
+gdk_surface_impl_move_to_rect (GdkSurface *window,
+ const GdkRectangle *rect,
+ GdkGravity rect_anchor,
+ GdkGravity window_anchor,
+ GdkAnchorHints anchor_hints,
+ gint rect_anchor_dx,
+ gint rect_anchor_dy)
+{
+ GdkSurface *transient_for_toplevel;
+ GdkDisplay *display;
+ GdkMonitor *monitor;
+ GdkRectangle bounds;
+ GdkRectangle root_rect = *rect;
+ GdkRectangle flipped_rect;
+ GdkRectangle final_rect;
+ gboolean flipped_x;
+ gboolean flipped_y;
+
+ /*
+ * First translate the anchor rect to toplevel coordinates. This is needed
+ * because not all backends will be able to get root coordinates for
+ * non-toplevel windows.
+ */
+ transient_for_toplevel = traverse_to_toplevel (window->transient_for,
+ root_rect.x,
+ root_rect.y,
+ &root_rect.x,
+ &root_rect.y);
+
+ gdk_surface_get_root_coords (transient_for_toplevel,
+ root_rect.x,
+ root_rect.y,
+ &root_rect.x,
+ &root_rect.y);
+
+ display = get_display_for_window (window, window->transient_for);
+ monitor = get_monitor_for_rect (display, &root_rect);
+ gdk_monitor_get_workarea (monitor, &bounds);
+
+ flipped_rect.width = window->width - window->shadow_left - window->shadow_right;
+ flipped_rect.height = window->height - window->shadow_top - window->shadow_bottom;
+ flipped_rect.x = maybe_flip_position (bounds.x,
+ bounds.width,
+ root_rect.x,
+ root_rect.width,
+ flipped_rect.width,
+ get_anchor_x_sign (rect_anchor),
+ get_anchor_x_sign (window_anchor),
+ rect_anchor_dx,
+ anchor_hints & GDK_ANCHOR_FLIP_X,
+ &flipped_x);
+ flipped_rect.y = maybe_flip_position (bounds.y,
+ bounds.height,
+ root_rect.y,
+ root_rect.height,
+ flipped_rect.height,
+ get_anchor_y_sign (rect_anchor),
+ get_anchor_y_sign (window_anchor),
+ rect_anchor_dy,
+ anchor_hints & GDK_ANCHOR_FLIP_Y,
+ &flipped_y);
+
+ final_rect = flipped_rect;
+
+ if (anchor_hints & GDK_ANCHOR_SLIDE_X)
+ {
+ if (final_rect.x + final_rect.width > bounds.x + bounds.width)
+ final_rect.x = bounds.x + bounds.width - final_rect.width;
+
+ if (final_rect.x < bounds.x)
+ final_rect.x = bounds.x;
+ }
+
+ if (anchor_hints & GDK_ANCHOR_SLIDE_Y)
+ {
+ if (final_rect.y + final_rect.height > bounds.y + bounds.height)
+ final_rect.y = bounds.y + bounds.height - final_rect.height;
+
+ if (final_rect.y < bounds.y)
+ final_rect.y = bounds.y;
+ }
+
+ if (anchor_hints & GDK_ANCHOR_RESIZE_X)
+ {
+ if (final_rect.x < bounds.x)
+ {
+ final_rect.width -= bounds.x - final_rect.x;
+ final_rect.x = bounds.x;
+ }
+
+ if (final_rect.x + final_rect.width > bounds.x + bounds.width)
+ final_rect.width = bounds.x + bounds.width - final_rect.x;
+ }
+
+ if (anchor_hints & GDK_ANCHOR_RESIZE_Y)
+ {
+ if (final_rect.y < bounds.y)
+ {
+ final_rect.height -= bounds.y - final_rect.y;
+ final_rect.y = bounds.y;
+ }
+
+ if (final_rect.y + final_rect.height > bounds.y + bounds.height)
+ final_rect.height = bounds.y + bounds.height - final_rect.y;
+ }
+
+ flipped_rect.x -= window->shadow_left;
+ flipped_rect.y -= window->shadow_top;
+ flipped_rect.width += window->shadow_left + window->shadow_right;
+ flipped_rect.height += window->shadow_top + window->shadow_bottom;
+
+ final_rect.x -= window->shadow_left;
+ final_rect.y -= window->shadow_top;
+ final_rect.width += window->shadow_left + window->shadow_right;
+ final_rect.height += window->shadow_top + window->shadow_bottom;
+
+ if (final_rect.width != window->width || final_rect.height != window->height)
+ gdk_surface_move_resize (window, final_rect.x, final_rect.y, final_rect.width, final_rect.height);
+ else
+ gdk_surface_move (window, final_rect.x, final_rect.y);
+
+ g_signal_emit_by_name (window,
+ "moved-to-rect",
+ &flipped_rect,
+ &final_rect,
+ flipped_x,
+ flipped_y);
+}
+
+static void
+gdk_surface_impl_process_updates_recurse (GdkSurface *window,
+ cairo_region_t *region)
+{
+ _gdk_surface_process_updates_recurse (window, region);
+}
+
+static void
+gdk_surface_impl_class_init (GdkSurfaceImplClass *impl_class)
+{
+ impl_class->beep = gdk_surface_impl_beep;
+ impl_class->move_to_rect = gdk_surface_impl_move_to_rect;
+ impl_class->process_updates_recurse = gdk_surface_impl_process_updates_recurse;
+}
+
+static void
+gdk_surface_impl_init (GdkSurfaceImpl *impl)
+{
+}
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GDK_SURFACE_IMPL_H__
+#define __GDK_SURFACE_IMPL_H__
+
+#include <gdk/gdksurface.h>
+#include <gdk/gdkproperty.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_SURFACE_IMPL (gdk_surface_impl_get_type ())
+#define GDK_SURFACE_IMPL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL, GdkSurfaceImpl))
+#define GDK_SURFACE_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL, GdkSurfaceImplClass))
+#define GDK_IS_SURFACE_IMPL(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL))
+#define GDK_IS_SURFACE_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL))
+#define GDK_SURFACE_IMPL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL, GdkSurfaceImplClass))
+
+typedef struct _GdkSurfaceImpl GdkSurfaceImpl;
+typedef struct _GdkSurfaceImplClass GdkSurfaceImplClass;
+
+struct _GdkSurfaceImpl
+{
+ GObject parent;
+};
+
+struct _GdkSurfaceImplClass
+{
+ GObjectClass parent_class;
+
+ cairo_surface_t *
+ (* ref_cairo_surface) (GdkSurface *window);
+ cairo_surface_t *
+ (* create_similar_image_surface) (GdkSurface * window,
+ cairo_format_t format,
+ int width,
+ int height);
+
+ void (* show) (GdkSurface *window,
+ gboolean already_mapped);
+ void (* hide) (GdkSurface *window);
+ void (* withdraw) (GdkSurface *window);
+ void (* raise) (GdkSurface *window);
+ void (* lower) (GdkSurface *window);
+ void (* restack_toplevel) (GdkSurface *window,
+ GdkSurface *sibling,
+ gboolean above);
+
+ void (* move_resize) (GdkSurface *window,
+ gboolean with_move,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
+ void (* move_to_rect) (GdkSurface *window,
+ const GdkRectangle *rect,
+ GdkGravity rect_anchor,
+ GdkGravity window_anchor,
+ GdkAnchorHints anchor_hints,
+ gint rect_anchor_dx,
+ gint rect_anchor_dy);
+
+ GdkEventMask (* get_events) (GdkSurface *window);
+ void (* set_events) (GdkSurface *window,
+ GdkEventMask event_mask);
+
+ void (* get_geometry) (GdkSurface *window,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height);
+ void (* get_root_coords) (GdkSurface *window,
+ gint x,
+ gint y,
+ gint *root_x,
+ gint *root_y);
+ gboolean (* get_device_state) (GdkSurface *window,
+ GdkDevice *device,
+ gdouble *x,
+ gdouble *y,
+ GdkModifierType *mask);
+ gboolean (* begin_paint) (GdkSurface *window);
+ void (* end_paint) (GdkSurface *window);
+
+ void (* shape_combine_region) (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y);
+ void (* input_shape_combine_region) (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y);
+
+ /* Called before processing updates for a window. This gives the windowing
+ * layer a chance to save the region for later use in avoiding duplicate
+ * exposes.
+ */
+ void (* queue_antiexpose) (GdkSurface *window,
+ cairo_region_t *update_area);
+
+/* Called to do the windowing system specific part of gdk_surface_destroy(),
+ *
+ * window: The window being destroyed
+ * recursing: If TRUE, then this is being called because a parent
+ * was destroyed. This generally means that the call to the windowing
+ * system to destroy the window can be omitted, since it will be
+ * destroyed as a result of the parent being destroyed.
+ * Unless @foreign_destroy
+ * foreign_destroy: If TRUE, the window or a parent was destroyed by some
+ * external agency. The window has already been destroyed and no
+ * windowing system calls should be made. (This may never happen
+ * for some windowing systems.)
+ */
+ void (* destroy) (GdkSurface *window,
+ gboolean recursing,
+ gboolean foreign_destroy);
+
+
+ /* optional */
+ gboolean (* beep) (GdkSurface *window);
+
+ void (* focus) (GdkSurface *window,
+ guint32 timestamp);
+ void (* set_type_hint) (GdkSurface *window,
+ GdkSurfaceTypeHint hint);
+ GdkSurfaceTypeHint (* get_type_hint) (GdkSurface *window);
+ void (* set_modal_hint) (GdkSurface *window,
+ gboolean modal);
+ void (* set_skip_taskbar_hint) (GdkSurface *window,
+ gboolean skips_taskbar);
+ void (* set_skip_pager_hint) (GdkSurface *window,
+ gboolean skips_pager);
+ void (* set_urgency_hint) (GdkSurface *window,
+ gboolean urgent);
+ void (* set_geometry_hints) (GdkSurface *window,
+ const GdkGeometry *geometry,
+ GdkSurfaceHints geom_mask);
+ void (* set_title) (GdkSurface *window,
+ const gchar *title);
+ void (* set_role) (GdkSurface *window,
+ const gchar *role);
+ void (* set_startup_id) (GdkSurface *window,
+ const gchar *startup_id);
+ void (* set_transient_for) (GdkSurface *window,
+ GdkSurface *parent);
+ void (* get_frame_extents) (GdkSurface *window,
+ GdkRectangle *rect);
+ void (* set_accept_focus) (GdkSurface *window,
+ gboolean accept_focus);
+ void (* set_focus_on_map) (GdkSurface *window,
+ gboolean focus_on_map);
+ void (* set_icon_list) (GdkSurface *window,
+ GList *pixbufs);
+ void (* set_icon_name) (GdkSurface *window,
+ const gchar *name);
+ void (* iconify) (GdkSurface *window);
+ void (* deiconify) (GdkSurface *window);
+ void (* stick) (GdkSurface *window);
+ void (* unstick) (GdkSurface *window);
+ void (* maximize) (GdkSurface *window);
+ void (* unmaximize) (GdkSurface *window);
+ void (* fullscreen) (GdkSurface *window);
+ void (* fullscreen_on_monitor) (GdkSurface *window,
+ GdkMonitor *monitor);
+ void (* apply_fullscreen_mode) (GdkSurface *window);
+ void (* unfullscreen) (GdkSurface *window);
+ void (* set_keep_above) (GdkSurface *window,
+ gboolean setting);
+ void (* set_keep_below) (GdkSurface *window,
+ gboolean setting);
+ GdkSurface * (* get_group) (GdkSurface *window);
+ void (* set_group) (GdkSurface *window,
+ GdkSurface *leader);
+ void (* set_decorations) (GdkSurface *window,
+ GdkWMDecoration decorations);
+ gboolean (* get_decorations) (GdkSurface *window,
+ GdkWMDecoration *decorations);
+ void (* set_functions) (GdkSurface *window,
+ GdkWMFunction functions);
+ void (* begin_resize_drag) (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp);
+ void (* begin_move_drag) (GdkSurface *window,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp);
+ void (* enable_synchronized_configure) (GdkSurface *window);
+ void (* configure_finished) (GdkSurface *window);
+ void (* set_opacity) (GdkSurface *window,
+ gdouble opacity);
+ void (* destroy_notify) (GdkSurface *window);
+ void (* register_dnd) (GdkSurface *window);
+ GdkDragContext * (*drag_begin) (GdkSurface *window,
+ GdkDevice *device,
+ GdkContentProvider*content,
+ GdkDragAction actions,
+ gint dx,
+ gint dy);
+
+ void (*process_updates_recurse) (GdkSurface *window,
+ cairo_region_t *region);
+
+ gint (* get_scale_factor) (GdkSurface *window);
+ void (* get_unscaled_size) (GdkSurface *window,
+ int *unscaled_width,
+ int *unscaled_height);
+
+ void (* set_opaque_region) (GdkSurface *window,
+ cairo_region_t *region);
+ void (* set_shadow_width) (GdkSurface *window,
+ gint left,
+ gint right,
+ gint top,
+ gint bottom);
+ gboolean (* show_window_menu) (GdkSurface *window,
+ GdkEvent *event);
+ GdkGLContext *(*create_gl_context) (GdkSurface *window,
+ gboolean attached,
+ GdkGLContext *share,
+ GError **error);
+ gboolean (* supports_edge_constraints)(GdkSurface *window);
+};
+
+/* Interface Functions */
+GType gdk_surface_impl_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_SURFACE_IMPL_H__ */
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
- * Josh MacDonald, Ryan Lortie
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#include "config.h"
-
-#include <cairo-gobject.h>
-
-#include "gdkwindow.h"
-
-#include "gdkrectangle.h"
-#include "gdkinternals.h"
-#include "gdkintl.h"
-#include "gdkdisplayprivate.h"
-#include "gdkdeviceprivate.h"
-#include "gdkmarshalers.h"
-#include "gdkframeclockidle.h"
-#include "gdkwindowimpl.h"
-#include "gdkglcontextprivate.h"
-#include "gdkdrawingcontextprivate.h"
-#include "gdk-private.h"
-
-#include <math.h>
-
-#include <epoxy/gl.h>
-
-/* for the use of round() */
-#include "fallback-c89.c"
-
-#ifdef GDK_WINDOWING_WAYLAND
-#include "wayland/gdkwayland.h"
-#endif
-
-#undef DEBUG_WINDOW_PRINTING
-
-
-/**
- * SECTION:windows
- * @Short_description: Onscreen display areas in the target window system
- * @Title: Windows
- *
- * A #GdkSurface is a (usually) rectangular region on the screen.
- * It’s a low-level object, used to implement high-level objects such as
- * #GtkWidget and #GtkWindow on the GTK+ level. A #GtkWindow is a toplevel
- * window, the thing a user might think of as a “window” with a titlebar
- * and so on; a #GtkWindow may contain many sub-GdkSurfaces.
- */
-
-/**
- * GdkSurface:
- *
- * The GdkSurface struct contains only private fields and
- * should not be accessed directly.
- */
-
-/* Historically a GdkSurface always matches a platform native window,
- * be it a toplevel window or a child window. In this setup the
- * GdkSurface (and other GdkDrawables) were platform independent classes,
- * and the actual platform specific implementation was in a delegate
- * object available as “impl” in the window object.
- *
- * With the addition of client side windows this changes a bit. The
- * application-visible GdkSurface object behaves as it did before, but
- * such windows now don't a corresponding native window. Instead subwindows
- * windows are “client side”, i.e. emulated by the gdk code such
- * that clipping, drawing, moving, events etc work as expected.
- *
- * GdkSurfaces have a pointer to the “impl window” they are in, i.e.
- * the topmost GdkSurface which have the same “impl” value. This is stored
- * in impl_window, which is different from the window itself only for client
- * side windows.
- * All GdkSurfaces (native or not) track the position of the window in the parent
- * (x, y), the size of the window (width, height), the position of the window
- * with respect to the impl window (abs_x, abs_y). We also track the clip
- * region of the window wrt parent windows, in window-relative coordinates (clip_region).
- */
-
-enum {
- MOVED_TO_RECT,
- LAST_SIGNAL
-};
-
-enum {
- PROP_0,
- PROP_CURSOR,
- PROP_DISPLAY,
- PROP_STATE,
- LAST_PROP
-};
-
-/* Global info */
-
-static void gdk_surface_finalize (GObject *object);
-
-static void gdk_surface_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void gdk_surface_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-
-static void gdk_surface_clear_backing_region (GdkSurface *window);
-
-static void recompute_visible_regions (GdkSurface *private,
- gboolean recalculate_children);
-static void gdk_surface_invalidate_in_parent (GdkSurface *private);
-static void update_cursor (GdkDisplay *display,
- GdkDevice *device);
-static void impl_window_add_update_area (GdkSurface *impl_window,
- cairo_region_t *region);
-static void gdk_surface_invalidate_region_full (GdkSurface *window,
- const cairo_region_t *region,
- gboolean invalidate_children);
-static void gdk_surface_invalidate_rect_full (GdkSurface *window,
- const GdkRectangle *rect,
- gboolean invalidate_children);
-static cairo_surface_t *gdk_surface_ref_impl_surface (GdkSurface *window);
-
-static void gdk_surface_set_frame_clock (GdkSurface *window,
- GdkFrameClock *clock);
-
-
-static guint signals[LAST_SIGNAL] = { 0 };
-static GParamSpec *properties[LAST_PROP] = { NULL, };
-
-G_DEFINE_ABSTRACT_TYPE (GdkSurface, gdk_surface, G_TYPE_OBJECT)
-
-#ifdef DEBUG_WINDOW_PRINTING
-char *
-print_region (cairo_region_t *region)
-{
- GString *s = g_string_new ("{");
- if (cairo_region_is_empty (region))
- {
- g_string_append (s, "empty");
- }
- else
- {
- int num = cairo_region_num_rectangles (region);
- cairo_rectangle_int_t r;
-
- if (num == 1)
- {
- cairo_region_get_rectangle (region, 0, &r);
- g_string_append_printf (s, "%dx%d @%d,%d", r.width, r.height, r.x, r.y);
- }
- else
- {
- int i;
- cairo_region_get_extents (region, &r);
- g_string_append_printf (s, "extent: %dx%d @%d,%d, details: ", r.width, r.height, r.x, r.y);
- for (i = 0; i < num; i++)
- {
- cairo_region_get_rectangle (region, i, &r);
- g_string_append_printf (s, "[%dx%d @%d,%d]", r.width, r.height, r.x, r.y);
- if (i != num -1)
- g_string_append (s, ", ");
- }
- }
- }
- g_string_append (s, "}");
- return g_string_free (s, FALSE);
-}
-#endif
-
-static GList *
-list_insert_link_before (GList *list,
- GList *sibling,
- GList *link)
-{
- if (list == NULL || sibling == list)
- {
- link->prev = NULL;
- link->next = list;
- if (list)
- list->prev = link;
- return link;
- }
- else if (sibling == NULL)
- {
- GList *last = g_list_last (list);
-
- last->next = link;
- link->prev = last;
- link->next = NULL;
-
- return list;
- }
- else
- {
- link->next = sibling;
- link->prev = sibling->prev;
- sibling->prev = link;
-
- if (link->prev)
- link->prev->next = link;
-
- return list;
- }
-}
-
-static void
-gdk_surface_init (GdkSurface *window)
-{
- /* 0-initialization is good for all other fields. */
-
- window->window_type = GDK_SURFACE_CHILD;
-
- window->state = GDK_SURFACE_STATE_WITHDRAWN;
- window->fullscreen_mode = GDK_FULLSCREEN_ON_CURRENT_MONITOR;
- window->width = 1;
- window->height = 1;
- window->toplevel_window_type = -1;
- window->children_list_node.data = window;
-
- window->device_cursor = g_hash_table_new_full (NULL, NULL,
- NULL, g_object_unref);
-}
-
-static void
-gdk_surface_class_init (GdkSurfaceClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = gdk_surface_finalize;
- object_class->set_property = gdk_surface_set_property;
- object_class->get_property = gdk_surface_get_property;
-
- /* Properties */
-
- /**
- * GdkSurface:cursor:
- *
- * The mouse pointer for a #GdkSurface. See gdk_surface_set_cursor() and
- * gdk_surface_get_cursor() for details.
- */
- properties[PROP_CURSOR] =
- g_param_spec_object ("cursor",
- P_("Cursor"),
- P_("Cursor"),
- GDK_TYPE_CURSOR,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
- /**
- * GdkSurface:display:
- *
- * The #GdkDisplay connection of the window. See gdk_surface_get_display()
- * for details.
- */
- properties[PROP_DISPLAY] =
- g_param_spec_object ("display",
- P_("Display"),
- P_("Display"),
- GDK_TYPE_DISPLAY,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
- properties[PROP_STATE] =
- g_param_spec_flags ("state",
- P_("State"),
- P_("State"),
- GDK_TYPE_SURFACE_STATE, GDK_SURFACE_STATE_WITHDRAWN,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (object_class, LAST_PROP, properties);
-
- /**
- * GdkSurface::moved-to-rect:
- * @window: the #GdkSurface that moved
- * @flipped_rect: (nullable): the position of @window after any possible
- * flipping or %NULL if the backend can't obtain it
- * @final_rect: (nullable): the final position of @window or %NULL if the
- * backend can't obtain it
- * @flipped_x: %TRUE if the anchors were flipped horizontally
- * @flipped_y: %TRUE if the anchors were flipped vertically
- *
- * Emitted when the position of @window is finalized after being moved to a
- * destination rectangle.
- *
- * @window might be flipped over the destination rectangle in order to keep
- * it on-screen, in which case @flipped_x and @flipped_y will be set to %TRUE
- * accordingly.
- *
- * @flipped_rect is the ideal position of @window after any possible
- * flipping, but before any possible sliding. @final_rect is @flipped_rect,
- * but possibly translated in the case that flipping is still ineffective in
- * keeping @window on-screen.
- * Stability: Private
- */
- signals[MOVED_TO_RECT] =
- g_signal_new (g_intern_static_string ("moved-to-rect"),
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL,
- NULL,
- _gdk_marshal_VOID__POINTER_POINTER_BOOLEAN_BOOLEAN,
- G_TYPE_NONE,
- 4,
- G_TYPE_POINTER,
- G_TYPE_POINTER,
- G_TYPE_BOOLEAN,
- G_TYPE_BOOLEAN);
-}
-
-static void
-seat_removed_cb (GdkDisplay *display,
- GdkSeat *seat,
- GdkSurface *window)
-{
- GdkDevice *device = gdk_seat_get_pointer (seat);
-
- window->devices_inside = g_list_remove (window->devices_inside, device);
- g_hash_table_remove (window->device_cursor, device);
-
- if (window->device_events)
- g_hash_table_remove (window->device_events, device);
-}
-
-static void
-gdk_surface_finalize (GObject *object)
-{
- GdkSurface *window = GDK_SURFACE (object);
-
- g_signal_handlers_disconnect_by_func (gdk_surface_get_display (window),
- seat_removed_cb, window);
-
- if (!GDK_SURFACE_DESTROYED (window))
- {
- if (GDK_SURFACE_TYPE (window) != GDK_SURFACE_FOREIGN)
- {
- g_warning ("losing last reference to undestroyed window");
- _gdk_surface_destroy (window, FALSE);
- }
- else
- /* We use TRUE here, to keep us from actually calling
- * XDestroyWindow() on the window
- */
- _gdk_surface_destroy (window, TRUE);
- }
-
- if (window->impl)
- {
- g_object_unref (window->impl);
- window->impl = NULL;
- }
-
- if (window->impl_window != window)
- {
- g_object_unref (window->impl_window);
- window->impl_window = NULL;
- }
-
- if (window->shape)
- cairo_region_destroy (window->shape);
-
- if (window->input_shape)
- cairo_region_destroy (window->input_shape);
-
- if (window->cursor)
- g_object_unref (window->cursor);
-
- if (window->device_cursor)
- g_hash_table_destroy (window->device_cursor);
-
- if (window->device_events)
- g_hash_table_destroy (window->device_events);
-
- if (window->devices_inside)
- g_list_free (window->devices_inside);
-
- g_clear_object (&window->display);
-
- if (window->opaque_region)
- cairo_region_destroy (window->opaque_region);
-
- G_OBJECT_CLASS (gdk_surface_parent_class)->finalize (object);
-}
-
-static void
-gdk_surface_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- GdkSurface *window = GDK_SURFACE (object);
-
- switch (prop_id)
- {
- case PROP_CURSOR:
- gdk_surface_set_cursor (window, g_value_get_object (value));
- break;
-
- case PROP_DISPLAY:
- window->display = g_value_dup_object (value);
- g_assert (window->display != NULL);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gdk_surface_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- GdkSurface *window = GDK_SURFACE (object);
-
- switch (prop_id)
- {
- case PROP_CURSOR:
- g_value_set_object (value, gdk_surface_get_cursor (window));
- break;
-
- case PROP_DISPLAY:
- g_value_set_object (value, window->display);
- break;
-
- case PROP_STATE:
- g_value_set_flags (value, window->state);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static gboolean
-gdk_surface_is_subsurface (GdkSurface *window)
-{
- return window->window_type == GDK_SURFACE_SUBSURFACE;
-}
-
-static GdkSurface *
-gdk_surface_get_impl_window (GdkSurface *window)
-{
- return window->impl_window;
-}
-
-GdkSurface *
-_gdk_surface_get_impl_window (GdkSurface *window)
-{
- return gdk_surface_get_impl_window (window);
-}
-
-static gboolean
-gdk_surface_has_impl (GdkSurface *window)
-{
- return window->impl_window == window;
-}
-
-static gboolean
-gdk_surface_is_toplevel (GdkSurface *window)
-{
- return
- window->parent == NULL ||
- window->parent->window_type == GDK_SURFACE_ROOT;
-}
-
-gboolean
-_gdk_surface_has_impl (GdkSurface *window)
-{
- return gdk_surface_has_impl (window);
-}
-
-static gboolean
-gdk_surface_has_no_impl (GdkSurface *window)
-{
- return window->impl_window != window;
-}
-
-static void
-remove_sibling_overlapped_area (GdkSurface *window,
- cairo_region_t *region)
-{
- GdkSurface *parent;
- GdkSurface *sibling;
- cairo_region_t *child_region;
- GdkRectangle r;
- GList *l;
-
- parent = window->parent;
-
- if (gdk_surface_is_toplevel (window))
- return;
-
- /* Convert from from window coords to parent coords */
- cairo_region_translate (region, window->x, window->y);
-
- for (l = parent->children; l; l = l->next)
- {
- sibling = l->data;
-
- if (sibling == window)
- break;
-
- if (!GDK_SURFACE_IS_MAPPED (sibling) || sibling->input_only)
- continue;
-
- r.x = sibling->x;
- r.y = sibling->y;
- r.width = sibling->width;
- r.height = sibling->height;
-
- child_region = cairo_region_create_rectangle (&r);
-
- if (sibling->shape)
- {
- /* Adjust shape region to parent window coords */
- cairo_region_translate (sibling->shape, sibling->x, sibling->y);
- cairo_region_intersect (child_region, sibling->shape);
- cairo_region_translate (sibling->shape, -sibling->x, -sibling->y);
- }
-
- cairo_region_subtract (region, child_region);
- cairo_region_destroy (child_region);
- }
-
- remove_sibling_overlapped_area (parent, region);
-
- /* Convert back to window coords */
- cairo_region_translate (region, -window->x, -window->y);
-}
-
-static void
-remove_child_area (GdkSurface *window,
- gboolean for_input,
- cairo_region_t *region)
-{
- GdkSurface *child;
- cairo_region_t *child_region;
- GdkRectangle r;
- GList *l;
-
- for (l = window->children; l; l = l->next)
- {
- child = l->data;
-
- /* If region is empty already, no need to do
- anything potentially costly */
- if (cairo_region_is_empty (region))
- break;
-
- if (!GDK_SURFACE_IS_MAPPED (child) || child->input_only)
- continue;
-
- r.x = child->x;
- r.y = child->y;
- r.width = child->width;
- r.height = child->height;
-
- /* Bail early if child totally outside region */
- if (cairo_region_contains_rectangle (region, &r) == CAIRO_REGION_OVERLAP_OUT)
- continue;
-
- child_region = cairo_region_create_rectangle (&r);
-
- if (child->shape)
- {
- /* Adjust shape region to parent window coords */
- cairo_region_translate (child->shape, child->x, child->y);
- cairo_region_intersect (child_region, child->shape);
- cairo_region_translate (child->shape, -child->x, -child->y);
- }
-
- if (for_input)
- {
- if (child->input_shape)
- cairo_region_intersect (child_region, child->input_shape);
- }
-
- cairo_region_subtract (region, child_region);
- cairo_region_destroy (child_region);
- }
-}
-
-static gboolean
-should_apply_clip_as_shape (GdkSurface *window)
-{
- return
- gdk_surface_has_impl (window) &&
- /* Not for non-shaped toplevels */
- (window->shape != NULL || window->applied_shape) &&
- /* or for foreign windows */
- window->window_type != GDK_SURFACE_FOREIGN &&
- /* or for the root window */
- window->window_type != GDK_SURFACE_ROOT;
-}
-
-static void
-apply_shape (GdkSurface *window,
- cairo_region_t *region)
-{
- GdkSurfaceImplClass *impl_class;
-
- /* We trash whether we applied a shape so that
- we can avoid unsetting it many times, which
- could happen in e.g. apply_clip_as_shape as
- windows get resized */
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- if (region)
- impl_class->shape_combine_region (window,
- region, 0, 0);
- else if (window->applied_shape)
- impl_class->shape_combine_region (window,
- NULL, 0, 0);
-
- window->applied_shape = region != NULL;
-}
-
-static gboolean
-region_rect_equal (const cairo_region_t *region,
- const GdkRectangle *rect)
-{
- GdkRectangle extents;
-
- if (cairo_region_num_rectangles (region) != 1)
- return FALSE;
-
- cairo_region_get_extents (region, &extents);
-
- return extents.x == rect->x &&
- extents.y == rect->y &&
- extents.width == rect->width &&
- extents.height == rect->height;
-}
-
-static void
-apply_clip_as_shape (GdkSurface *window)
-{
- GdkRectangle r;
- cairo_region_t *region;
-
- r.x = r.y = 0;
- r.width = window->width;
- r.height = window->height;
-
- region = cairo_region_copy (window->clip_region);
- remove_sibling_overlapped_area (window, region);
-
- /* We only apply the clip region if would differ
- from the actual clip region implied by the size
- of the window. This is to avoid unneccessarily
- adding meaningless shapes to all native subwindows */
- if (!region_rect_equal (region, &r))
- apply_shape (window, region);
- else
- apply_shape (window, NULL);
-
- cairo_region_destroy (region);
-}
-
-static void
-recompute_visible_regions_internal (GdkSurface *private,
- gboolean recalculate_clip,
- gboolean recalculate_children)
-{
- GdkRectangle r;
- GList *l;
- GdkSurface *child;
- cairo_region_t *new_clip;
- gboolean clip_region_changed;
- gboolean abs_pos_changed;
- int old_abs_x, old_abs_y;
-
- old_abs_x = private->abs_x;
- old_abs_y = private->abs_y;
-
- /* Update absolute position */
- if ((gdk_surface_has_impl (private) &&
- private->window_type != GDK_SURFACE_SUBSURFACE) ||
- (gdk_surface_is_toplevel (private) &&
- private->window_type == GDK_SURFACE_SUBSURFACE))
- {
- /* Native windows and toplevel subsurfaces start here */
- private->abs_x = 0;
- private->abs_y = 0;
- }
- else
- {
- private->abs_x = private->parent->abs_x + private->x;
- private->abs_y = private->parent->abs_y + private->y;
- }
-
- abs_pos_changed =
- private->abs_x != old_abs_x ||
- private->abs_y != old_abs_y;
-
- /* Update clip region based on:
- * parent clip
- * window size/position
- */
- clip_region_changed = FALSE;
- if (recalculate_clip)
- {
- if (private->viewable)
- {
- /* Calculate visible region (sans children) in parent window coords */
- r.x = private->x;
- r.y = private->y;
- r.width = private->width;
- r.height = private->height;
- new_clip = cairo_region_create_rectangle (&r);
-
- if (!gdk_surface_is_toplevel (private))
- cairo_region_intersect (new_clip, private->parent->clip_region);
-
- /* Convert from parent coords to window coords */
- cairo_region_translate (new_clip, -private->x, -private->y);
-
- if (should_apply_clip_as_shape (private) && private->shape)
- cairo_region_intersect (new_clip, private->shape);
- }
- else
- new_clip = cairo_region_create ();
-
- if (private->clip_region == NULL ||
- !cairo_region_equal (private->clip_region, new_clip))
- clip_region_changed = TRUE;
-
- if (private->clip_region)
- cairo_region_destroy (private->clip_region);
- private->clip_region = new_clip;
- }
-
- /* Update all children, recursively (except for root, where children are not exact). */
- if ((abs_pos_changed || clip_region_changed || recalculate_children) &&
- private->window_type != GDK_SURFACE_ROOT)
- {
- for (l = private->children; l; l = l->next)
- {
- child = l->data;
- /* Only recalculate clip if the the clip region changed, otherwise
- * there is no way the child clip region could change (its has not e.g. moved)
- * Except if recalculate_children is set to force child updates
- */
- recompute_visible_regions_internal (child,
- recalculate_clip && (clip_region_changed || recalculate_children),
- FALSE);
- }
- }
-}
-
-/* Call this when private has changed in one or more of these ways:
- * size changed
- * window moved
- * new window added
- * stacking order of window changed
- * child deleted
- *
- * It will recalculate abs_x/y and the clip regions
- *
- * Unless the window didn’t change stacking order or size/pos, pass in TRUE
- * for recalculate_siblings. (Mostly used internally for the recursion)
- *
- * If a child window was removed (and you can’t use that child for
- * recompute_visible_regions), pass in TRUE for recalculate_children on the parent
- */
-static void
-recompute_visible_regions (GdkSurface *private,
- gboolean recalculate_children)
-{
- GdkSurface *toplevel;
-
- toplevel = gdk_surface_get_toplevel (private);
- toplevel->geometry_dirty = TRUE;
-
- recompute_visible_regions_internal (private,
- TRUE,
- recalculate_children);
-}
-
-static void
-gdk_surface_clear_old_updated_area (GdkSurface *window)
-{
- int i;
-
- for (i = 0; i < 2; i++)
- {
- if (window->old_updated_area[i])
- {
- cairo_region_destroy (window->old_updated_area[i]);
- window->old_updated_area[i] = NULL;
- }
- }
-}
-
-static void
-gdk_surface_append_old_updated_area (GdkSurface *window,
- cairo_region_t *region)
-{
- if (window->old_updated_area[1])
- cairo_region_destroy (window->old_updated_area[1]);
- window->old_updated_area[1] = window->old_updated_area[0];
- window->old_updated_area[0] = cairo_region_reference (region);
-}
-
-void
-_gdk_surface_update_size (GdkSurface *window)
-{
- gdk_surface_clear_old_updated_area (window);
- recompute_visible_regions (window, FALSE);
-}
-
-static GdkEventMask
-get_native_device_event_mask (GdkSurface *private,
- GdkDevice *device)
-{
- GdkEventMask event_mask;
-
- if (device)
- event_mask = GPOINTER_TO_INT (g_hash_table_lookup (private->device_events, device));
- else
- event_mask = private->event_mask;
-
- if (private->window_type == GDK_SURFACE_ROOT ||
- private->window_type == GDK_SURFACE_FOREIGN)
- return event_mask;
- else
- {
- GdkEventMask mask;
-
- mask = private->event_mask;
-
- /* We need thse for all native windows so we can
- emulate events on children: */
- mask |=
- GDK_EXPOSURE_MASK |
- GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
- GDK_TOUCH_MASK |
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- GDK_SCROLL_MASK;
-
- return mask;
- }
-}
-
-static GdkEventMask
-get_native_event_mask (GdkSurface *private)
-{
- return get_native_device_event_mask (private, NULL);
-}
-
-GdkSurface*
-gdk_surface_new (GdkDisplay *display,
- GdkSurface *parent,
- GdkSurfaceAttr *attributes)
-{
- GdkSurface *window;
- gboolean native;
- GdkEventMask event_mask;
-
- g_return_val_if_fail (attributes != NULL, NULL);
-
- if (parent != NULL && GDK_SURFACE_DESTROYED (parent))
- {
- g_warning ("gdk_surface_new(): parent is destroyed");
- return NULL;
- }
-
- window = _gdk_display_create_window (display);
-
- window->parent = parent;
-
- window->accept_focus = TRUE;
- window->focus_on_map = TRUE;
-
- window->x = attributes->x;
- window->y = attributes->y;
- window->width = (attributes->width > 1) ? (attributes->width) : (1);
- window->height = (attributes->height > 1) ? (attributes->height) : (1);
- window->alpha = 255;
-
- if (attributes->wclass == GDK_INPUT_ONLY)
- {
- /* Backwards compatiblity - we've always ignored
- * attributes->window_type for input-only windows
- * before
- */
- if (parent == NULL)
- window->window_type = GDK_SURFACE_TEMP;
- else
- window->window_type = GDK_SURFACE_CHILD;
- }
- else
- window->window_type = attributes->window_type;
-
- /* Sanity checks */
- switch (window->window_type)
- {
- case GDK_SURFACE_TOPLEVEL:
- case GDK_SURFACE_TEMP:
- if (parent != NULL && GDK_SURFACE_TYPE (parent) != GDK_SURFACE_ROOT)
- g_warning (G_STRLOC "Toplevel windows must be created as children of\n"
- "a window of type GDK_SURFACE_ROOT");
- break;
- case GDK_SURFACE_SUBSURFACE:
-#ifdef GDK_WINDOWING_WAYLAND
- if (!GDK_IS_WAYLAND_DISPLAY (display))
- {
- g_warning (G_STRLOC "Subsurface windows can only be used on Wayland");
- return NULL;
- }
-#endif
- break;
- case GDK_SURFACE_CHILD:
- if (GDK_SURFACE_TYPE (parent) == GDK_SURFACE_ROOT ||
- GDK_SURFACE_TYPE (parent) == GDK_SURFACE_FOREIGN)
- {
- g_warning (G_STRLOC "Child windows must not be created as children of\n"
- "a window of type GDK_SURFACE_ROOT or GDK_SURFACE_FOREIGN");
- return NULL;
- }
- break;
- default:
- g_warning (G_STRLOC "cannot make windows of type %d", window->window_type);
- return NULL;
- }
-
- window->event_mask = GDK_ALL_EVENTS_MASK;
-
- if (attributes->wclass == GDK_INPUT_OUTPUT)
- {
- window->input_only = FALSE;
- }
- else
- {
- window->input_only = TRUE;
- }
-
- native = FALSE;
-
- if (window->parent != NULL)
- window->parent->children = g_list_concat (&window->children_list_node, window->parent->children);
- else
- {
- GdkFrameClock *frame_clock = g_object_new (GDK_TYPE_FRAME_CLOCK_IDLE, NULL);
- gdk_surface_set_frame_clock (window, frame_clock);
- g_object_unref (frame_clock);
-
- native = TRUE; /* Always use native windows for toplevels */
- }
-
-#ifdef GDK_WINDOWING_WAYLAND
- if (window->window_type == GDK_SURFACE_SUBSURFACE)
- native = TRUE; /* Always use native windows for subsurfaces as well */
-#endif
-
- if (native)
- {
- event_mask = get_native_event_mask (window);
-
- /* Create the impl */
- _gdk_display_create_window_impl (display, window, parent, event_mask, attributes);
- window->impl_window = window;
- }
- else
- {
- window->impl_window = g_object_ref (window->parent->impl_window);
- window->impl = g_object_ref (window->impl_window->impl);
- }
-
- recompute_visible_regions (window, FALSE);
-
- g_signal_connect (display, "seat-removed", G_CALLBACK (seat_removed_cb), window);
-
- return window;
-}
-
-/**
- * gdk_surface_new_toplevel: (constructor)
- * @display: the display to create the window on
- * @width: width of new window
- * @height: height of new window
- *
- * Creates a new toplevel window. The window will be managed by the window
- * manager.
- *
- * Returns: (transfer full): the new #GdkSurface
- **/
-GdkSurface *
-gdk_surface_new_toplevel (GdkDisplay *display,
- gint width,
- gint height)
-{
- GdkSurfaceAttr attr;
-
- g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
-
- attr.wclass = GDK_INPUT_OUTPUT;
- attr.x = 0;
- attr.y = 0;
- attr.width = width;
- attr.height = height;
- attr.window_type = GDK_SURFACE_TOPLEVEL;
-
- return gdk_surface_new (display, NULL, &attr);
-}
-
-/**
- * gdk_surface_new_popup: (constructor)
- * @display: the display to create the window on
- * @position: position of the window on screen
- *
- * Creates a new toplevel popup window. The window will bypass window
- * management.
- *
- * Returns: (transfer full): the new #GdkSurface
- **/
-GdkSurface *
-gdk_surface_new_popup (GdkDisplay *display,
- const GdkRectangle *position)
-{
- GdkSurfaceAttr attr;
-
- g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
- g_return_val_if_fail (position != NULL, NULL);
-
- attr.wclass = GDK_INPUT_OUTPUT;
- attr.x = position->x;
- attr.y = position->y;
- attr.width = position->width;
- attr.height = position->height;
- attr.window_type = GDK_SURFACE_TEMP;
-
- return gdk_surface_new (display, NULL, &attr);
-}
-
-/**
- * gdk_surface_new_temp: (constructor)
- * @display: the display to create the window on
- *
- * Creates a new toplevel temporary window. The window will be
- * situated off-screen and not handle output.
- *
- * You most likely do not want to use this function.
- *
- * Returns: (transfer full): the new #GdkSurface
- **/
-GdkSurface *
-gdk_surface_new_temp (GdkDisplay *display)
-{
- GdkSurfaceAttr attr;
-
- g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
-
- attr.wclass = GDK_INPUT_ONLY;
- attr.x = -100;
- attr.y = -100;
- attr.width = 10;
- attr.height = 10;
- attr.window_type = GDK_SURFACE_TEMP;
-
- return gdk_surface_new (display, NULL, &attr);
-}
-
-/**
- * gdk_surface_new_child: (constructor)
- * @parent: the parent window
- * @position: placement of the window inside @parent
- *
- * Creates a new client-side child window.
- *
- * Returns: (transfer full): the new #GdkSurface
- **/
-GdkSurface *
-gdk_surface_new_child (GdkSurface *parent,
- const GdkRectangle *position)
-{
- GdkSurfaceAttr attr;
-
- g_return_val_if_fail (GDK_IS_SURFACE (parent), NULL);
-
- attr.wclass = GDK_INPUT_OUTPUT;
- attr.x = position->x;
- attr.y = position->y;
- attr.width = position->width;
- attr.height = position->height;
- attr.window_type = GDK_SURFACE_CHILD;
-
- return gdk_surface_new (gdk_surface_get_display (parent), parent, &attr);
-}
-
-static void
-update_pointer_info_foreach (GdkDisplay *display,
- GdkDevice *device,
- GdkPointerSurfaceInfo *pointer_info,
- gpointer user_data)
-{
- GdkSurface *window = user_data;
-
- if (pointer_info->window_under_pointer == window)
- {
- g_object_unref (pointer_info->window_under_pointer);
- pointer_info->window_under_pointer = NULL;
- }
-}
-
-static void
-window_remove_from_pointer_info (GdkSurface *window,
- GdkDisplay *display)
-{
- _gdk_display_pointer_info_foreach (display,
- update_pointer_info_foreach,
- window);
-}
-
-static void
-gdk_surface_free_current_paint (GdkSurface *window)
-{
- cairo_surface_destroy (window->current_paint.surface);
- window->current_paint.surface = NULL;
-
- cairo_region_destroy (window->current_paint.region);
- window->current_paint.region = NULL;
-
- window->current_paint.surface_needs_composite = FALSE;
-}
-
-/**
- * _gdk_surface_destroy_hierarchy:
- * @window: a #GdkSurface
- * @recursing: If %TRUE, then this is being called because a parent
- * was destroyed.
- * @recursing_native: If %TRUE, then this is being called because a native parent
- * was destroyed. This generally means that the call to the
- * windowing system to destroy the window can be omitted, since
- * it will be destroyed as a result of the parent being destroyed.
- * Unless @foreign_destroy.
- * @foreign_destroy: If %TRUE, the window or a parent was destroyed by some
- * external agency. The window has already been destroyed and no
- * windowing system calls should be made. (This may never happen
- * for some windowing systems.)
- *
- * Internal function to destroy a window. Like gdk_surface_destroy(),
- * but does not drop the reference count created by gdk_surface_new().
- **/
-static void
-_gdk_surface_destroy_hierarchy (GdkSurface *window,
- gboolean recursing,
- gboolean recursing_native,
- gboolean foreign_destroy)
-{
- GdkSurfaceImplClass *impl_class;
- GdkSurface *temp_window;
- GdkDisplay *display;
- GList *tmp;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- display = gdk_surface_get_display (window);
-
- switch (window->window_type)
- {
- default:
- g_assert_not_reached ();
- break;
-
- case GDK_SURFACE_ROOT:
- if (!gdk_display_is_closed (display))
- {
- g_error ("attempted to destroy root window");
- break;
- }
- /* else fall thru */
- case GDK_SURFACE_TOPLEVEL:
- case GDK_SURFACE_CHILD:
- case GDK_SURFACE_TEMP:
- case GDK_SURFACE_FOREIGN:
- case GDK_SURFACE_SUBSURFACE:
- if (window->window_type == GDK_SURFACE_FOREIGN && !foreign_destroy)
- {
- }
- else
- {
- if (window->parent)
- {
- if (window->parent->children)
- window->parent->children = g_list_remove_link (window->parent->children, &window->children_list_node);
-
- if (!recursing &&
- GDK_SURFACE_IS_MAPPED (window))
- {
- recompute_visible_regions (window, FALSE);
- gdk_surface_invalidate_in_parent (window);
- }
- }
-
- if (window->gl_paint_context)
- {
- /* Make sure to destroy if current */
- g_object_run_dispose (G_OBJECT (window->gl_paint_context));
- g_object_unref (window->gl_paint_context);
- window->gl_paint_context = NULL;
- }
-
- if (window->frame_clock)
- {
- g_object_run_dispose (G_OBJECT (window->frame_clock));
- gdk_surface_set_frame_clock (window, NULL);
- }
-
- gdk_surface_free_current_paint (window);
-
- if (window->window_type == GDK_SURFACE_FOREIGN)
- g_assert (window->children == NULL);
- else
- {
- tmp = window->children;
- window->children = NULL;
- /* No need to free children list, its all made up of in-struct nodes */
-
- while (tmp)
- {
- temp_window = tmp->data;
- tmp = tmp->next;
-
- if (temp_window)
- _gdk_surface_destroy_hierarchy (temp_window,
- TRUE,
- recursing_native || gdk_surface_has_impl (window),
- foreign_destroy);
- }
- }
-
- _gdk_surface_clear_update_area (window);
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- if (gdk_surface_has_impl (window))
- impl_class->destroy (window, recursing_native, foreign_destroy);
- else
- {
- /* hide to make sure we repaint and break grabs */
- gdk_surface_hide (window);
- }
-
- window->state |= GDK_SURFACE_STATE_WITHDRAWN;
- window->parent = NULL;
- window->destroyed = TRUE;
-
- window_remove_from_pointer_info (window, display);
-
- if (window->clip_region)
- {
- cairo_region_destroy (window->clip_region);
- window->clip_region = NULL;
- }
-
- g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_STATE]);
- }
- break;
- }
-}
-
-/**
- * _gdk_surface_destroy:
- * @window: a #GdkSurface
- * @foreign_destroy: If %TRUE, the window or a parent was destroyed by some
- * external agency. The window has already been destroyed and no
- * windowing system calls should be made. (This may never happen
- * for some windowing systems.)
- *
- * Internal function to destroy a window. Like gdk_surface_destroy(),
- * but does not drop the reference count created by gdk_surface_new().
- **/
-void
-_gdk_surface_destroy (GdkSurface *window,
- gboolean foreign_destroy)
-{
- _gdk_surface_destroy_hierarchy (window, FALSE, FALSE, foreign_destroy);
-}
-
-/**
- * gdk_surface_destroy:
- * @window: a #GdkSurface
- *
- * Destroys the window system resources associated with @window and decrements @window's
- * reference count. The window system resources for all children of @window are also
- * destroyed, but the children’s reference counts are not decremented.
- *
- * Note that a window will not be destroyed automatically when its reference count
- * reaches zero. You must call this function yourself before that happens.
- *
- **/
-void
-gdk_surface_destroy (GdkSurface *window)
-{
- _gdk_surface_destroy_hierarchy (window, FALSE, FALSE, FALSE);
- g_object_unref (window);
-}
-
-/**
- * gdk_surface_set_user_data:
- * @window: a #GdkSurface
- * @user_data: (allow-none) (type GObject.Object): user data
- *
- * For most purposes this function is deprecated in favor of
- * g_object_set_data(). However, for historical reasons GTK+ stores
- * the #GtkWidget that owns a #GdkSurface as user data on the
- * #GdkSurface. So, custom widget implementations should use
- * this function for that. If GTK+ receives an event for a #GdkSurface,
- * and the user data for the window is non-%NULL, GTK+ will assume the
- * user data is a #GtkWidget, and forward the event to that widget.
- *
- **/
-void
-gdk_surface_set_user_data (GdkSurface *window,
- gpointer user_data)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- window->user_data = user_data;
-}
-
-/**
- * gdk_surface_get_user_data:
- * @window: a #GdkSurface
- * @data: (out): return location for user data
- *
- * Retrieves the user data for @window, which is normally the widget
- * that @window belongs to. See gdk_surface_set_user_data().
- *
- **/
-void
-gdk_surface_get_user_data (GdkSurface *window,
- gpointer *data)
-{
- *data = window->user_data;
-}
-
-/**
- * gdk_surface_get_window_type:
- * @window: a #GdkSurface
- *
- * Gets the type of the window. See #GdkSurfaceType.
- *
- * Returns: type of window
- **/
-GdkSurfaceType
-gdk_surface_get_window_type (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), (GdkSurfaceType) -1);
-
- return GDK_SURFACE_TYPE (window);
-}
-
-/**
- * gdk_surface_get_display:
- * @window: a #GdkSurface
- *
- * Gets the #GdkDisplay associated with a #GdkSurface.
- *
- * Returns: (transfer none): the #GdkDisplay associated with @window
- **/
-GdkDisplay *
-gdk_surface_get_display (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- return window->display;
-}
-/**
- * gdk_surface_is_destroyed:
- * @window: a #GdkSurface
- *
- * Check to see if a window is destroyed..
- *
- * Returns: %TRUE if the window is destroyed
- **/
-gboolean
-gdk_surface_is_destroyed (GdkSurface *window)
-{
- return GDK_SURFACE_DESTROYED (window);
-}
-
-/**
- * gdk_surface_has_native:
- * @window: a #GdkSurface
- *
- * Checks whether the window has a native window or not.
- *
- * Returns: %TRUE if the @window has a native window, %FALSE otherwise.
- */
-gboolean
-gdk_surface_has_native (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- return window->parent == NULL || window->parent->impl != window->impl;
-}
-
-/**
- * gdk_surface_get_position:
- * @window: a #GdkSurface
- * @x: (out) (allow-none): X coordinate of window
- * @y: (out) (allow-none): Y coordinate of window
- *
- * Obtains the position of the window as reported in the
- * most-recently-processed #GdkEventConfigure. Contrast with
- * gdk_surface_get_geometry() which queries the X server for the
- * current window position, regardless of which events have been
- * received or processed.
- *
- * The position coordinates are relative to the window’s parent window.
- *
- **/
-void
-gdk_surface_get_position (GdkSurface *window,
- gint *x,
- gint *y)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (x)
- *x = window->x;
- if (y)
- *y = window->y;
-}
-
-/**
- * gdk_surface_get_parent:
- * @window: a #GdkSurface
- *
- * Obtains the parent of @window, as known to GDK. Does not query the
- * X server; thus this returns the parent as passed to gdk_surface_new(),
- * not the actual parent. This should never matter unless you’re using
- * Xlib calls mixed with GDK calls on the X11 platform. It may also
- * matter for toplevel windows, because the window manager may choose
- * to reparent them.
- *
- * Returns: (transfer none): parent of @window
- **/
-GdkSurface*
-gdk_surface_get_parent (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- if (gdk_surface_is_subsurface (window))
- return window->transient_for;
- else
- return window->parent;
-}
-
-/**
- * gdk_surface_get_toplevel:
- * @window: a #GdkSurface
- *
- * Gets the toplevel window that’s an ancestor of @window.
- *
- * Any window type but %GDK_SURFACE_CHILD is considered a
- * toplevel window, as is a %GDK_SURFACE_CHILD window that
- * has a root window as parent.
- *
- * Returns: (transfer none): the toplevel window containing @window
- **/
-GdkSurface *
-gdk_surface_get_toplevel (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- while (window->window_type == GDK_SURFACE_CHILD ||
- window->window_type == GDK_SURFACE_SUBSURFACE)
- {
- if (gdk_surface_is_toplevel (window))
- break;
- window = window->parent;
- }
-
- return window;
-}
-
-/**
- * gdk_surface_get_children:
- * @window: a #GdkSurface
- *
- * Gets the list of children of @window known to GDK.
- * This function only returns children created via GDK,
- * so for example it’s useless when used with the root window;
- * it only returns windows an application created itself.
- *
- * The returned list must be freed, but the elements in the
- * list need not be.
- *
- * Returns: (transfer container) (element-type GdkSurface):
- * list of child windows inside @window
- **/
-GList*
-gdk_surface_get_children (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- return g_list_copy (window->children);
-}
-
-/**
- * gdk_surface_peek_children:
- * @window: a #GdkSurface
- *
- * Like gdk_surface_get_children(), but does not copy the list of
- * children, so the list does not need to be freed.
- *
- * Returns: (transfer none) (element-type GdkSurface):
- * a reference to the list of child windows in @window
- **/
-GList *
-gdk_surface_peek_children (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- return window->children;
-}
-
-
-/**
- * gdk_surface_get_children_with_user_data:
- * @window: a #GdkSurface
- * @user_data: user data to look for
- *
- * Gets the list of children of @window known to GDK with a
- * particular @user_data set on it.
- *
- * The returned list must be freed, but the elements in the
- * list need not be.
- *
- * The list is returned in (relative) stacking order, i.e. the
- * lowest window is first.
- *
- * Returns: (transfer container) (element-type GdkSurface):
- * list of child windows inside @window
- **/
-GList *
-gdk_surface_get_children_with_user_data (GdkSurface *window,
- gpointer user_data)
-{
- GdkSurface *child;
- GList *res, *l;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- res = NULL;
- for (l = window->children; l != NULL; l = l->next)
- {
- child = l->data;
-
- if (child->user_data == user_data)
- res = g_list_prepend (res, child);
- }
-
- return res;
-}
-
-
-/**
- * gdk_surface_is_visible:
- * @window: a #GdkSurface
- *
- * Checks whether the window has been mapped (with gdk_surface_show() or
- * gdk_surface_show_unraised()).
- *
- * Returns: %TRUE if the window is mapped
- **/
-gboolean
-gdk_surface_is_visible (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- return GDK_SURFACE_IS_MAPPED (window);
-}
-
-/**
- * gdk_surface_is_viewable:
- * @window: a #GdkSurface
- *
- * Check if the window and all ancestors of the window are
- * mapped. (This is not necessarily "viewable" in the X sense, since
- * we only check as far as we have GDK window parents, not to the root
- * window.)
- *
- * Returns: %TRUE if the window is viewable
- **/
-gboolean
-gdk_surface_is_viewable (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- if (window->destroyed)
- return FALSE;
-
- return window->viewable;
-}
-
-/**
- * gdk_surface_get_state:
- * @window: a #GdkSurface
- *
- * Gets the bitwise OR of the currently active window state flags,
- * from the #GdkSurfaceState enumeration.
- *
- * Returns: window state bitfield
- **/
-GdkSurfaceState
-gdk_surface_get_state (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- return window->state;
-}
-
-static cairo_content_t
-gdk_surface_get_content (GdkSurface *window)
-{
- cairo_surface_t *surface;
- cairo_content_t content;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
-
- surface = gdk_surface_ref_impl_surface (window);
- content = cairo_surface_get_content (surface);
- cairo_surface_destroy (surface);
-
- return content;
-}
-
-static cairo_surface_t *
-gdk_surface_ref_impl_surface (GdkSurface *window)
-{
- return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->ref_cairo_surface (gdk_surface_get_impl_window (window));
-}
-
-GdkGLContext *
-gdk_surface_get_paint_gl_context (GdkSurface *window,
- GError **error)
-{
- GError *internal_error = NULL;
-
- if (GDK_DISPLAY_DEBUG_CHECK (window->display, GL_DISABLE))
- {
- g_set_error_literal (error, GDK_GL_ERROR,
- GDK_GL_ERROR_NOT_AVAILABLE,
- _("GL support disabled via GDK_DEBUG"));
- return NULL;
- }
-
- if (window->impl_window->gl_paint_context == NULL)
- {
- GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- if (impl_class->create_gl_context == NULL)
- {
- g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
- _("The current backend does not support OpenGL"));
- return NULL;
- }
-
- window->impl_window->gl_paint_context =
- impl_class->create_gl_context (window->impl_window,
- TRUE,
- NULL,
- &internal_error);
- }
-
- if (internal_error != NULL)
- {
- g_propagate_error (error, internal_error);
- g_clear_object (&(window->impl_window->gl_paint_context));
- return NULL;
- }
-
- gdk_gl_context_realize (window->impl_window->gl_paint_context, &internal_error);
- if (internal_error != NULL)
- {
- g_propagate_error (error, internal_error);
- g_clear_object (&(window->impl_window->gl_paint_context));
- return NULL;
- }
-
- return window->impl_window->gl_paint_context;
-}
-
-/**
- * gdk_surface_create_gl_context:
- * @window: a #GdkSurface
- * @error: return location for an error
- *
- * Creates a new #GdkGLContext matching the
- * framebuffer format to the visual of the #GdkSurface. The context
- * is disconnected from any particular window or surface.
- *
- * If the creation of the #GdkGLContext failed, @error will be set.
- *
- * Before using the returned #GdkGLContext, you will need to
- * call gdk_gl_context_make_current() or gdk_gl_context_realize().
- *
- * Returns: (transfer full): the newly created #GdkGLContext, or
- * %NULL on error
- **/
-GdkGLContext *
-gdk_surface_create_gl_context (GdkSurface *window,
- GError **error)
-{
- GdkGLContext *paint_context;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
- paint_context = gdk_surface_get_paint_gl_context (window, error);
- if (paint_context == NULL)
- return NULL;
-
- return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->create_gl_context (window->impl_window,
- FALSE,
- paint_context,
- error);
-}
-
-/**
- * gdk_surface_create_vulkan_context:
- * @window: a #GdkSurface
- * @error: return location for an error
- *
- * Creates a new #GdkVulkanContext for rendering on @window.
- *
- * If the creation of the #GdkVulkanContext failed, @error will be set.
- *
- * Returns: (transfer full): the newly created #GdkVulkanContext, or
- * %NULL on error
- **/
-GdkVulkanContext *
-gdk_surface_create_vulkan_context (GdkSurface *window,
- GError **error)
-{
- GdkDisplay *display;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
- if (GDK_DISPLAY_DEBUG_CHECK (window->display, VULKAN_DISABLE))
- {
- g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE,
- _("Vulkan support disabled via GDK_DEBUG"));
- return NULL;
- }
-
- display = gdk_surface_get_display (window);
-
- if (GDK_DISPLAY_GET_CLASS (display)->vk_extension_name == NULL)
- {
- g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
- "The %s backend has no Vulkan support.", G_OBJECT_TYPE_NAME (display));
- return FALSE;
- }
-
- return g_initable_new (GDK_DISPLAY_GET_CLASS (display)->vk_context_type,
- NULL,
- error,
- "window", window,
- NULL);
-}
-
-static void
-gdk_surface_begin_paint_internal (GdkSurface *window,
- const cairo_region_t *region)
-{
- GdkRectangle clip_box;
- GdkSurfaceImplClass *impl_class;
- double sx, sy;
- gboolean needs_surface;
- cairo_content_t surface_content;
-
- if (window->current_paint.surface != NULL)
- {
- g_warning ("A paint operation on the window is alredy in progress. "
- "This is not allowed.");
- return;
- }
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- needs_surface = TRUE;
- if (impl_class->begin_paint)
- needs_surface = impl_class->begin_paint (window);
-
- window->current_paint.region = cairo_region_copy (region);
- cairo_region_intersect (window->current_paint.region, window->clip_region);
- cairo_region_get_extents (window->current_paint.region, &clip_box);
-
- surface_content = gdk_surface_get_content (window);
-
- if (needs_surface)
- {
- window->current_paint.surface = gdk_surface_create_similar_surface (window,
- surface_content,
- MAX (clip_box.width, 1),
- MAX (clip_box.height, 1));
- sx = sy = 1;
- cairo_surface_get_device_scale (window->current_paint.surface, &sx, &sy);
- cairo_surface_set_device_offset (window->current_paint.surface, -clip_box.x*sx, -clip_box.y*sy);
- gdk_cairo_surface_mark_as_direct (window->current_paint.surface, window);
-
- window->current_paint.surface_needs_composite = TRUE;
- }
- else
- {
- window->current_paint.surface = gdk_surface_ref_impl_surface (window);
- window->current_paint.surface_needs_composite = FALSE;
- }
-
- if (!cairo_region_is_empty (window->current_paint.region))
- gdk_surface_clear_backing_region (window);
-}
-
-static void
-gdk_surface_end_paint_internal (GdkSurface *window)
-{
- GdkSurfaceImplClass *impl_class;
- cairo_t *cr;
-
- if (window->current_paint.surface == NULL)
- {
- g_warning (G_STRLOC": no preceding call to gdk_surface_begin_draw_frame(), see documentation");
- return;
- }
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- if (impl_class->end_paint)
- impl_class->end_paint (window);
-
- if (window->current_paint.surface_needs_composite)
- {
- cairo_surface_t *surface;
-
- surface = gdk_surface_ref_impl_surface (window);
- cr = cairo_create (surface);
-
- cairo_set_source_surface (cr, window->current_paint.surface, 0, 0);
- gdk_cairo_region (cr, window->current_paint.region);
- cairo_clip (cr);
-
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint (cr);
-
- cairo_destroy (cr);
-
- cairo_surface_flush (surface);
- cairo_surface_destroy (surface);
- }
-
- gdk_surface_free_current_paint (window);
-}
-
-/**
- * gdk_surface_begin_draw_frame:
- * @window: a #GdkSurface
- * @context: (allow-none): the context used to draw the frame
- * @region: a Cairo region
- *
- * Indicates that you are beginning the process of redrawing @region
- * on @window, and provides you with a #GdkDrawingContext.
- *
- * If @window is a top level #GdkSurface, backed by a native window
- * implementation, a backing store (offscreen buffer) large enough to
- * contain @region will be created. The backing store will be initialized
- * with the background color or background surface for @window. Then, all
- * drawing operations performed on @window will be diverted to the
- * backing store. When you call gdk_surface_end_frame(), the contents of
- * the backing store will be copied to @window, making it visible
- * on screen. Only the part of @window contained in @region will be
- * modified; that is, drawing operations are clipped to @region.
- *
- * The net result of all this is to remove flicker, because the user
- * sees the finished product appear all at once when you call
- * gdk_surface_end_draw_frame(). If you draw to @window directly without
- * calling gdk_surface_begin_draw_frame(), the user may see flicker
- * as individual drawing operations are performed in sequence.
- *
- * When using GTK+, the widget system automatically places calls to
- * gdk_surface_begin_draw_frame() and gdk_surface_end_draw_frame() around
- * emissions of the `GtkWidget::draw` signal. That is, if you’re
- * drawing the contents of the widget yourself, you can assume that the
- * widget has a cleared background, is already set as the clip region,
- * and already has a backing store. Therefore in most cases, application
- * code in GTK does not need to call gdk_surface_begin_draw_frame()
- * explicitly.
- *
- * Returns: (transfer none): a #GdkDrawingContext context that should be
- * used to draw the contents of the window; the returned context is owned
- * by GDK.
- */
-GdkDrawingContext *
-gdk_surface_begin_draw_frame (GdkSurface *window,
- GdkDrawContext *draw_context,
- const cairo_region_t *region)
-{
- GdkDrawingContext *context;
- cairo_region_t *real_region;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
- g_return_val_if_fail (gdk_surface_has_native (window), NULL);
- g_return_val_if_fail (gdk_surface_is_toplevel (window), NULL);
- g_return_val_if_fail (region != NULL, NULL);
- if (draw_context != NULL)
- {
- g_return_val_if_fail (GDK_IS_DRAW_CONTEXT (draw_context), NULL);
- g_return_val_if_fail (gdk_draw_context_get_window (draw_context) == window, NULL);
- }
-
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- if (window->drawing_context != NULL)
- {
- g_critical ("The window %p already has a drawing context. You cannot "
- "call gdk_surface_begin_draw_frame() without calling "
- "gdk_surface_end_draw_frame() first.", window);
- return NULL;
- }
-
- real_region = cairo_region_copy (region);
-
- if (draw_context)
- gdk_draw_context_begin_frame (draw_context, real_region);
- else
- gdk_surface_begin_paint_internal (window, real_region);
-
- context = g_object_new (GDK_TYPE_DRAWING_CONTEXT,
- "window", window,
- "paint-context", draw_context,
- "clip", real_region,
- NULL);
-
- /* Do not take a reference, to avoid creating cycles */
- window->drawing_context = context;
-
- cairo_region_destroy (real_region);
-
- return context;
-}
-
-/**
- * gdk_surface_end_draw_frame:
- * @window: a #GdkSurface
- * @context: the #GdkDrawingContext created by gdk_surface_begin_draw_frame()
- *
- * Indicates that the drawing of the contents of @window started with
- * gdk_surface_begin_frame() has been completed.
- *
- * This function will take care of destroying the #GdkDrawingContext.
- *
- * It is an error to call this function without a matching
- * gdk_surface_begin_frame() first.
- */
-void
-gdk_surface_end_draw_frame (GdkSurface *window,
- GdkDrawingContext *context)
-{
- GdkDrawContext *paint_context;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (GDK_IS_DRAWING_CONTEXT (context));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (window->drawing_context == NULL)
- {
- g_critical ("The window %p has no drawing context. You must call "
- "gdk_surface_begin_draw_frame() before calling "
- "gdk_surface_end_draw_frame().", window);
- return;
- }
- g_return_if_fail (window->drawing_context == context);
-
- paint_context = gdk_drawing_context_get_paint_context (context);
- if (paint_context)
- {
- cairo_region_t *clip = gdk_drawing_context_get_clip (context);
-
- gdk_draw_context_end_frame (paint_context,
- clip,
- window->active_update_area);
-
- cairo_region_destroy (clip);
- }
- else
- {
- gdk_surface_end_paint_internal (window);
- }
-
- window->drawing_context = NULL;
-
- g_object_unref (context);
-}
-
-/*< private >
- * gdk_surface_get_current_paint_region:
- * @window: a #GdkSurface
- *
- * Retrieves a copy of the current paint region.
- *
- * Returns: (transfer full): a Cairo region
- */
-cairo_region_t *
-gdk_surface_get_current_paint_region (GdkSurface *window)
-{
- cairo_region_t *region;
-
- if (window->impl_window->current_paint.region != NULL)
- {
- region = cairo_region_copy (window->impl_window->current_paint.region);
- cairo_region_translate (region, -window->abs_x, -window->abs_y);
- }
- else
- {
- region = cairo_region_copy (window->clip_region);
- }
-
- return region;
-}
-
-/*< private >
- * gdk_surface_get_drawing_context:
- * @window: a #GdkSurface
- *
- * Retrieves the #GdkDrawingContext associated to @window by
- * gdk_surface_begin_draw_frame().
- *
- * Returns: (transfer none) (nullable): a #GdkDrawingContext, if any is set
- */
-GdkDrawingContext *
-gdk_surface_get_drawing_context (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- return window->drawing_context;
-}
-
-/**
- * gdk_surface_get_clip_region:
- * @window: a #GdkSurface
- *
- * Computes the region of a window that potentially can be written
- * to by drawing primitives. This region may not take into account
- * other factors such as if the window is obscured by other windows,
- * but no area outside of this region will be affected by drawing
- * primitives.
- *
- * Returns: a #cairo_region_t. This must be freed with cairo_region_destroy()
- * when you are done.
- **/
-cairo_region_t*
-gdk_surface_get_clip_region (GdkSurface *window)
-{
- cairo_region_t *result;
-
- g_return_val_if_fail (GDK_SURFACE (window), NULL);
-
- result = cairo_region_copy (window->clip_region);
-
- if (window->current_paint.region != NULL)
- cairo_region_intersect (result, window->current_paint.region);
-
- return result;
-}
-
-/**
- * gdk_surface_get_visible_region:
- * @window: a #GdkSurface
- *
- * Computes the region of the @window that is potentially visible.
- * This does not necessarily take into account if the window is
- * obscured by other windows, but no area outside of this region
- * is visible.
- *
- * Returns: a #cairo_region_t. This must be freed with cairo_region_destroy()
- * when you are done.
- **/
-cairo_region_t *
-gdk_surface_get_visible_region (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- return cairo_region_copy (window->clip_region);
-}
-
-static void
-gdk_surface_clear_backing_region (GdkSurface *window)
-{
- cairo_t *cr;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- cr = cairo_create (window->current_paint.surface);
-
- cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
- gdk_cairo_region (cr, window->current_paint.region);
- cairo_fill (cr);
-
- cairo_destroy (cr);
-}
-
-/* This returns either the current working surface on the paint stack
- * or the actual impl surface of the window. This should not be used
- * from very many places: be careful! */
-static cairo_surface_t *
-ref_window_surface (GdkSurface *window)
-{
- if (window->impl_window->current_paint.surface)
- return cairo_surface_reference (window->impl_window->current_paint.surface);
- else
- return gdk_surface_ref_impl_surface (window);
-}
-
-/* This is used in places like gdk_cairo_set_source_window and
- * other places to take "screenshots" of windows. Thus, we allow
- * it to be used outside of a begin_paint / end_paint. */
-cairo_surface_t *
-_gdk_surface_ref_cairo_surface (GdkSurface *window)
-{
- cairo_surface_t *surface;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- surface = ref_window_surface (window);
-
- if (gdk_surface_has_impl (window))
- {
- return surface;
- }
- else
- {
- cairo_surface_t *subsurface;
- subsurface = cairo_surface_create_for_rectangle (surface,
- window->abs_x,
- window->abs_y,
- window->width,
- window->height);
- cairo_surface_destroy (surface);
- return subsurface;
- }
-}
-
-/* Code for dirty-region queueing
- */
-static GSList *update_windows = NULL;
-
-static inline gboolean
-gdk_surface_is_ancestor (GdkSurface *window,
- GdkSurface *ancestor)
-{
- while (window)
- {
- GdkSurface *parent = window->parent;
-
- if (parent == ancestor)
- return TRUE;
-
- window = parent;
- }
-
- return FALSE;
-}
-
-static void
-gdk_surface_add_update_window (GdkSurface *window)
-{
- GSList *tmp;
- GSList *prev = NULL;
- gboolean has_ancestor_in_list = FALSE;
-
- /* Check whether "window" is already in "update_windows" list.
- * It could be added during execution of gtk_widget_destroy() when
- * setting focus widget to NULL and redrawing old focus widget.
- * See bug 711552.
- */
- tmp = g_slist_find (update_windows, window);
- if (tmp != NULL)
- return;
-
- for (tmp = update_windows; tmp; tmp = tmp->next)
- {
- GdkSurface *parent = window->parent;
-
- /* check if tmp is an ancestor of "window"; if it is, set a
- * flag indicating that all following windows are either
- * children of "window" or from a differen hierarchy
- */
- if (!has_ancestor_in_list && gdk_surface_is_ancestor (window, tmp->data))
- has_ancestor_in_list = TRUE;
-
- /* insert in reverse stacking order when adding around siblings,
- * so processing updates properly paints over lower stacked windows
- */
- if (parent == GDK_SURFACE (tmp->data)->parent)
- {
- if (parent != NULL)
- {
- gint index = g_list_index (parent->children, window);
- for (; tmp && parent == GDK_SURFACE (tmp->data)->parent; tmp = tmp->next)
- {
- gint sibling_index = g_list_index (parent->children, tmp->data);
- if (index > sibling_index)
- break;
- prev = tmp;
- }
- }
- /* here, tmp got advanced past all lower stacked siblings */
- tmp = g_slist_prepend (tmp, g_object_ref (window));
- if (prev)
- prev->next = tmp;
- else
- update_windows = tmp;
- return;
- }
-
- /* if "window" has an ancestor in the list and tmp is one of
- * "window's" children, insert "window" before tmp
- */
- if (has_ancestor_in_list && gdk_surface_is_ancestor (tmp->data, window))
- {
- tmp = g_slist_prepend (tmp, g_object_ref (window));
-
- if (prev)
- prev->next = tmp;
- else
- update_windows = tmp;
- return;
- }
-
- /* if we're at the end of the list and had an ancestor it it,
- * append to the list
- */
- if (! tmp->next && has_ancestor_in_list)
- {
- tmp = g_slist_append (tmp, g_object_ref (window));
- return;
- }
-
- prev = tmp;
- }
-
- /* if all above checks failed ("window" is from a different
- * hierarchy than what is already in the list) or the list is
- * empty, prepend
- */
- update_windows = g_slist_prepend (update_windows, g_object_ref (window));
-}
-
-static void
-gdk_surface_remove_update_window (GdkSurface *window)
-{
- GSList *link;
-
- link = g_slist_find (update_windows, window);
- if (link != NULL)
- {
- update_windows = g_slist_delete_link (update_windows, link);
- g_object_unref (window);
- }
-}
-
-static gboolean
-gdk_surface_is_toplevel_frozen (GdkSurface *window)
-{
- GdkSurface *toplevel;
-
- toplevel = gdk_surface_get_toplevel (window);
-
- return toplevel->update_and_descendants_freeze_count > 0;
-}
-
-static void
-gdk_surface_schedule_update (GdkSurface *window)
-{
- GdkFrameClock *frame_clock;
-
- if (window &&
- (window->update_freeze_count ||
- gdk_surface_is_toplevel_frozen (window)))
- return;
-
- /* If there's no frame clock (a foreign window), then the invalid
- * region will just stick around unless gdk_surface_process_updates()
- * is called. */
- frame_clock = gdk_surface_get_frame_clock (window);
- if (frame_clock)
- gdk_frame_clock_request_phase (gdk_surface_get_frame_clock (window),
- GDK_FRAME_CLOCK_PHASE_PAINT);
-}
-
-void
-_gdk_surface_process_updates_recurse (GdkSurface *window,
- cairo_region_t *expose_region)
-{
- cairo_region_t *clipped_expose_region;
- GdkEvent *event;
-
- if (window->destroyed)
- return;
-
- clipped_expose_region = cairo_region_copy (expose_region);
-
- cairo_region_intersect (clipped_expose_region, window->clip_region);
-
- if (cairo_region_is_empty (clipped_expose_region))
- goto out;
-
- /* Paint the window before the children, clipped to the window region */
-
- event = gdk_event_new (GDK_EXPOSE);
- event->any.window = g_object_ref (window);
- event->any.send_event = FALSE;
- event->expose.count = 0;
- event->expose.region = cairo_region_reference (clipped_expose_region);
- cairo_region_get_extents (clipped_expose_region, &event->expose.area);
-
- _gdk_event_emit (event);
- gdk_event_free (event);
-
- out:
- cairo_region_destroy (clipped_expose_region);
-}
-
-
-static void
-gdk_surface_update_native_shapes (GdkSurface *window)
-{
- if (should_apply_clip_as_shape (window))
- apply_clip_as_shape (window);
-}
-
-/* Process and remove any invalid area on the native window by creating
- * expose events for the window and all non-native descendants.
- */
-static void
-gdk_surface_process_updates_internal (GdkSurface *window)
-{
- GdkSurfaceImplClass *impl_class;
- GdkSurface *toplevel;
-
- toplevel = gdk_surface_get_toplevel (window);
- if (toplevel->geometry_dirty)
- {
- gdk_surface_update_native_shapes (toplevel);
- toplevel->geometry_dirty = FALSE;
- }
-
- /* Ensure the window lives while updating it */
- g_object_ref (window);
-
- window->in_update = TRUE;
-
- /* If an update got queued during update processing, we can get a
- * window in the update queue that has an empty update_area.
- * just ignore it.
- */
- if (window->update_area)
- {
- g_assert (window->active_update_area == NULL); /* No reentrancy */
-
- window->active_update_area = window->update_area;
- window->update_area = NULL;
-
- if (gdk_surface_is_viewable (window))
- {
- cairo_region_t *expose_region;
-
- expose_region = cairo_region_copy (window->active_update_area);
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- /* Clip to part visible in impl window */
- cairo_region_intersect (expose_region, window->clip_region);
-
- if (impl_class->queue_antiexpose)
- impl_class->queue_antiexpose (window, expose_region);
-
- impl_class->process_updates_recurse (window, expose_region);
-
- gdk_surface_append_old_updated_area (window, window->active_update_area);
-
- cairo_region_destroy (expose_region);
- }
-
- cairo_region_destroy (window->active_update_area);
- window->active_update_area = NULL;
- }
-
- window->in_update = FALSE;
-
- g_object_unref (window);
-}
-
-static void
-gdk_surface_paint_on_clock (GdkFrameClock *clock,
- void *data)
-{
- GdkSurface *window;
-
- window = GDK_SURFACE (data);
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (window->impl_window == window);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- g_object_ref (window);
-
- if (window->update_area &&
- !window->update_freeze_count &&
- !gdk_surface_is_toplevel_frozen (window) &&
-
- /* Don't recurse into process_updates_internal, we'll
- * do the update later when idle instead. */
- !window->in_update)
- {
- gdk_surface_process_updates_internal (window);
- gdk_surface_remove_update_window (window);
- }
-
- g_object_unref (window);
-}
-
-static void
-gdk_surface_invalidate_rect_full (GdkSurface *window,
- const GdkRectangle *rect,
- gboolean invalidate_children)
-{
- GdkRectangle window_rect;
- cairo_region_t *region;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (window->input_only || !window->viewable)
- return;
-
- if (!rect)
- {
- window_rect.x = 0;
- window_rect.y = 0;
- window_rect.width = window->width;
- window_rect.height = window->height;
- rect = &window_rect;
- }
-
- region = cairo_region_create_rectangle (rect);
- gdk_surface_invalidate_region_full (window, region, invalidate_children);
- cairo_region_destroy (region);
-}
-
-/**
- * gdk_surface_invalidate_rect:
- * @window: a #GdkSurface
- * @rect: (allow-none): rectangle to invalidate or %NULL to invalidate the whole
- * window
- * @invalidate_children: whether to also invalidate child windows
- *
- * A convenience wrapper around gdk_surface_invalidate_region() which
- * invalidates a rectangular region. See
- * gdk_surface_invalidate_region() for details.
- **/
-void
-gdk_surface_invalidate_rect (GdkSurface *window,
- const GdkRectangle *rect,
- gboolean invalidate_children)
-{
- gdk_surface_invalidate_rect_full (window, rect, invalidate_children);
-}
-
-static void
-impl_window_add_update_area (GdkSurface *impl_window,
- cairo_region_t *region)
-{
- if (impl_window->update_area)
- cairo_region_union (impl_window->update_area, region);
- else
- {
- gdk_surface_add_update_window (impl_window);
- impl_window->update_area = cairo_region_copy (region);
- gdk_surface_schedule_update (impl_window);
- }
-}
-
-static void
-gdk_surface_invalidate_maybe_recurse_full (GdkSurface *window,
- const cairo_region_t *region,
- GdkSurfaceChildFunc child_func,
- gpointer user_data)
-{
- cairo_region_t *visible_region;
- cairo_rectangle_int_t r;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (window->input_only ||
- !window->viewable ||
- cairo_region_is_empty (region) ||
- window->window_type == GDK_SURFACE_ROOT)
- return;
-
- r.x = 0;
- r.y = 0;
-
- visible_region = cairo_region_copy (region);
-
- while (window != NULL &&
- !cairo_region_is_empty (visible_region))
- {
- r.width = window->width;
- r.height = window->height;
- cairo_region_intersect_rectangle (visible_region, &r);
-
- if (gdk_surface_has_impl (window))
- {
- impl_window_add_update_area (window, visible_region);
- break;
- }
- else
- {
- cairo_region_translate (visible_region,
- window->x, window->y);
- window = window->parent;
- }
- }
-
- cairo_region_destroy (visible_region);
-}
-
-/**
- * gdk_surface_invalidate_maybe_recurse:
- * @window: a #GdkSurface
- * @region: a #cairo_region_t
- * @child_func: (scope call) (allow-none): function to use to decide if to
- * recurse to a child, %NULL means never recurse.
- * @user_data: data passed to @child_func
- *
- * Adds @region to the update area for @window. The update area is the
- * region that needs to be redrawn, or “dirty region.”
- *
- * GDK will process all updates whenever the frame clock schedules a redraw,
- * so there’s no need to do forces redraws manually, you just need to
- * invalidate regions that you know should be redrawn.
- *
- * The @child_func parameter controls whether the region of
- * each child window that intersects @region will also be invalidated.
- * Only children for which @child_func returns #TRUE will have the area
- * invalidated.
- **/
-void
-gdk_surface_invalidate_maybe_recurse (GdkSurface *window,
- const cairo_region_t *region,
- GdkSurfaceChildFunc child_func,
- gpointer user_data)
-{
- gdk_surface_invalidate_maybe_recurse_full (window, region,
- child_func, user_data);
-}
-
-static gboolean
-true_predicate (GdkSurface *window,
- gpointer user_data)
-{
- return TRUE;
-}
-
-static void
-gdk_surface_invalidate_region_full (GdkSurface *window,
- const cairo_region_t *region,
- gboolean invalidate_children)
-{
- gdk_surface_invalidate_maybe_recurse_full (window, region,
- invalidate_children ?
- true_predicate : (gboolean (*) (GdkSurface *, gpointer))NULL,
- NULL);
-}
-
-/**
- * gdk_surface_invalidate_region:
- * @window: a #GdkSurface
- * @region: a #cairo_region_t
- * @invalidate_children: %TRUE to also invalidate child windows
- *
- * Adds @region to the update area for @window. The update area is the
- * region that needs to be redrawn, or “dirty region.”
- *
- * GDK will process all updates whenever the frame clock schedules a redraw,
- * so there’s no need to do forces redraws manually, you just need to
- * invalidate regions that you know should be redrawn.
- *
- * The @invalidate_children parameter controls whether the region of
- * each child window that intersects @region will also be invalidated.
- * If %FALSE, then the update area for child windows will remain
- * unaffected. See gdk_surface_invalidate_maybe_recurse if you need
- * fine grained control over which children are invalidated.
- **/
-void
-gdk_surface_invalidate_region (GdkSurface *window,
- const cairo_region_t *region,
- gboolean invalidate_children)
-{
- gdk_surface_invalidate_maybe_recurse (window, region,
- invalidate_children ?
- true_predicate : (gboolean (*) (GdkSurface *, gpointer))NULL,
- NULL);
-}
-
-/**
- * _gdk_surface_invalidate_for_expose:
- * @window: a #GdkSurface
- * @region: a #cairo_region_t
- *
- * Adds @region to the update area for @window.
- *
- * GDK will process all updates whenever the frame clock schedules a redraw,
- * so there’s no need to do forces redraws manually, you just need to
- * invalidate regions that you know should be redrawn.
- *
- * This version of invalidation is used when you recieve expose events
- * from the native window system. It exposes the native window, plus
- * any non-native child windows.
- **/
-void
-_gdk_surface_invalidate_for_expose (GdkSurface *window,
- cairo_region_t *region)
-{
- gdk_surface_invalidate_maybe_recurse_full (window, region,
- (gboolean (*) (GdkSurface *, gpointer))gdk_surface_has_no_impl,
- NULL);
-}
-
-
-/**
- * gdk_surface_get_update_area:
- * @window: a #GdkSurface
- *
- * Transfers ownership of the update area from @window to the caller
- * of the function. That is, after calling this function, @window will
- * no longer have an invalid/dirty region; the update area is removed
- * from @window and handed to you. If a window has no update area,
- * gdk_surface_get_update_area() returns %NULL. You are responsible for
- * calling cairo_region_destroy() on the returned region if it’s non-%NULL.
- *
- * Returns: the update area for @window
- **/
-cairo_region_t *
-gdk_surface_get_update_area (GdkSurface *window)
-{
- GdkSurface *impl_window;
- cairo_region_t *tmp_region, *to_remove;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- impl_window = gdk_surface_get_impl_window (window);
-
- if (impl_window->update_area)
- {
- tmp_region = cairo_region_copy (window->clip_region);
- /* Convert to impl coords */
- cairo_region_translate (tmp_region, window->abs_x, window->abs_y);
- cairo_region_intersect (tmp_region, impl_window->update_area);
-
- if (cairo_region_is_empty (tmp_region))
- {
- cairo_region_destroy (tmp_region);
- return NULL;
- }
- else
- {
- /* Convert from impl coords */
- cairo_region_translate (tmp_region, -window->abs_x, -window->abs_y);
-
- /* Don't remove any update area that is overlapped by sibling windows
- or child windows as these really need to be repainted independently of this window. */
- to_remove = cairo_region_copy (tmp_region);
-
- remove_child_area (window, FALSE, to_remove);
- remove_sibling_overlapped_area (window, to_remove);
-
- /* Remove from update_area */
- cairo_region_translate (to_remove, window->abs_x, window->abs_y);
- cairo_region_subtract (impl_window->update_area, to_remove);
-
- cairo_region_destroy (to_remove);
-
- if (cairo_region_is_empty (impl_window->update_area))
- {
- cairo_region_destroy (impl_window->update_area);
- impl_window->update_area = NULL;
-
- gdk_surface_remove_update_window ((GdkSurface *)impl_window);
- }
-
- return tmp_region;
- }
- }
- else
- return NULL;
-}
-
-/**
- * _gdk_surface_clear_update_area:
- * @window: a #GdkSurface.
- *
- * Internal function to clear the update area for a window. This
- * is called when the window is hidden or destroyed.
- **/
-void
-_gdk_surface_clear_update_area (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->update_area)
- {
- gdk_surface_remove_update_window (window);
-
- cairo_region_destroy (window->update_area);
- window->update_area = NULL;
- }
-}
-
-/**
- * gdk_surface_freeze_updates:
- * @window: a #GdkSurface
- *
- * Temporarily freezes a window such that it won’t receive expose
- * events. The window will begin receiving expose events again when
- * gdk_surface_thaw_updates() is called. If gdk_surface_freeze_updates()
- * has been called more than once, gdk_surface_thaw_updates() must be called
- * an equal number of times to begin processing exposes.
- **/
-void
-gdk_surface_freeze_updates (GdkSurface *window)
-{
- GdkSurface *impl_window;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl_window = gdk_surface_get_impl_window (window);
- impl_window->update_freeze_count++;
-}
-
-/**
- * gdk_surface_thaw_updates:
- * @window: a #GdkSurface
- *
- * Thaws a window frozen with gdk_surface_freeze_updates().
- **/
-void
-gdk_surface_thaw_updates (GdkSurface *window)
-{
- GdkSurface *impl_window;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl_window = gdk_surface_get_impl_window (window);
-
- g_return_if_fail (impl_window->update_freeze_count > 0);
-
- if (--impl_window->update_freeze_count == 0)
- gdk_surface_schedule_update (GDK_SURFACE (impl_window));
-}
-
-void
-gdk_surface_freeze_toplevel_updates (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (window->window_type != GDK_SURFACE_CHILD);
-
- window->update_and_descendants_freeze_count++;
- _gdk_frame_clock_freeze (gdk_surface_get_frame_clock (window));
-}
-
-void
-gdk_surface_thaw_toplevel_updates (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (window->window_type != GDK_SURFACE_CHILD);
- g_return_if_fail (window->update_and_descendants_freeze_count > 0);
-
- window->update_and_descendants_freeze_count--;
- _gdk_frame_clock_thaw (gdk_surface_get_frame_clock (window));
-
- gdk_surface_schedule_update (window);
-}
-
-/**
- * gdk_surface_constrain_size:
- * @geometry: a #GdkGeometry structure
- * @flags: a mask indicating what portions of @geometry are set
- * @width: desired width of window
- * @height: desired height of the window
- * @new_width: (out): location to store resulting width
- * @new_height: (out): location to store resulting height
- *
- * Constrains a desired width and height according to a
- * set of geometry hints (such as minimum and maximum size).
- */
-void
-gdk_surface_constrain_size (GdkGeometry *geometry,
- GdkSurfaceHints flags,
- gint width,
- gint height,
- gint *new_width,
- gint *new_height)
-{
- /* This routine is partially borrowed from fvwm.
- *
- * Copyright 1993, Robert Nation
- * You may use this code for any purpose, as long as the original
- * copyright remains in the source code and all documentation
- *
- * which in turn borrows parts of the algorithm from uwm
- */
- gint min_width = 0;
- gint min_height = 0;
- gint base_width = 0;
- gint base_height = 0;
- gint xinc = 1;
- gint yinc = 1;
- gint max_width = G_MAXINT;
- gint max_height = G_MAXINT;
-
-#define FLOOR(value, base) ( ((gint) ((value) / (base))) * (base) )
-
- if ((flags & GDK_HINT_BASE_SIZE) && (flags & GDK_HINT_MIN_SIZE))
- {
- base_width = geometry->base_width;
- base_height = geometry->base_height;
- min_width = geometry->min_width;
- min_height = geometry->min_height;
- }
- else if (flags & GDK_HINT_BASE_SIZE)
- {
- base_width = geometry->base_width;
- base_height = geometry->base_height;
- min_width = geometry->base_width;
- min_height = geometry->base_height;
- }
- else if (flags & GDK_HINT_MIN_SIZE)
- {
- base_width = geometry->min_width;
- base_height = geometry->min_height;
- min_width = geometry->min_width;
- min_height = geometry->min_height;
- }
-
- if (flags & GDK_HINT_MAX_SIZE)
- {
- max_width = geometry->max_width ;
- max_height = geometry->max_height;
- }
-
- if (flags & GDK_HINT_RESIZE_INC)
- {
- xinc = MAX (xinc, geometry->width_inc);
- yinc = MAX (yinc, geometry->height_inc);
- }
-
- /* clamp width and height to min and max values
- */
- width = CLAMP (width, min_width, max_width);
- height = CLAMP (height, min_height, max_height);
-
- /* shrink to base + N * inc
- */
- width = base_width + FLOOR (width - base_width, xinc);
- height = base_height + FLOOR (height - base_height, yinc);
-
- /* constrain aspect ratio, according to:
- *
- * width
- * min_aspect <= -------- <= max_aspect
- * height
- */
-
- if (flags & GDK_HINT_ASPECT &&
- geometry->min_aspect > 0 &&
- geometry->max_aspect > 0)
- {
- gint delta;
-
- if (geometry->min_aspect * height > width)
- {
- delta = FLOOR (height - width / geometry->min_aspect, yinc);
- if (height - delta >= min_height)
- height -= delta;
- else
- {
- delta = FLOOR (height * geometry->min_aspect - width, xinc);
- if (width + delta <= max_width)
- width += delta;
- }
- }
-
- if (geometry->max_aspect * height < width)
- {
- delta = FLOOR (width - height * geometry->max_aspect, xinc);
- if (width - delta >= min_width)
- width -= delta;
- else
- {
- delta = FLOOR (width / geometry->max_aspect - height, yinc);
- if (height + delta <= max_height)
- height += delta;
- }
- }
- }
-
-#undef FLOOR
-
- *new_width = width;
- *new_height = height;
-}
-
-/**
- * gdk_surface_get_device_position_double:
- * @window: a #GdkSurface.
- * @device: pointer #GdkDevice to query to.
- * @x: (out) (allow-none): return location for the X coordinate of @device, or %NULL.
- * @y: (out) (allow-none): return location for the Y coordinate of @device, or %NULL.
- * @mask: (out) (allow-none): return location for the modifier mask, or %NULL.
- *
- * Obtains the current device position in doubles and modifier state.
- * The position is given in coordinates relative to the upper left
- * corner of @window.
- *
- * Returns: (nullable) (transfer none): The window underneath @device
- * (as with gdk_device_get_window_at_position()), or %NULL if the
- * window is not known to GDK.
- **/
-GdkSurface *
-gdk_surface_get_device_position_double (GdkSurface *window,
- GdkDevice *device,
- double *x,
- double *y,
- GdkModifierType *mask)
-{
- gdouble tmp_x, tmp_y;
- GdkModifierType tmp_mask;
- gboolean normal_child;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
- g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
- g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
-
- tmp_x = tmp_y = 0;
- tmp_mask = 0;
- normal_child = GDK_SURFACE_IMPL_GET_CLASS (window->impl)->get_device_state (window,
- device,
- &tmp_x, &tmp_y,
- &tmp_mask);
- /* We got the coords on the impl, convert to the window */
- tmp_x -= window->abs_x;
- tmp_y -= window->abs_y;
-
- if (x)
- *x = tmp_x;
- if (y)
- *y = tmp_y;
- if (mask)
- *mask = tmp_mask;
-
- if (normal_child)
- return _gdk_surface_find_child_at (window, tmp_x, tmp_y);
- return NULL;
-}
-
-/**
- * gdk_surface_get_device_position:
- * @window: a #GdkSurface.
- * @device: pointer #GdkDevice to query to.
- * @x: (out) (allow-none): return location for the X coordinate of @device, or %NULL.
- * @y: (out) (allow-none): return location for the Y coordinate of @device, or %NULL.
- * @mask: (out) (allow-none): return location for the modifier mask, or %NULL.
- *
- * Obtains the current device position and modifier state.
- * The position is given in coordinates relative to the upper left
- * corner of @window.
- *
- * Use gdk_surface_get_device_position_double() if you need subpixel precision.
- *
- * Returns: (nullable) (transfer none): The window underneath @device
- * (as with gdk_device_get_window_at_position()), or %NULL if the
- * window is not known to GDK.
- **/
-GdkSurface *
-gdk_surface_get_device_position (GdkSurface *window,
- GdkDevice *device,
- gint *x,
- gint *y,
- GdkModifierType *mask)
-{
- gdouble tmp_x, tmp_y;
-
- window = gdk_surface_get_device_position_double (window, device,
- &tmp_x, &tmp_y, mask);
- if (x)
- *x = round (tmp_x);
- if (y)
- *y = round (tmp_y);
-
- return window;
-}
-
-static gboolean
-gdk_surface_raise_internal (GdkSurface *window)
-{
- GdkSurface *parent = window->parent;
- GdkSurfaceImplClass *impl_class;
- gboolean did_raise = FALSE;
-
- if (parent && parent->children->data != window)
- {
- parent->children = g_list_remove_link (parent->children, &window->children_list_node);
- parent->children = g_list_concat (&window->children_list_node, parent->children);
- did_raise = TRUE;
- }
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- /* Just do native raise for toplevels */
- if (gdk_surface_has_impl (window))
- impl_class->raise (window);
-
- return did_raise;
-}
-
-/* Returns TRUE If the native window was mapped or unmapped */
-static gboolean
-set_viewable (GdkSurface *w,
- gboolean val)
-{
- GdkSurface *child;
- GList *l;
-
- if (w->viewable == val)
- return FALSE;
-
- w->viewable = val;
-
- if (val)
- recompute_visible_regions (w, FALSE);
-
- for (l = w->children; l != NULL; l = l->next)
- {
- child = l->data;
-
- if (GDK_SURFACE_IS_MAPPED (child))
- set_viewable (child, val);
- }
-
- return FALSE;
-}
-
-/* Returns TRUE If the native window was mapped or unmapped */
-gboolean
-_gdk_surface_update_viewable (GdkSurface *window)
-{
- gboolean viewable;
-
- if (window->window_type == GDK_SURFACE_FOREIGN ||
- window->window_type == GDK_SURFACE_ROOT)
- viewable = TRUE;
- else if (gdk_surface_is_toplevel (window) ||
- window->parent->viewable)
- viewable = GDK_SURFACE_IS_MAPPED (window);
- else
- viewable = FALSE;
-
- return set_viewable (window, viewable);
-}
-
-static void
-gdk_surface_show_internal (GdkSurface *window, gboolean raise)
-{
- GdkSurfaceImplClass *impl_class;
- gboolean was_mapped, was_viewable;
- gboolean did_show, did_raise = FALSE;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->destroyed)
- return;
-
- was_mapped = GDK_SURFACE_IS_MAPPED (window);
- was_viewable = window->viewable;
-
- if (raise)
- {
- /* Keep children in (reverse) stacking order */
- did_raise = gdk_surface_raise_internal (window);
- }
-
- if (gdk_surface_has_impl (window))
- {
- if (!was_mapped)
- gdk_synthesize_window_state (window,
- GDK_SURFACE_STATE_WITHDRAWN,
- 0);
- }
- else
- {
- window->state = 0;
- g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_STATE]);
- }
-
- did_show = _gdk_surface_update_viewable (window);
-
- /* If it was already viewable the backend show op won't be called, call it
- again to ensure things happen right if the mapped tracking was not right
- for e.g. a foreign window.
- Dunno if this is strictly needed but its what happened pre-csw.
- Also show if not done by gdk_surface_update_viewable. */
- if (gdk_surface_has_impl (window) && (was_viewable || !did_show))
- {
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- impl_class->show (window, !did_show ? was_mapped : TRUE);
- }
-
- if (!was_mapped && !gdk_surface_has_impl (window))
- {
- if (window->event_mask & GDK_STRUCTURE_MASK)
- _gdk_make_event (window, GDK_MAP, NULL, FALSE);
-
- if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
- _gdk_make_event (window, GDK_MAP, NULL, FALSE);
- }
-
- if (!was_mapped || did_raise)
- {
- recompute_visible_regions (window, FALSE);
-
- if (gdk_surface_is_viewable (window))
- gdk_surface_invalidate_rect_full (window, NULL, TRUE);
- }
-}
-
-/**
- * gdk_surface_show_unraised:
- * @window: a #GdkSurface
- *
- * Shows a #GdkSurface onscreen, but does not modify its stacking
- * order. In contrast, gdk_surface_show() will raise the window
- * to the top of the window stack.
- *
- * On the X11 platform, in Xlib terms, this function calls
- * XMapWindow() (it also updates some internal GDK state, which means
- * that you can’t really use XMapWindow() directly on a GDK window).
- */
-void
-gdk_surface_show_unraised (GdkSurface *window)
-{
- gdk_surface_show_internal (window, FALSE);
-}
-
-/**
- * gdk_surface_raise:
- * @window: a #GdkSurface
- *
- * Raises @window to the top of the Z-order (stacking order), so that
- * other windows with the same parent window appear below @window.
- * This is true whether or not the windows are visible.
- *
- * If @window is a toplevel, the window manager may choose to deny the
- * request to move the window in the Z-order, gdk_surface_raise() only
- * requests the restack, does not guarantee it.
- */
-void
-gdk_surface_raise (GdkSurface *window)
-{
- gboolean did_raise;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->destroyed)
- return;
-
- /* Keep children in (reverse) stacking order */
- did_raise = gdk_surface_raise_internal (window);
-
- if (did_raise &&
- !gdk_surface_is_toplevel (window) &&
- gdk_surface_is_viewable (window) &&
- !window->input_only)
- gdk_surface_invalidate_region_full (window, window->clip_region, TRUE);
-}
-
-static void
-gdk_surface_lower_internal (GdkSurface *window)
-{
- GdkSurface *parent = window->parent;
- GdkSurfaceImplClass *impl_class;
-
- if (parent)
- {
- parent->children = g_list_remove_link (parent->children, &window->children_list_node);
- parent->children = g_list_concat (parent->children, &window->children_list_node);
- }
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- /* Just do native lower for toplevels */
- if (gdk_surface_has_impl (window))
- impl_class->lower (window);
-}
-
-static void
-gdk_surface_invalidate_in_parent (GdkSurface *private)
-{
- GdkRectangle r, child;
-
- if (gdk_surface_is_toplevel (private))
- return;
-
- /* get the visible rectangle of the parent */
- r.x = r.y = 0;
- r.width = private->parent->width;
- r.height = private->parent->height;
-
- child.x = private->x;
- child.y = private->y;
- child.width = private->width;
- child.height = private->height;
- gdk_rectangle_intersect (&r, &child, &r);
-
- gdk_surface_invalidate_rect_full (private->parent, &r, TRUE);
-}
-
-
-/**
- * gdk_surface_lower:
- * @window: a #GdkSurface
- *
- * Lowers @window to the bottom of the Z-order (stacking order), so that
- * other windows with the same parent window appear above @window.
- * This is true whether or not the other windows are visible.
- *
- * If @window is a toplevel, the window manager may choose to deny the
- * request to move the window in the Z-order, gdk_surface_lower() only
- * requests the restack, does not guarantee it.
- *
- * Note that gdk_surface_show() raises the window again, so don’t call this
- * function before gdk_surface_show(). (Try gdk_surface_show_unraised().)
- */
-void
-gdk_surface_lower (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->destroyed)
- return;
-
- /* Keep children in (reverse) stacking order */
- gdk_surface_lower_internal (window);
-
- gdk_surface_invalidate_in_parent (window);
-}
-
-/**
- * gdk_surface_restack:
- * @window: a #GdkSurface
- * @sibling: (allow-none): a #GdkSurface that is a sibling of @window, or %NULL
- * @above: a boolean
- *
- * Changes the position of @window in the Z-order (stacking order), so that
- * it is above @sibling (if @above is %TRUE) or below @sibling (if @above is
- * %FALSE).
- *
- * If @sibling is %NULL, then this either raises (if @above is %TRUE) or
- * lowers the window.
- *
- * If @window is a toplevel, the window manager may choose to deny the
- * request to move the window in the Z-order, gdk_surface_restack() only
- * requests the restack, does not guarantee it.
- */
-void
-gdk_surface_restack (GdkSurface *window,
- GdkSurface *sibling,
- gboolean above)
-{
- GdkSurfaceImplClass *impl_class;
- GdkSurface *parent;
- GList *sibling_link;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (sibling == NULL || GDK_IS_SURFACE (sibling));
-
- if (window->destroyed)
- return;
-
- if (sibling == NULL)
- {
- if (above)
- gdk_surface_raise (window);
- else
- gdk_surface_lower (window);
- return;
- }
-
- if (gdk_surface_is_toplevel (window))
- {
- g_return_if_fail (gdk_surface_is_toplevel (sibling));
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- impl_class->restack_toplevel (window, sibling, above);
- return;
- }
-
- parent = window->parent;
- if (parent)
- {
- sibling_link = g_list_find (parent->children, sibling);
- g_return_if_fail (sibling_link != NULL);
- if (sibling_link == NULL)
- return;
-
- parent->children = g_list_remove_link (parent->children, &window->children_list_node);
- if (above)
- parent->children = list_insert_link_before (parent->children,
- sibling_link,
- &window->children_list_node);
- else
- parent->children = list_insert_link_before (parent->children,
- sibling_link->next,
- &window->children_list_node);
- }
-
- gdk_surface_invalidate_in_parent (window);
-}
-
-
-/**
- * gdk_surface_show:
- * @window: a #GdkSurface
- *
- * Like gdk_surface_show_unraised(), but also raises the window to the
- * top of the window stack (moves the window to the front of the
- * Z-order).
- *
- * This function maps a window so it’s visible onscreen. Its opposite
- * is gdk_surface_hide().
- *
- * When implementing a #GtkWidget, you should call this function on the widget's
- * #GdkSurface as part of the “map” method.
- */
-void
-gdk_surface_show (GdkSurface *window)
-{
- gdk_surface_show_internal (window, TRUE);
-}
-
-/**
- * gdk_surface_hide:
- * @window: a #GdkSurface
- *
- * For toplevel windows, withdraws them, so they will no longer be
- * known to the window manager; for all windows, unmaps them, so
- * they won’t be displayed. Normally done automatically as
- * part of gtk_widget_hide().
- */
-void
-gdk_surface_hide (GdkSurface *window)
-{
- GdkSurfaceImplClass *impl_class;
- gboolean was_mapped, did_hide;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->destroyed)
- return;
-
- was_mapped = GDK_SURFACE_IS_MAPPED (window);
-
- if (gdk_surface_has_impl (window))
- {
-
- if (GDK_SURFACE_IS_MAPPED (window))
- gdk_synthesize_window_state (window,
- 0,
- GDK_SURFACE_STATE_WITHDRAWN);
- }
- else if (was_mapped)
- {
- window->state = GDK_SURFACE_STATE_WITHDRAWN;
- g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_STATE]);
- }
-
- if (was_mapped)
- {
- GdkDisplay *display;
- GdkSeat *seat;
- GList *devices, *d;
-
- /* May need to break grabs on children */
- display = gdk_surface_get_display (window);
- seat = gdk_display_get_default_seat (display);
-
- devices = gdk_seat_get_slaves (seat, GDK_SEAT_CAPABILITY_ALL);
- devices = g_list_prepend (devices, gdk_seat_get_keyboard (seat));
- devices = g_list_prepend (devices, gdk_seat_get_pointer (seat));
-
- for (d = devices; d; d = d->next)
- {
- GdkDevice *device = d->data;
-
- if (_gdk_display_end_device_grab (display,
- device,
- _gdk_display_get_next_serial (display),
- window,
- TRUE))
- {
-G_GNUC_BEGIN_IGNORE_DEPRECATIONS
- gdk_device_ungrab (device, GDK_CURRENT_TIME);
-G_GNUC_END_IGNORE_DEPRECATIONS
- }
- }
-
- g_list_free (devices);
- }
-
- did_hide = _gdk_surface_update_viewable (window);
-
- /* Hide foreign window as those are not handled by update_viewable. */
- if (gdk_surface_has_impl (window) && (!did_hide))
- {
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- impl_class->hide (window);
- }
-
- gdk_surface_clear_old_updated_area (window);
- recompute_visible_regions (window, FALSE);
-
- if (was_mapped && !gdk_surface_has_impl (window))
- {
- if (window->event_mask & GDK_STRUCTURE_MASK)
- _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
-
- if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
- _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
- }
-
- /* Invalidate the rect */
- if (was_mapped)
- gdk_surface_invalidate_in_parent (window);
-}
-
-/**
- * gdk_surface_withdraw:
- * @window: a toplevel #GdkSurface
- *
- * Withdraws a window (unmaps it and asks the window manager to forget about it).
- * This function is not really useful as gdk_surface_hide() automatically
- * withdraws toplevel windows before hiding them.
- **/
-void
-gdk_surface_withdraw (GdkSurface *window)
-{
- GdkSurfaceImplClass *impl_class;
- gboolean was_mapped;
- GdkGLContext *current_context;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->destroyed)
- return;
-
- was_mapped = GDK_SURFACE_IS_MAPPED (window);
-
- if (gdk_surface_has_impl (window))
- {
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- impl_class->withdraw (window);
-
- if (was_mapped)
- {
- if (window->event_mask & GDK_STRUCTURE_MASK)
- _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
-
- if (window->parent && window->parent->event_mask & GDK_SUBSTRUCTURE_MASK)
- _gdk_make_event (window, GDK_UNMAP, NULL, FALSE);
- }
-
- current_context = gdk_gl_context_get_current ();
- if (current_context != NULL && gdk_gl_context_get_window (current_context) == window)
- gdk_gl_context_clear_current ();
-
- recompute_visible_regions (window, FALSE);
- gdk_surface_clear_old_updated_area (window);
- }
-}
-
-/**
- * gdk_surface_set_events:
- * @window: a #GdkSurface
- * @event_mask: event mask for @window
- *
- * The event mask for a window determines which events will be reported
- * for that window from all master input devices. For example, an event mask
- * including #GDK_BUTTON_PRESS_MASK means the window should report button
- * press events. The event mask is the bitwise OR of values from the
- * #GdkEventMask enumeration.
- *
- * See the [input handling overview][event-masks] for details.
- **/
-void
-gdk_surface_set_events (GdkSurface *window,
- GdkEventMask event_mask)
-{
- GdkSurfaceImplClass *impl_class;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->destroyed)
- return;
-
- window->event_mask = event_mask;
-
- if (gdk_surface_has_impl (window))
- {
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- impl_class->set_events (window,
- get_native_event_mask (window));
- }
-
-}
-
-/**
- * gdk_surface_get_events:
- * @window: a #GdkSurface
- *
- * Gets the event mask for @window for all master input devices. See
- * gdk_surface_set_events().
- *
- * Returns: event mask for @window
- **/
-GdkEventMask
-gdk_surface_get_events (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
-
- if (window->destroyed)
- return 0;
-
- return window->event_mask;
-}
-
-/**
- * gdk_surface_set_device_events:
- * @window: a #GdkSurface
- * @device: #GdkDevice to enable events for.
- * @event_mask: event mask for @window
- *
- * Sets the event mask for a given device (Normally a floating device, not
- * attached to any visible pointer) to @window. For example, an event mask
- * including #GDK_BUTTON_PRESS_MASK means the window should report button
- * press events. The event mask is the bitwise OR of values from the
- * #GdkEventMask enumeration.
- *
- * See the [input handling overview][event-masks] for details.
- **/
-void
-gdk_surface_set_device_events (GdkSurface *window,
- GdkDevice *device,
- GdkEventMask event_mask)
-{
- GdkEventMask device_mask;
- GdkSurface *native;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (GDK_IS_DEVICE (device));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (G_UNLIKELY (!window->device_events))
- window->device_events = g_hash_table_new (NULL, NULL);
-
- if (event_mask == 0)
- {
- /* FIXME: unsetting events on a master device
- * would restore window->event_mask
- */
- g_hash_table_remove (window->device_events, device);
- }
- else
- g_hash_table_insert (window->device_events, device,
- GINT_TO_POINTER (event_mask));
-
- native = gdk_surface_get_toplevel (window);
-
- device_mask = get_native_device_event_mask (window, device);
- GDK_DEVICE_GET_CLASS (device)->select_window_events (device, native, device_mask);
-}
-
-/**
- * gdk_surface_get_device_events:
- * @window: a #GdkSurface.
- * @device: a #GdkDevice.
- *
- * Returns the event mask for @window corresponding to an specific device.
- *
- * Returns: device event mask for @window
- **/
-GdkEventMask
-gdk_surface_get_device_events (GdkSurface *window,
- GdkDevice *device)
-{
- GdkEventMask mask;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
- g_return_val_if_fail (GDK_IS_DEVICE (device), 0);
-
- if (GDK_SURFACE_DESTROYED (window))
- return 0;
-
- if (!window->device_events)
- return 0;
-
- mask = GPOINTER_TO_INT (g_hash_table_lookup (window->device_events, device));
-
- /* FIXME: device could be controlled by window->event_mask */
-
- return mask;
-}
-
-static void
-gdk_surface_move_resize_toplevel (GdkSurface *window,
- gboolean with_move,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- cairo_region_t *old_region, *new_region;
- GdkSurfaceImplClass *impl_class;
- gboolean expose;
- gboolean is_resize;
-
- expose = FALSE;
- old_region = NULL;
-
- is_resize = (width != -1) || (height != -1);
-
- if (gdk_surface_is_viewable (window) &&
- !window->input_only)
- {
- expose = TRUE;
- old_region = cairo_region_copy (window->clip_region);
- }
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- impl_class->move_resize (window, with_move, x, y, width, height);
-
- /* Avoid recomputing for pure toplevel moves, for performance reasons */
- if (is_resize)
- recompute_visible_regions (window, FALSE);
-
- if (expose)
- {
- new_region = cairo_region_copy (window->clip_region);
-
- /* This is the newly exposed area (due to any resize),
- * X will expose it, but lets do that without the roundtrip
- */
- cairo_region_subtract (new_region, old_region);
- gdk_surface_invalidate_region_full (window, new_region, TRUE);
-
- cairo_region_destroy (old_region);
- cairo_region_destroy (new_region);
- }
-}
-
-
-static void
-gdk_surface_move_resize_internal (GdkSurface *window,
- gboolean with_move,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- cairo_region_t *old_region, *new_region;
- gboolean expose;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->destroyed)
- return;
-
- if (gdk_surface_is_toplevel (window))
- {
- gdk_surface_move_resize_toplevel (window, with_move, x, y, width, height);
- return;
- }
-
- if (width == 0)
- width = 1;
- if (height == 0)
- height = 1;
-
- /* Bail early if no change */
- if (window->width == width &&
- window->height == height &&
- (!with_move ||
- (window->x == x &&
- window->y == y)))
- return;
-
- /* Handle child windows */
-
- expose = FALSE;
- old_region = NULL;
-
- if (gdk_surface_is_viewable (window) &&
- !window->input_only)
- {
- GdkRectangle r;
-
- expose = TRUE;
-
- r.x = window->x;
- r.y = window->y;
- r.width = window->width;
- r.height = window->height;
-
- old_region = cairo_region_create_rectangle (&r);
- }
-
- /* Set the new position and size */
- if (with_move)
- {
- window->x = x;
- window->y = y;
- }
- if (!(width < 0 && height < 0))
- {
- window->width = width;
- window->height = height;
- }
-
- recompute_visible_regions (window, FALSE);
-
- if (expose)
- {
- GdkRectangle r;
-
- r.x = window->x;
- r.y = window->y;
- r.width = window->width;
- r.height = window->height;
-
- new_region = cairo_region_create_rectangle (&r);
-
- cairo_region_union (new_region, old_region);
-
- gdk_surface_invalidate_region_full (window->parent, new_region, TRUE);
-
- cairo_region_destroy (old_region);
- cairo_region_destroy (new_region);
- }
-}
-
-
-
-/**
- * gdk_surface_move:
- * @window: a #GdkSurface
- * @x: X coordinate relative to window’s parent
- * @y: Y coordinate relative to window’s parent
- *
- * Repositions a window relative to its parent window.
- * For toplevel windows, window managers may ignore or modify the move;
- * you should probably use gtk_window_move() on a #GtkWindow widget
- * anyway, instead of using GDK functions. For child windows,
- * the move will reliably succeed.
- *
- * If you’re also planning to resize the window, use gdk_surface_move_resize()
- * to both move and resize simultaneously, for a nicer visual effect.
- **/
-void
-gdk_surface_move (GdkSurface *window,
- gint x,
- gint y)
-{
- gdk_surface_move_resize_internal (window, TRUE, x, y, -1, -1);
-}
-
-/**
- * gdk_surface_resize:
- * @window: a #GdkSurface
- * @width: new width of the window
- * @height: new height of the window
- *
- * Resizes @window; for toplevel windows, asks the window manager to resize
- * the window. The window manager may not allow the resize. When using GTK+,
- * use gtk_window_resize() instead of this low-level GDK function.
- *
- * Windows may not be resized below 1x1.
- *
- * If you’re also planning to move the window, use gdk_surface_move_resize()
- * to both move and resize simultaneously, for a nicer visual effect.
- **/
-void
-gdk_surface_resize (GdkSurface *window,
- gint width,
- gint height)
-{
- gdk_surface_move_resize_internal (window, FALSE, 0, 0, width, height);
-}
-
-
-/**
- * gdk_surface_move_resize:
- * @window: a #GdkSurface
- * @x: new X position relative to window’s parent
- * @y: new Y position relative to window’s parent
- * @width: new width
- * @height: new height
- *
- * Equivalent to calling gdk_surface_move() and gdk_surface_resize(),
- * except that both operations are performed at once, avoiding strange
- * visual effects. (i.e. the user may be able to see the window first
- * move, then resize, if you don’t use gdk_surface_move_resize().)
- **/
-void
-gdk_surface_move_resize (GdkSurface *window,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- gdk_surface_move_resize_internal (window, TRUE, x, y, width, height);
-}
-
-/**
- * gdk_surface_move_to_rect:
- * @window: the #GdkSurface to move
- * @rect: (not nullable): the destination #GdkRectangle to align @window with
- * @rect_anchor: the point on @rect to align with @window's anchor point
- * @window_anchor: the point on @window to align with @rect's anchor point
- * @anchor_hints: positioning hints to use when limited on space
- * @rect_anchor_dx: horizontal offset to shift @window, i.e. @rect's anchor
- * point
- * @rect_anchor_dy: vertical offset to shift @window, i.e. @rect's anchor point
- *
- * Moves @window to @rect, aligning their anchor points.
- *
- * @rect is relative to the top-left corner of the window that @window is
- * transient for. @rect_anchor and @window_anchor determine anchor points on
- * @rect and @window to pin together. @rect's anchor point can optionally be
- * offset by @rect_anchor_dx and @rect_anchor_dy, which is equivalent to
- * offsetting the position of @window.
- *
- * @anchor_hints determines how @window will be moved if the anchor points cause
- * it to move off-screen. For example, %GDK_ANCHOR_FLIP_X will replace
- * %GDK_GRAVITY_NORTH_WEST with %GDK_GRAVITY_NORTH_EAST and vice versa if
- * @window extends beyond the left or right edges of the monitor.
- *
- * Connect to the #GdkSurface::moved-to-rect signal to find out how it was
- * actually positioned.
- *
- * Stability: Private
- */
-void
-gdk_surface_move_to_rect (GdkSurface *window,
- const GdkRectangle *rect,
- GdkGravity rect_anchor,
- GdkGravity window_anchor,
- GdkAnchorHints anchor_hints,
- gint rect_anchor_dx,
- gint rect_anchor_dy)
-{
- GdkSurfaceImplClass *impl_class;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (window->transient_for);
- g_return_if_fail (rect);
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- impl_class->move_to_rect (window,
- rect,
- rect_anchor,
- window_anchor,
- anchor_hints,
- rect_anchor_dx,
- rect_anchor_dy);
-}
-
-/**
- * gdk_surface_scroll:
- * @window: a #GdkSurface
- * @dx: Amount to scroll in the X direction
- * @dy: Amount to scroll in the Y direction
- *
- * Scroll the contents of @window, both pixels and children, by the
- * given amount. @window itself does not move. Portions of the window
- * that the scroll operation brings in from offscreen areas are
- * invalidated. The invalidated region may be bigger than what would
- * strictly be necessary.
- *
- * For X11, a minimum area will be invalidated if the window has no
- * subwindows, or if the edges of the window’s parent do not extend
- * beyond the edges of the window. In other cases, a multi-step process
- * is used to scroll the window which may produce temporary visual
- * artifacts and unnecessary invalidations.
- **/
-void
-gdk_surface_scroll (GdkSurface *window,
- gint dx,
- gint dy)
-{
- GList *tmp_list;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (dx == 0 && dy == 0)
- return;
-
- if (window->destroyed)
- return;
-
- /* First move all child windows, without causing invalidation */
-
- tmp_list = window->children;
- while (tmp_list)
- {
- GdkSurface *child = GDK_SURFACE (tmp_list->data);
-
- /* Just update the positions, the bits will move with the copy */
- child->x += dx;
- child->y += dy;
-
- tmp_list = tmp_list->next;
- }
-
- recompute_visible_regions (window, TRUE);
-
- gdk_surface_invalidate_rect_full (window, NULL, TRUE);
-}
-
-/**
- * gdk_surface_move_region:
- * @window: a #GdkSurface
- * @region: The #cairo_region_t to move
- * @dx: Amount to move in the X direction
- * @dy: Amount to move in the Y direction
- *
- * Move the part of @window indicated by @region by @dy pixels in the Y
- * direction and @dx pixels in the X direction. The portions of @region
- * that not covered by the new position of @region are invalidated.
- *
- * Child windows are not moved.
- */
-void
-gdk_surface_move_region (GdkSurface *window,
- const cairo_region_t *region,
- gint dx,
- gint dy)
-{
- cairo_region_t *expose_area;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (region != NULL);
-
- if (dx == 0 && dy == 0)
- return;
-
- if (window->destroyed)
- return;
-
- expose_area = cairo_region_copy (region);
- cairo_region_translate (expose_area, dx, dy);
- cairo_region_union (expose_area, region);
-
- gdk_surface_invalidate_region_full (window, expose_area, FALSE);
- cairo_region_destroy (expose_area);
-}
-
-static void
-gdk_surface_set_cursor_internal (GdkSurface *window,
- GdkDevice *device,
- GdkCursor *cursor)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- g_assert (gdk_surface_get_display (window) == gdk_device_get_display (device));
-
- if (window->window_type == GDK_SURFACE_ROOT ||
- window->window_type == GDK_SURFACE_FOREIGN)
- GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
- else
- {
- GdkPointerSurfaceInfo *pointer_info;
- GdkDisplay *display;
-
- display = gdk_surface_get_display (window);
- pointer_info = _gdk_display_get_pointer_info (display, device);
-
- if (_gdk_surface_event_parent_of (window, pointer_info->window_under_pointer))
- update_cursor (display, device);
- }
-}
-
-/**
- * gdk_surface_get_cursor:
- * @window: a #GdkSurface
- *
- * Retrieves a #GdkCursor pointer for the cursor currently set on the
- * specified #GdkSurface, or %NULL. If the return value is %NULL then
- * there is no custom cursor set on the specified window, and it is
- * using the cursor for its parent window.
- *
- * Returns: (nullable) (transfer none): a #GdkCursor, or %NULL. The
- * returned object is owned by the #GdkSurface and should not be
- * unreferenced directly. Use gdk_surface_set_cursor() to unset the
- * cursor of the window
- */
-GdkCursor *
-gdk_surface_get_cursor (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- return window->cursor;
-}
-
-/**
- * gdk_surface_set_cursor:
- * @window: a #GdkSurface
- * @cursor: (allow-none): a cursor
- *
- * Sets the default mouse pointer for a #GdkSurface.
- *
- * Note that @cursor must be for the same display as @window.
- *
- * Use gdk_cursor_new_for_display() or gdk_cursor_new_from_texture() to
- * create the cursor. To make the cursor invisible, use %GDK_BLANK_CURSOR.
- * Passing %NULL for the @cursor argument to gdk_surface_set_cursor() means
- * that @window will use the cursor of its parent window. Most windows
- * should use this default.
- */
-void
-gdk_surface_set_cursor (GdkSurface *window,
- GdkCursor *cursor)
-{
- GdkDisplay *display;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- display = gdk_surface_get_display (window);
-
- if (window->cursor)
- {
- g_object_unref (window->cursor);
- window->cursor = NULL;
- }
-
- if (!GDK_SURFACE_DESTROYED (window))
- {
- GdkDevice *device;
- GList *seats, *s;
-
- if (cursor)
- window->cursor = g_object_ref (cursor);
-
- seats = gdk_display_list_seats (display);
-
- for (s = seats; s; s = s->next)
- {
- GList *devices, *d;
-
- device = gdk_seat_get_pointer (s->data);
- gdk_surface_set_cursor_internal (window, device, window->cursor);
-
- devices = gdk_seat_get_slaves (s->data, GDK_SEAT_CAPABILITY_TABLET_STYLUS);
- for (d = devices; d; d = d->next)
- {
- device = gdk_device_get_associated_device (d->data);
- gdk_surface_set_cursor_internal (window, device, window->cursor);
- }
- g_list_free (devices);
- }
-
- g_list_free (seats);
- g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_CURSOR]);
- }
-}
-
-/**
- * gdk_surface_get_device_cursor:
- * @window: a #GdkSurface.
- * @device: a master, pointer #GdkDevice.
- *
- * Retrieves a #GdkCursor pointer for the @device currently set on the
- * specified #GdkSurface, or %NULL. If the return value is %NULL then
- * there is no custom cursor set on the specified window, and it is
- * using the cursor for its parent window.
- *
- * Returns: (nullable) (transfer none): a #GdkCursor, or %NULL. The
- * returned object is owned by the #GdkSurface and should not be
- * unreferenced directly. Use gdk_surface_set_cursor() to unset the
- * cursor of the window
- **/
-GdkCursor *
-gdk_surface_get_device_cursor (GdkSurface *window,
- GdkDevice *device)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
- g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
- g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
- g_return_val_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER, NULL);
-
- return g_hash_table_lookup (window->device_cursor, device);
-}
-
-/**
- * gdk_surface_set_device_cursor:
- * @window: a #GdkSurface
- * @device: a master, pointer #GdkDevice
- * @cursor: a #GdkCursor
- *
- * Sets a specific #GdkCursor for a given device when it gets inside @window.
- * Use gdk_cursor_new_for_display() or gdk_cursor_new_from_texture() to create
- * the cursor. To make the cursor invisible, use %GDK_BLANK_CURSOR. Passing
- * %NULL for the @cursor argument to gdk_surface_set_cursor() means that
- * @window will use the cursor of its parent window. Most windows should
- * use this default.
- **/
-void
-gdk_surface_set_device_cursor (GdkSurface *window,
- GdkDevice *device,
- GdkCursor *cursor)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (GDK_IS_DEVICE (device));
- g_return_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD);
- g_return_if_fail (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER);
-
- if (!cursor)
- g_hash_table_remove (window->device_cursor, device);
- else
- g_hash_table_replace (window->device_cursor, device, g_object_ref (cursor));
-
- gdk_surface_set_cursor_internal (window, device, cursor);
-}
-
-/**
- * gdk_surface_get_geometry:
- * @window: a #GdkSurface
- * @x: (out) (allow-none): return location for X coordinate of window (relative to its parent)
- * @y: (out) (allow-none): return location for Y coordinate of window (relative to its parent)
- * @width: (out) (allow-none): return location for width of window
- * @height: (out) (allow-none): return location for height of window
- *
- * Any of the return location arguments to this function may be %NULL,
- * if you aren’t interested in getting the value of that field.
- *
- * The X and Y coordinates returned are relative to the parent window
- * of @window, which for toplevels usually means relative to the
- * window decorations (titlebar, etc.) rather than relative to the
- * root window (screen-size background window).
- *
- * On the X11 platform, the geometry is obtained from the X server,
- * so reflects the latest position of @window; this may be out-of-sync
- * with the position of @window delivered in the most-recently-processed
- * #GdkEventConfigure. gdk_surface_get_position() in contrast gets the
- * position from the most recent configure event.
- *
- * Note: If @window is not a toplevel, it is much better
- * to call gdk_surface_get_position(), gdk_surface_get_width() and
- * gdk_surface_get_height() instead, because it avoids the roundtrip to
- * the X server and because these functions support the full 32-bit
- * coordinate space, whereas gdk_surface_get_geometry() is restricted to
- * the 16-bit coordinates of X11.
- */
-void
-gdk_surface_get_geometry (GdkSurface *window,
- gint *x,
- gint *y,
- gint *width,
- gint *height)
-{
- GdkSurface *parent;
- GdkSurfaceImplClass *impl_class;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (!GDK_SURFACE_DESTROYED (window))
- {
- if (gdk_surface_has_impl (window))
- {
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- impl_class->get_geometry (window, x, y,
- width, height);
- /* This reports the position wrt to the native parent, we need to convert
- it to be relative to the client side parent */
- parent = window->parent;
- if (parent && !gdk_surface_has_impl (parent))
- {
- if (x)
- *x -= parent->abs_x;
- if (y)
- *y -= parent->abs_y;
- }
- }
- else
- {
- if (x)
- *x = window->x;
- if (y)
- *y = window->y;
- if (width)
- *width = window->width;
- if (height)
- *height = window->height;
- }
- }
-}
-
-/**
- * gdk_surface_get_width:
- * @window: a #GdkSurface
- *
- * Returns the width of the given @window.
- *
- * On the X11 platform the returned size is the size reported in the
- * most-recently-processed configure event, rather than the current
- * size on the X server.
- *
- * Returns: The width of @window
- */
-int
-gdk_surface_get_width (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
-
- return window->width;
-}
-
-/**
- * gdk_surface_get_height:
- * @window: a #GdkSurface
- *
- * Returns the height of the given @window.
- *
- * On the X11 platform the returned size is the size reported in the
- * most-recently-processed configure event, rather than the current
- * size on the X server.
- *
- * Returns: The height of @window
- */
-int
-gdk_surface_get_height (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
-
- return window->height;
-}
-
-/**
- * gdk_surface_get_origin:
- * @window: a #GdkSurface
- * @x: (out) (allow-none): return location for X coordinate
- * @y: (out) (allow-none): return location for Y coordinate
- *
- * Obtains the position of a window in root window coordinates.
- * (Compare with gdk_surface_get_position() and
- * gdk_surface_get_geometry() which return the position of a window
- * relative to its parent window.)
- *
- * Returns: not meaningful, ignore
- */
-gint
-gdk_surface_get_origin (GdkSurface *window,
- gint *x,
- gint *y)
-{
- gint dummy_x, dummy_y;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
-
- gdk_surface_get_root_coords (window,
- 0, 0,
- x ? x : &dummy_x,
- y ? y : &dummy_y);
-
- return TRUE;
-}
-
-/**
- * gdk_surface_get_root_coords:
- * @window: a #GdkSurface
- * @x: X coordinate in window
- * @y: Y coordinate in window
- * @root_x: (out): return location for X coordinate
- * @root_y: (out): return location for Y coordinate
- *
- * Obtains the position of a window position in root
- * window coordinates. This is similar to
- * gdk_surface_get_origin() but allows you to pass
- * in any position in the window, not just the origin.
- */
-void
-gdk_surface_get_root_coords (GdkSurface *window,
- gint x,
- gint y,
- gint *root_x,
- gint *root_y)
-{
- GdkSurfaceImplClass *impl_class;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- {
- *root_x = 0;
- *root_y = 0;
- return;
- }
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- impl_class->get_root_coords (window->impl_window,
- x + window->abs_x,
- y + window->abs_y,
- root_x, root_y);
-}
-
-/**
- * gdk_surface_coords_to_parent:
- * @window: a child window
- * @x: X coordinate in child’s coordinate system
- * @y: Y coordinate in child’s coordinate system
- * @parent_x: (out) (allow-none): return location for X coordinate
- * in parent’s coordinate system, or %NULL
- * @parent_y: (out) (allow-none): return location for Y coordinate
- * in parent’s coordinate system, or %NULL
- *
- * Transforms window coordinates from a child window to its parent
- * window. Calling this function is equivalent to adding the return
- * values of gdk_surface_get_position() to the child coordinates.
- *
- * See also: gdk_surface_coords_from_parent()
- **/
-void
-gdk_surface_coords_to_parent (GdkSurface *window,
- gdouble x,
- gdouble y,
- gdouble *parent_x,
- gdouble *parent_y)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (parent_x)
- *parent_x = x + window->x;
-
- if (parent_y)
- *parent_y = y + window->y;
-}
-
-/**
- * gdk_surface_coords_from_parent:
- * @window: a child window
- * @parent_x: X coordinate in parent’s coordinate system
- * @parent_y: Y coordinate in parent’s coordinate system
- * @x: (out) (allow-none): return location for X coordinate in child’s coordinate system
- * @y: (out) (allow-none): return location for Y coordinate in child’s coordinate system
- *
- * Transforms window coordinates from a parent window to a child
- * window.
- *
- * Calling this function is equivalent to subtracting the return
- * values of gdk_surface_get_position() from the parent coordinates.
- *
- * See also: gdk_surface_coords_to_parent()
- **/
-void
-gdk_surface_coords_from_parent (GdkSurface *window,
- gdouble parent_x,
- gdouble parent_y,
- gdouble *x,
- gdouble *y)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (x)
- *x = parent_x - window->x;
-
- if (y)
- *y = parent_y - window->y;
-}
-
-/**
- * gdk_surface_shape_combine_region:
- * @window: a #GdkSurface
- * @shape_region: (allow-none): region of window to be non-transparent
- * @offset_x: X position of @shape_region in @window coordinates
- * @offset_y: Y position of @shape_region in @window coordinates
- *
- * Makes pixels in @window outside @shape_region be transparent,
- * so that the window may be nonrectangular.
- *
- * If @shape_region is %NULL, the shape will be unset, so the whole
- * window will be opaque again. @offset_x and @offset_y are ignored
- * if @shape_region is %NULL.
- *
- * On the X11 platform, this uses an X server extension which is
- * widely available on most common platforms, but not available on
- * very old X servers, and occasionally the implementation will be
- * buggy. On servers without the shape extension, this function
- * will do nothing.
- *
- * This function works on both toplevel and child windows.
- */
-void
-gdk_surface_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
- cairo_region_t *old_region, *new_region, *diff;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (!window->shape && shape_region == NULL)
- return;
-
- window->shaped = (shape_region != NULL);
-
- if (window->shape)
- cairo_region_destroy (window->shape);
-
- old_region = NULL;
- if (GDK_SURFACE_IS_MAPPED (window))
- old_region = cairo_region_copy (window->clip_region);
-
- if (shape_region)
- {
- window->shape = cairo_region_copy (shape_region);
- cairo_region_translate (window->shape, offset_x, offset_y);
- }
- else
- window->shape = NULL;
-
- recompute_visible_regions (window, FALSE);
-
- if (old_region)
- {
- new_region = cairo_region_copy (window->clip_region);
-
- /* New area in the window, needs invalidation */
- diff = cairo_region_copy (new_region);
- cairo_region_subtract (diff, old_region);
-
- gdk_surface_invalidate_region_full (window, diff, TRUE);
-
- cairo_region_destroy (diff);
-
- if (!gdk_surface_is_toplevel (window))
- {
- /* New area in the non-root parent window, needs invalidation */
- diff = cairo_region_copy (old_region);
- cairo_region_subtract (diff, new_region);
-
- /* Adjust region to parent window coords */
- cairo_region_translate (diff, window->x, window->y);
-
- gdk_surface_invalidate_region_full (window->parent, diff, TRUE);
-
- cairo_region_destroy (diff);
- }
-
- cairo_region_destroy (new_region);
- cairo_region_destroy (old_region);
- }
-}
-
-static void
-do_child_shapes (GdkSurface *window,
- gboolean merge)
-{
- GdkRectangle r;
- cairo_region_t *region;
-
- r.x = 0;
- r.y = 0;
- r.width = window->width;
- r.height = window->height;
-
- region = cairo_region_create_rectangle (&r);
- remove_child_area (window, FALSE, region);
-
- if (merge && window->shape)
- cairo_region_subtract (region, window->shape);
-
- cairo_region_xor_rectangle (region, &r);
-
- gdk_surface_shape_combine_region (window, region, 0, 0);
-
- cairo_region_destroy (region);
-}
-
-/**
- * gdk_surface_set_child_shapes:
- * @window: a #GdkSurface
- *
- * Sets the shape mask of @window to the union of shape masks
- * for all children of @window, ignoring the shape mask of @window
- * itself. Contrast with gdk_surface_merge_child_shapes() which includes
- * the shape mask of @window in the masks to be merged.
- **/
-void
-gdk_surface_set_child_shapes (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- do_child_shapes (window, FALSE);
-}
-
-/**
- * gdk_surface_merge_child_shapes:
- * @window: a #GdkSurface
- *
- * Merges the shape masks for any child windows into the
- * shape mask for @window. i.e. the union of all masks
- * for @window and its children will become the new mask
- * for @window. See gdk_surface_shape_combine_region().
- *
- * This function is distinct from gdk_surface_set_child_shapes()
- * because it includes @window’s shape mask in the set of shapes to
- * be merged.
- */
-void
-gdk_surface_merge_child_shapes (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- do_child_shapes (window, TRUE);
-}
-
-/**
- * gdk_surface_input_shape_combine_region:
- * @window: a #GdkSurface
- * @shape_region: region of window to be non-transparent
- * @offset_x: X position of @shape_region in @window coordinates
- * @offset_y: Y position of @shape_region in @window coordinates
- *
- * Like gdk_surface_shape_combine_region(), but the shape applies
- * only to event handling. Mouse events which happen while
- * the pointer position corresponds to an unset bit in the
- * mask will be passed on the window below @window.
- *
- * An input shape is typically used with RGBA windows.
- * The alpha channel of the window defines which pixels are
- * invisible and allows for nicely antialiased borders,
- * and the input shape controls where the window is
- * “clickable”.
- *
- * On the X11 platform, this requires version 1.1 of the
- * shape extension.
- *
- * On the Win32 platform, this functionality is not present and the
- * function does nothing.
- */
-void
-gdk_surface_input_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
- GdkSurfaceImplClass *impl_class;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (window->input_shape)
- cairo_region_destroy (window->input_shape);
-
- if (shape_region)
- {
- window->input_shape = cairo_region_copy (shape_region);
- cairo_region_translate (window->input_shape, offset_x, offset_y);
- }
- else
- window->input_shape = NULL;
-
- if (gdk_surface_has_impl (window))
- {
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- impl_class->input_shape_combine_region (window, window->input_shape, 0, 0);
- }
-}
-
-static void
-do_child_input_shapes (GdkSurface *window,
- gboolean merge)
-{
- GdkRectangle r;
- cairo_region_t *region;
-
- r.x = 0;
- r.y = 0;
- r.width = window->width;
- r.height = window->height;
-
- region = cairo_region_create_rectangle (&r);
- remove_child_area (window, TRUE, region);
-
- if (merge && window->shape)
- cairo_region_subtract (region, window->shape);
- if (merge && window->input_shape)
- cairo_region_subtract (region, window->input_shape);
-
- cairo_region_xor_rectangle (region, &r);
-
- gdk_surface_input_shape_combine_region (window, region, 0, 0);
-}
-
-
-/**
- * gdk_surface_set_child_input_shapes:
- * @window: a #GdkSurface
- *
- * Sets the input shape mask of @window to the union of input shape masks
- * for all children of @window, ignoring the input shape mask of @window
- * itself. Contrast with gdk_surface_merge_child_input_shapes() which includes
- * the input shape mask of @window in the masks to be merged.
- **/
-void
-gdk_surface_set_child_input_shapes (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- do_child_input_shapes (window, FALSE);
-}
-
-/**
- * gdk_surface_set_pass_through:
- * @window: a #GdkSurface
- * @pass_through: a boolean
- *
- * Sets whether input to the window is passed through to the window
- * below.
- *
- * The default value of this is %FALSE, which means that pointer
- * events that happen inside the window are send first to the window,
- * but if the event is not selected by the event mask then the event
- * is sent to the parent window, and so on up the hierarchy.
- *
- * If @pass_through is %TRUE then such pointer events happen as if the
- * window wasn't there at all, and thus will be sent first to any
- * windows below @window. This is useful if the window is used in a
- * transparent fashion. In the terminology of the web this would be called
- * "pointer-events: none".
- *
- * Note that a window with @pass_through %TRUE can still have a subwindow
- * without pass through, so you can get events on a subset of a window. And in
- * that cases you would get the in-between related events such as the pointer
- * enter/leave events on its way to the destination window.
- **/
-void
-gdk_surface_set_pass_through (GdkSurface *window,
- gboolean pass_through)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- window->pass_through = !!pass_through;
-}
-
-/**
- * gdk_surface_get_pass_through:
- * @window: a #GdkSurface
- *
- * Returns whether input to the window is passed through to the window
- * below.
- *
- * See gdk_surface_set_pass_through() for details
- **/
-gboolean
-gdk_surface_get_pass_through (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- return window->pass_through;
-}
-
-/**
- * gdk_surface_merge_child_input_shapes:
- * @window: a #GdkSurface
- *
- * Merges the input shape masks for any child windows into the
- * input shape mask for @window. i.e. the union of all input masks
- * for @window and its children will become the new input mask
- * for @window. See gdk_surface_input_shape_combine_region().
- *
- * This function is distinct from gdk_surface_set_child_input_shapes()
- * because it includes @window’s input shape mask in the set of
- * shapes to be merged.
- **/
-void
-gdk_surface_merge_child_input_shapes (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- do_child_input_shapes (window, TRUE);
-}
-
-
-/**
- * gdk_surface_get_modal_hint:
- * @window: A toplevel #GdkSurface.
- *
- * Determines whether or not the window manager is hinted that @window
- * has modal behaviour.
- *
- * Returns: whether or not the window has the modal hint set.
- */
-gboolean
-gdk_surface_get_modal_hint (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- return window->modal_hint;
-}
-
-/**
- * gdk_surface_get_accept_focus:
- * @window: a toplevel #GdkSurface.
- *
- * Determines whether or not the desktop environment shuld be hinted that
- * the window does not want to receive input focus.
- *
- * Returns: whether or not the window should receive input focus.
- */
-gboolean
-gdk_surface_get_accept_focus (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- return window->accept_focus;
-}
-
-/**
- * gdk_surface_get_focus_on_map:
- * @window: a toplevel #GdkSurface.
- *
- * Determines whether or not the desktop environment should be hinted that the
- * window does not want to receive input focus when it is mapped.
- *
- * Returns: whether or not the window wants to receive input focus when
- * it is mapped.
- */
-gboolean
-gdk_surface_get_focus_on_map (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- return window->focus_on_map;
-}
-
-/**
- * gdk_surface_is_input_only:
- * @window: a toplevel #GdkSurface
- *
- * Determines whether or not the window is an input only window.
- *
- * Returns: %TRUE if @window is input only
- */
-gboolean
-gdk_surface_is_input_only (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- return window->input_only;
-}
-
-/**
- * gdk_surface_is_shaped:
- * @window: a toplevel #GdkSurface
- *
- * Determines whether or not the window is shaped.
- *
- * Returns: %TRUE if @window is shaped
- */
-gboolean
-gdk_surface_is_shaped (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- return window->shaped;
-}
-
-/* Gets the toplevel for a window as used for events,
- i.e. including offscreen parents going up to the native
- toplevel */
-static GdkSurface *
-get_event_toplevel (GdkSurface *window)
-{
- GdkSurface *parent;
-
- while ((parent = window->parent) != NULL &&
- (parent->window_type != GDK_SURFACE_ROOT))
- window = parent;
-
- return window;
-}
-
-gboolean
-_gdk_surface_event_parent_of (GdkSurface *parent,
- GdkSurface *child)
-{
- GdkSurface *w;
-
- w = child;
- while (w != NULL)
- {
- if (w == parent)
- return TRUE;
-
- w = w->parent;
- }
-
- return FALSE;
-}
-
-static void
-update_cursor (GdkDisplay *display,
- GdkDevice *device)
-{
- GdkSurface *cursor_window, *parent, *toplevel;
- GdkSurface *pointer_window;
- GdkPointerSurfaceInfo *pointer_info;
- GdkDeviceGrabInfo *grab;
- GdkCursor *cursor;
-
- pointer_info = _gdk_display_get_pointer_info (display, device);
- pointer_window = pointer_info->window_under_pointer;
-
- /* We ignore the serials here and just pick the last grab
- we've sent, as that would shortly be used anyway. */
- grab = _gdk_display_get_last_device_grab (display, device);
- if (/* have grab */
- grab != NULL &&
- /* the pointer is not in a descendant of the grab window */
- !_gdk_surface_event_parent_of (grab->window, pointer_window))
- {
- /* use the cursor from the grab window */
- cursor_window = grab->window;
- }
- else
- {
- /* otherwise use the cursor from the pointer window */
- cursor_window = pointer_window;
- }
-
- /* Find the first window with the cursor actually set, as
- the cursor is inherited from the parent */
- while (cursor_window->cursor == NULL &&
- !g_hash_table_contains (cursor_window->device_cursor, device) &&
- (parent = cursor_window->parent) != NULL &&
- parent->window_type != GDK_SURFACE_ROOT)
- cursor_window = parent;
-
- cursor = g_hash_table_lookup (cursor_window->device_cursor, device);
-
- if (!cursor)
- cursor = cursor_window->cursor;
-
- /* Set all cursors on toplevel, otherwise its tricky to keep track of
- * which native window has what cursor set. */
- toplevel = get_event_toplevel (pointer_window);
- GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, toplevel, cursor);
-}
-
-static gboolean
-point_in_window (GdkSurface *window,
- gdouble x,
- gdouble y)
-{
- return
- x >= 0 && x < window->width &&
- y >= 0 && y < window->height &&
- (window->shape == NULL ||
- cairo_region_contains_point (window->shape,
- x, y)) &&
- (window->input_shape == NULL ||
- cairo_region_contains_point (window->input_shape,
- x, y));
-}
-
-/* Same as point_in_window, except it also takes pass_through and its
- interaction with child windows into account */
-static gboolean
-point_in_input_window (GdkSurface *window,
- gdouble x,
- gdouble y,
- GdkSurface **input_window,
- gdouble *input_window_x,
- gdouble *input_window_y)
-{
- GdkSurface *sub;
- double child_x, child_y;
- GList *l;
-
- if (!point_in_window (window, x, y))
- return FALSE;
-
- if (!window->pass_through)
- {
- if (input_window)
- {
- *input_window = window;
- *input_window_x = x;
- *input_window_y = y;
- }
- return TRUE;
- }
-
- /* For pass-through, must be over a child input window */
-
- /* Children is ordered in reverse stack order, i.e. first is topmost */
- for (l = window->children; l != NULL; l = l->next)
- {
- sub = l->data;
-
- if (!GDK_SURFACE_IS_MAPPED (sub))
- continue;
-
- gdk_surface_coords_from_parent ((GdkSurface *)sub,
- x, y,
- &child_x, &child_y);
- if (point_in_input_window (sub, child_x, child_y,
- input_window, input_window_x, input_window_y))
- {
- if (input_window)
- gdk_surface_coords_to_parent (sub,
- *input_window_x,
- *input_window_y,
- input_window_x,
- input_window_y);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-GdkSurface *
-_gdk_surface_find_child_at (GdkSurface *window,
- double x,
- double y)
-{
- GdkSurface *sub;
- double child_x, child_y;
- GList *l;
-
- if (point_in_window (window, x, y))
- {
- /* Children is ordered in reverse stack order, i.e. first is topmost */
- for (l = window->children; l != NULL; l = l->next)
- {
- sub = l->data;
-
- if (!GDK_SURFACE_IS_MAPPED (sub))
- continue;
-
- gdk_surface_coords_from_parent ((GdkSurface *)sub,
- x, y,
- &child_x, &child_y);
- if (point_in_input_window (sub, child_x, child_y,
- NULL, NULL, NULL))
- return (GdkSurface *)sub;
- }
- }
-
- return NULL;
-}
-
-GdkSurface *
-_gdk_surface_find_descendant_at (GdkSurface *window,
- gdouble x,
- gdouble y,
- gdouble *found_x,
- gdouble *found_y)
-{
- GdkSurface *sub, *input_window;
- gdouble child_x, child_y;
- GList *l;
- gboolean found;
-
- if (point_in_window (window, x, y))
- {
- do
- {
- found = FALSE;
- /* Children is ordered in reverse stack order, i.e. first is topmost */
- for (l = window->children; l != NULL; l = l->next)
- {
- sub = l->data;
-
- if (!GDK_SURFACE_IS_MAPPED (sub))
- continue;
-
- gdk_surface_coords_from_parent ((GdkSurface *)sub,
- x, y,
- &child_x, &child_y);
- if (point_in_input_window (sub, child_x, child_y,
- &input_window, &child_x, &child_y))
- {
- x = child_x;
- y = child_y;
- window = input_window;
- found = TRUE;
- break;
- }
- }
- }
- while (found);
- }
- else
- {
- /* Not in window at all */
- window = NULL;
- }
-
- if (found_x)
- *found_x = x;
- if (found_y)
- *found_y = y;
-
- return window;
-}
-
-/**
- * gdk_surface_beep:
- * @window: a toplevel #GdkSurface
- *
- * Emits a short beep associated to @window in the appropriate
- * display, if supported. Otherwise, emits a short beep on
- * the display just as gdk_display_beep().
- **/
-void
-gdk_surface_beep (GdkSurface *window)
-{
- GdkDisplay *display;
- GdkSurface *toplevel;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- toplevel = get_event_toplevel (window);
- display = gdk_surface_get_display (window);
-
- if (toplevel)
- {
- if (GDK_SURFACE_IMPL_GET_CLASS (toplevel->impl)->beep (toplevel))
- return;
- }
-
- /* If windows fail to beep, we beep the display. */
- gdk_display_beep (display);
-}
-
-/**
- * gdk_surface_set_support_multidevice:
- * @window: a #GdkSurface.
- * @support_multidevice: %TRUE to enable multidevice support in @window.
- *
- * This function will enable multidevice features in @window.
- *
- * Multidevice aware windows will need to handle properly multiple,
- * per device enter/leave events, device grabs and grab ownerships.
- **/
-void
-gdk_surface_set_support_multidevice (GdkSurface *window,
- gboolean support_multidevice)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (window->support_multidevice == support_multidevice)
- return;
-
- window->support_multidevice = support_multidevice;
-
- /* FIXME: What to do if called when some pointers are inside the window ? */
-}
-
-/**
- * gdk_surface_get_support_multidevice:
- * @window: a #GdkSurface.
- *
- * Returns %TRUE if the window is aware of the existence of multiple
- * devices.
- *
- * Returns: %TRUE if the window handles multidevice features.
- **/
-gboolean
-gdk_surface_get_support_multidevice (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- if (GDK_SURFACE_DESTROYED (window))
- return FALSE;
-
- return window->support_multidevice;
-}
-
-/* send motion events if the right buttons are down */
-
-GdkEvent *
-_gdk_make_event (GdkSurface *window,
- GdkEventType type,
- GdkEvent *event_in_queue,
- gboolean before_event)
-{
- GdkEvent *event = gdk_event_new (type);
- guint32 the_time;
- GdkModifierType the_state;
-
- the_time = gdk_event_get_time (event_in_queue);
- gdk_event_get_state (event_in_queue, &the_state);
-
- event->any.window = g_object_ref (window);
- event->any.send_event = FALSE;
- if (event_in_queue && event_in_queue->any.send_event)
- event->any.send_event = TRUE;
-
- switch ((guint) type)
- {
- case GDK_MOTION_NOTIFY:
- event->motion.time = the_time;
- event->motion.axes = NULL;
- event->motion.state = the_state;
- break;
-
- case GDK_BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- event->button.time = the_time;
- event->button.axes = NULL;
- event->button.state = the_state;
- break;
-
- case GDK_TOUCH_BEGIN:
- case GDK_TOUCH_UPDATE:
- case GDK_TOUCH_END:
- case GDK_TOUCH_CANCEL:
- event->touch.time = the_time;
- event->touch.axes = NULL;
- event->touch.state = the_state;
- break;
-
- case GDK_SCROLL:
- event->scroll.time = the_time;
- event->scroll.state = the_state;
- break;
-
- case GDK_KEY_PRESS:
- case GDK_KEY_RELEASE:
- event->key.time = the_time;
- event->key.state = the_state;
- break;
-
- case GDK_ENTER_NOTIFY:
- case GDK_LEAVE_NOTIFY:
- event->crossing.time = the_time;
- event->crossing.state = the_state;
- break;
-
- case GDK_PROXIMITY_IN:
- case GDK_PROXIMITY_OUT:
- event->proximity.time = the_time;
- break;
-
- case GDK_DRAG_ENTER:
- case GDK_DRAG_LEAVE:
- case GDK_DRAG_MOTION:
- case GDK_DROP_START:
- event->dnd.time = the_time;
- break;
-
- case GDK_TOUCHPAD_SWIPE:
- event->touchpad_swipe.time = the_time;
- event->touchpad_swipe.state = the_state;
- break;
-
- case GDK_TOUCHPAD_PINCH:
- event->touchpad_pinch.time = the_time;
- event->touchpad_pinch.state = the_state;
- break;
-
- case GDK_FOCUS_CHANGE:
- case GDK_CONFIGURE:
- case GDK_MAP:
- case GDK_UNMAP:
- case GDK_DELETE:
- case GDK_DESTROY:
- case GDK_EXPOSE:
- default:
- break;
- }
-
- if (event_in_queue)
- {
- if (before_event)
- _gdk_event_queue_insert_before (gdk_surface_get_display (window), event_in_queue, event);
- else
- _gdk_event_queue_insert_after (gdk_surface_get_display (window), event_in_queue, event);
- }
- else
- _gdk_event_queue_append (gdk_surface_get_display (window), event);
-
- return event;
-}
-
-void
-_gdk_display_set_window_under_pointer (GdkDisplay *display,
- GdkDevice *device,
- GdkSurface *window)
-{
- GdkPointerSurfaceInfo *device_info;
-
- device_info = _gdk_display_get_pointer_info (display, device);
-
- if (device_info->window_under_pointer)
- g_object_unref (device_info->window_under_pointer);
- device_info->window_under_pointer = window;
-
- if (window)
- {
- g_object_ref (window);
- update_cursor (display, device);
- }
-}
-
-#define GDK_ANY_BUTTON_MASK (GDK_BUTTON1_MASK | \
- GDK_BUTTON2_MASK | \
- GDK_BUTTON3_MASK | \
- GDK_BUTTON4_MASK | \
- GDK_BUTTON5_MASK)
-
-#ifdef DEBUG_WINDOW_PRINTING
-
-#ifdef GDK_WINDOWING_X11
-#include "x11/gdkx.h"
-#endif
-
-static void
-gdk_surface_print (GdkSurface *window,
- int indent)
-{
- char *s;
- const char *window_types[] = {
- "root",
- "toplevel",
- "child",
- "dialog",
- "temp",
- "foreign",
- "subsurface"
- };
-
- g_print ("%*s%p: [%s] %d,%d %dx%d", indent, "", window,
- window->user_data ? g_type_name_from_instance (window->user_data) : "no widget",
- window->x, window->y,
- window->width, window->height
- );
-
- if (gdk_surface_has_impl (window))
- {
-#ifdef GDK_WINDOWING_X11
- g_print (" impl(0x%lx)", gdk_x11_surface_get_xid (window));
-#endif
- }
-
- if (window->window_type != GDK_SURFACE_CHILD)
- g_print (" %s", window_types[window->window_type]);
-
- if (window->input_only)
- g_print (" input-only");
-
- if (window->shaped)
- g_print (" shaped");
-
- if (!gdk_surface_is_visible ((GdkSurface *)window))
- g_print (" hidden");
-
- g_print (" abs[%d,%d]",
- window->abs_x, window->abs_y);
-
- if (window->alpha != 255)
- g_print (" alpha[%d]",
- window->alpha);
-
- s = print_region (window->clip_region);
- g_print (" clipbox[%s]", s);
-
- g_print ("\n");
-}
-
-
-static void
-gdk_surface_print_tree (GdkSurface *window,
- int indent,
- gboolean include_input_only)
-{
- GList *l;
-
- if (window->input_only && !include_input_only)
- return;
-
- gdk_surface_print (window, indent);
-
- for (l = window->children; l != NULL; l = l->next)
- gdk_surface_print_tree (l->data, indent + 4, include_input_only);
-}
-
-#endif /* DEBUG_WINDOW_PRINTING */
-
-void
-_gdk_windowing_got_event (GdkDisplay *display,
- GList *event_link,
- GdkEvent *event,
- gulong serial)
-{
- GdkSurface *event_window;
- gboolean unlink_event = FALSE;
- GdkDeviceGrabInfo *button_release_grab;
- GdkPointerSurfaceInfo *pointer_info = NULL;
- GdkDevice *device, *source_device;
-
- _gdk_display_update_last_event (display, event);
-
- device = gdk_event_get_device (event);
- source_device = gdk_event_get_source_device (event);
-
- if (device)
- {
- if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD &&
- gdk_device_get_source (device) != GDK_SOURCE_TABLET_PAD)
- {
- pointer_info = _gdk_display_get_pointer_info (display, device);
-
- if (source_device != pointer_info->last_slave &&
- gdk_device_get_device_type (source_device) == GDK_DEVICE_TYPE_SLAVE)
- pointer_info->last_slave = source_device;
- else if (pointer_info->last_slave)
- source_device = pointer_info->last_slave;
- }
-
- _gdk_display_device_grab_update (display, device, source_device, serial);
-
- if (gdk_device_get_input_mode (device) == GDK_MODE_DISABLED ||
- !_gdk_display_check_grab_ownership (display, device, serial))
- {
- /* Device events are blocked by another
- * device grab, or the device is disabled
- */
- unlink_event = TRUE;
- goto out;
- }
- }
-
- event_window = event->any.window;
- if (!event_window)
- goto out;
-
-#ifdef DEBUG_WINDOW_PRINTING
- if (event->any.type == GDK_KEY_PRESS &&
- (event->key.keyval == 0xa7 ||
- event->key.keyval == 0xbd))
- {
- gdk_surface_print_tree (event_window, 0, event->key.keyval == 0xbd);
- }
-#endif
-
- if (event_window->window_type == GDK_SURFACE_ROOT)
- goto out;
-
- if (event->any.type == GDK_ENTER_NOTIFY)
- _gdk_display_set_window_under_pointer (display, device, event_window);
- else if (event->any.type == GDK_LEAVE_NOTIFY)
- _gdk_display_set_window_under_pointer (display, device, NULL);
-
- if ((event->any.type == GDK_BUTTON_RELEASE ||
- event->any.type == GDK_TOUCH_CANCEL ||
- event->any.type == GDK_TOUCH_END) &&
- !event->any.send_event)
- {
- if (event->any.type == GDK_BUTTON_RELEASE ||
- gdk_event_get_pointer_emulated (event))
- {
- button_release_grab =
- _gdk_display_has_device_grab (display, device, serial);
-
- if (button_release_grab &&
- button_release_grab->implicit &&
- (event->button.state & GDK_ANY_BUTTON_MASK & ~(GDK_BUTTON1_MASK << (event->button.button - 1))) == 0)
- {
- button_release_grab->serial_end = serial;
- button_release_grab->implicit_ungrab = FALSE;
- _gdk_display_device_grab_update (display, device, source_device, serial);
- }
- }
- }
-
- out:
- if (unlink_event)
- {
- _gdk_event_queue_remove_link (display, event_link);
- g_list_free_1 (event_link);
- gdk_event_free (event);
- }
-
- /* This does two things - first it sees if there are motions at the
- * end of the queue that can be compressed. Second, if there is just
- * a single motion that won't be dispatched because it is a compression
- * candidate it queues up flushing the event queue.
- */
- _gdk_event_queue_handle_motion_compression (display);
-}
-
-/**
- * gdk_surface_create_similar_surface:
- * @window: window to make new surface similar to
- * @content: the content for the new surface
- * @width: width of the new surface
- * @height: height of the new surface
- *
- * Create a new surface that is as compatible as possible with the
- * given @window. For example the new surface will have the same
- * fallback resolution and font options as @window. Generally, the new
- * surface will also use the same backend as @window, unless that is
- * not possible for some reason. The type of the returned surface may
- * be examined with cairo_surface_get_type().
- *
- * Initially the surface contents are all 0 (transparent if contents
- * have transparency, black otherwise.)
- *
- * Returns: a pointer to the newly allocated surface. The caller
- * owns the surface and should call cairo_surface_destroy() when done
- * with it.
- *
- * This function always returns a valid pointer, but it will return a
- * pointer to a “nil” surface if @other is already in an error state
- * or any other error occurs.
- **/
-cairo_surface_t *
-gdk_surface_create_similar_surface (GdkSurface * window,
- cairo_content_t content,
- int width,
- int height)
-{
- cairo_surface_t *window_surface, *surface;
- double sx, sy;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- window_surface = gdk_surface_ref_impl_surface (window);
- sx = sy = 1;
- cairo_surface_get_device_scale (window_surface, &sx, &sy);
-
- if (GDK_DISPLAY_DEBUG_CHECK (window->display, CAIRO_IMAGE))
- {
- surface = cairo_image_surface_create (content == CAIRO_CONTENT_COLOR ? CAIRO_FORMAT_RGB24 :
- content == CAIRO_CONTENT_ALPHA ? CAIRO_FORMAT_A8 : CAIRO_FORMAT_ARGB32,
- width * sx, height * sy);
- cairo_surface_set_device_scale (surface, sx, sy);
- }
- else
- {
- surface = cairo_surface_create_similar (window_surface,
- content,
- width, height);
- }
-
- cairo_surface_destroy (window_surface);
-
- return surface;
-}
-
-
-/**
- * gdk_surface_create_similar_image_surface:
- * @window: (nullable): window to make new surface similar to, or
- * %NULL if none
- * @format: (type int): the format for the new surface
- * @width: width of the new surface
- * @height: height of the new surface
- * @scale: the scale of the new surface, or 0 to use same as @window
- *
- * Create a new image surface that is efficient to draw on the
- * given @window.
- *
- * Initially the surface contents are all 0 (transparent if contents
- * have transparency, black otherwise.)
- *
- * The @width and @height of the new surface are not affected by
- * the scaling factor of the @window, or by the @scale argument; they
- * are the size of the surface in device pixels. If you wish to create
- * an image surface capable of holding the contents of @window you can
- * use:
- *
- * |[<!-- language="C" -->
- * int scale = gdk_surface_get_scale_factor (window);
- * int width = gdk_surface_get_width (window) * scale;
- * int height = gdk_surface_get_height (window) * scale;
- *
- * // format is set elsewhere
- * cairo_surface_t *surface =
- * gdk_surface_create_similar_image_surface (window,
- * format,
- * width, height,
- * scale);
- * ]|
- *
- * Note that unlike cairo_surface_create_similar_image(), the new
- * surface's device scale is set to @scale, or to the scale factor of
- * @window if @scale is 0.
- *
- * Returns: a pointer to the newly allocated surface. The caller
- * owns the surface and should call cairo_surface_destroy() when done
- * with it.
- *
- * This function always returns a valid pointer, but it will return a
- * pointer to a “nil” surface if @other is already in an error state
- * or any other error occurs.
- **/
-cairo_surface_t *
-gdk_surface_create_similar_image_surface (GdkSurface * window,
- cairo_format_t format,
- int width,
- int height,
- int scale)
-{
- cairo_surface_t *surface;
-
- g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), NULL);
-
- if (window == NULL)
- {
- surface = cairo_image_surface_create (format, width, height);
- }
- else if (GDK_SURFACE_IMPL_GET_CLASS (window->impl)->create_similar_image_surface)
- {
- surface =
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->create_similar_image_surface (window, format, width, height);
- }
- else
- {
- cairo_surface_t *window_surface;
-
- window_surface = gdk_surface_ref_impl_surface (window);
- surface =
- cairo_surface_create_similar_image (window_surface,
- format,
- width,
- height);
- cairo_surface_destroy (window_surface);
- }
-
- if (scale == 0)
- scale = gdk_surface_get_scale_factor (window);
-
- cairo_surface_set_device_scale (surface, scale, scale);
-
- return surface;
-}
-
-
-/**
- * gdk_surface_focus:
- * @window: a #GdkSurface
- * @timestamp: timestamp of the event triggering the window focus
- *
- * Sets keyboard focus to @window. In most cases, gtk_window_present()
- * should be used on a #GtkWindow, rather than calling this function.
- *
- **/
-void
-gdk_surface_focus (GdkSurface *window,
- guint32 timestamp)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->focus (window, timestamp);
-}
-
-/**
- * gdk_surface_set_type_hint:
- * @window: A toplevel #GdkSurface
- * @hint: A hint of the function this window will have
- *
- * The application can use this call to provide a hint to the window
- * manager about the functionality of a window. The window manager
- * can use this information when determining the decoration and behaviour
- * of the window.
- *
- * The hint must be set before the window is mapped.
- **/
-void
-gdk_surface_set_type_hint (GdkSurface *window,
- GdkSurfaceTypeHint hint)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_type_hint (window, hint);
-}
-
-/**
- * gdk_surface_get_type_hint:
- * @window: A toplevel #GdkSurface
- *
- * This function returns the type hint set for a window.
- *
- * Returns: The type hint set for @window
- **/
-GdkSurfaceTypeHint
-gdk_surface_get_type_hint (GdkSurface *window)
-{
- return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->get_type_hint (window);
-}
-
-/**
- * gdk_surface_set_modal_hint:
- * @window: A toplevel #GdkSurface
- * @modal: %TRUE if the window is modal, %FALSE otherwise.
- *
- * The application can use this hint to tell the window manager
- * that a certain window has modal behaviour. The window manager
- * can use this information to handle modal windows in a special
- * way.
- *
- * You should only use this on windows for which you have
- * previously called gdk_surface_set_transient_for()
- **/
-void
-gdk_surface_set_modal_hint (GdkSurface *window,
- gboolean modal)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_modal_hint (window, modal);
-}
-
-/**
- * gdk_surface_set_skip_taskbar_hint:
- * @window: a toplevel #GdkSurface
- * @skips_taskbar: %TRUE to skip the taskbar
- *
- * Toggles whether a window should appear in a task list or window
- * list. If a window’s semantic type as specified with
- * gdk_surface_set_type_hint() already fully describes the window, this
- * function should not be called in addition,
- * instead you should allow the window to be treated according to
- * standard policy for its semantic type.
- **/
-void
-gdk_surface_set_skip_taskbar_hint (GdkSurface *window,
- gboolean skips_taskbar)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_skip_taskbar_hint (window, skips_taskbar);
-}
-
-/**
- * gdk_surface_set_skip_pager_hint:
- * @window: a toplevel #GdkSurface
- * @skips_pager: %TRUE to skip the pager
- *
- * Toggles whether a window should appear in a pager (workspace
- * switcher, or other desktop utility program that displays a small
- * thumbnail representation of the windows on the desktop). If a
- * window’s semantic type as specified with gdk_surface_set_type_hint()
- * already fully describes the window, this function should
- * not be called in addition, instead you should
- * allow the window to be treated according to standard policy for
- * its semantic type.
- **/
-void
-gdk_surface_set_skip_pager_hint (GdkSurface *window,
- gboolean skips_pager)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_skip_pager_hint (window, skips_pager);
-}
-
-/**
- * gdk_surface_set_urgency_hint:
- * @window: a toplevel #GdkSurface
- * @urgent: %TRUE if the window is urgent
- *
- * Toggles whether a window needs the user's
- * urgent attention.
- **/
-void
-gdk_surface_set_urgency_hint (GdkSurface *window,
- gboolean urgent)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_urgency_hint (window, urgent);
-}
-
-/**
- * gdk_surface_set_geometry_hints:
- * @window: a toplevel #GdkSurface
- * @geometry: geometry hints
- * @geom_mask: bitmask indicating fields of @geometry to pay attention to
- *
- * Sets the geometry hints for @window. Hints flagged in @geom_mask
- * are set, hints not flagged in @geom_mask are unset.
- * To unset all hints, use a @geom_mask of 0 and a @geometry of %NULL.
- *
- * This function provides hints to the windowing system about
- * acceptable sizes for a toplevel window. The purpose of
- * this is to constrain user resizing, but the windowing system
- * will typically (but is not required to) also constrain the
- * current size of the window to the provided values and
- * constrain programatic resizing via gdk_surface_resize() or
- * gdk_surface_move_resize().
- *
- * Note that on X11, this effect has no effect on windows
- * of type %GDK_SURFACE_TEMP since these windows are not resizable
- * by the user.
- *
- * Since you can’t count on the windowing system doing the
- * constraints for programmatic resizes, you should generally
- * call gdk_surface_constrain_size() yourself to determine
- * appropriate sizes.
- *
- **/
-void
-gdk_surface_set_geometry_hints (GdkSurface *window,
- const GdkGeometry *geometry,
- GdkSurfaceHints geom_mask)
-{
- g_return_if_fail (geometry != NULL || geom_mask == 0);
-
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_geometry_hints (window, geometry, geom_mask);
-}
-
-/**
- * gdk_surface_set_title:
- * @window: a toplevel #GdkSurface
- * @title: title of @window
- *
- * Sets the title of a toplevel window, to be displayed in the titlebar.
- * If you haven’t explicitly set the icon name for the window
- * (using gdk_surface_set_icon_name()), the icon name will be set to
- * @title as well. @title must be in UTF-8 encoding (as with all
- * user-readable strings in GDK/GTK+). @title may not be %NULL.
- **/
-void
-gdk_surface_set_title (GdkSurface *window,
- const gchar *title)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_title (window, title);
-}
-
-/**
- * gdk_surface_set_role:
- * @window: a toplevel #GdkSurface
- * @role: a string indicating its role
- *
- * When using GTK+, typically you should use gtk_window_set_role() instead
- * of this low-level function.
- *
- * The window manager and session manager use a window’s role to
- * distinguish it from other kinds of window in the same application.
- * When an application is restarted after being saved in a previous
- * session, all windows with the same title and role are treated as
- * interchangeable. So if you have two windows with the same title
- * that should be distinguished for session management purposes, you
- * should set the role on those windows. It doesn’t matter what string
- * you use for the role, as long as you have a different role for each
- * non-interchangeable kind of window.
- *
- **/
-void
-gdk_surface_set_role (GdkSurface *window,
- const gchar *role)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_role (window, role);
-}
-
-/**
- * gdk_surface_set_startup_id:
- * @window: a toplevel #GdkSurface
- * @startup_id: a string with startup-notification identifier
- *
- * When using GTK+, typically you should use gtk_window_set_startup_id()
- * instead of this low-level function.
- **/
-void
-gdk_surface_set_startup_id (GdkSurface *window,
- const gchar *startup_id)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_startup_id (window, startup_id);
-}
-
-/**
- * gdk_surface_set_transient_for:
- * @window: a toplevel #GdkSurface
- * @parent: another toplevel #GdkSurface
- *
- * Indicates to the window manager that @window is a transient dialog
- * associated with the application window @parent. This allows the
- * window manager to do things like center @window on @parent and
- * keep @window above @parent.
- *
- * See gtk_window_set_transient_for() if you’re using #GtkWindow or
- * #GtkDialog.
- **/
-void
-gdk_surface_set_transient_for (GdkSurface *window,
- GdkSurface *parent)
-{
- window->transient_for = parent;
-
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_transient_for (window, parent);
-}
-
-/**
- * gdk_surface_get_root_origin:
- * @window: a toplevel #GdkSurface
- * @x: (out): return location for X position of window frame
- * @y: (out): return location for Y position of window frame
- *
- * Obtains the top-left corner of the window manager frame in root
- * window coordinates.
- *
- **/
-void
-gdk_surface_get_root_origin (GdkSurface *window,
- gint *x,
- gint *y)
-{
- GdkRectangle rect;
-
- gdk_surface_get_frame_extents (window, &rect);
-
- if (x)
- *x = rect.x;
-
- if (y)
- *y = rect.y;
-}
-
-/**
- * gdk_surface_get_frame_extents:
- * @window: a toplevel #GdkSurface
- * @rect: (out): rectangle to fill with bounding box of the window frame
- *
- * Obtains the bounding box of the window, including window manager
- * titlebar/borders if any. The frame position is given in root window
- * coordinates. To get the position of the window itself (rather than
- * the frame) in root window coordinates, use gdk_surface_get_origin().
- *
- **/
-void
-gdk_surface_get_frame_extents (GdkSurface *window,
- GdkRectangle *rect)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->get_frame_extents (window, rect);
-}
-
-/**
- * gdk_surface_set_accept_focus:
- * @window: a toplevel #GdkSurface
- * @accept_focus: %TRUE if the window should receive input focus
- *
- * Setting @accept_focus to %FALSE hints the desktop environment that the
- * window doesn’t want to receive input focus.
- *
- * On X, it is the responsibility of the window manager to interpret this
- * hint. ICCCM-compliant window manager usually respect it.
- **/
-void
-gdk_surface_set_accept_focus (GdkSurface *window,
- gboolean accept_focus)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_accept_focus (window, accept_focus);
-}
-
-/**
- * gdk_surface_set_focus_on_map:
- * @window: a toplevel #GdkSurface
- * @focus_on_map: %TRUE if the window should receive input focus when mapped
- *
- * Setting @focus_on_map to %FALSE hints the desktop environment that the
- * window doesn’t want to receive input focus when it is mapped.
- * focus_on_map should be turned off for windows that aren’t triggered
- * interactively (such as popups from network activity).
- *
- * On X, it is the responsibility of the window manager to interpret
- * this hint. Window managers following the freedesktop.org window
- * manager extension specification should respect it.
- **/
-void
-gdk_surface_set_focus_on_map (GdkSurface *window,
- gboolean focus_on_map)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_focus_on_map (window, focus_on_map);
-}
-
-/**
- * gdk_surface_set_icon_list:
- * @window: The #GdkSurface toplevel window to set the icon of.
- * @surfaces: (transfer none) (element-type GdkTexture):
- * A list of image surfaces, of different sizes.
- *
- * Sets a list of icons for the window. One of these will be used
- * to represent the window when it has been iconified. The icon is
- * usually shown in an icon box or some sort of task bar. Which icon
- * size is shown depends on the window manager. The window manager
- * can scale the icon but setting several size icons can give better
- * image quality since the window manager may only need to scale the
- * icon by a small amount or not at all.
- *
- * Note that some platforms don't support window icons.
- */
-void
-gdk_surface_set_icon_list (GdkSurface *window,
- GList *textures)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_icon_list (window, textures);
-}
-
-/**
- * gdk_surface_set_icon_name:
- * @window: a toplevel #GdkSurface
- * @name: (allow-none): name of window while iconified (minimized)
- *
- * Windows may have a name used while minimized, distinct from the
- * name they display in their titlebar. Most of the time this is a bad
- * idea from a user interface standpoint. But you can set such a name
- * with this function, if you like.
- *
- * After calling this with a non-%NULL @name, calls to gdk_surface_set_title()
- * will not update the icon title.
- *
- * Using %NULL for @name unsets the icon title; further calls to
- * gdk_surface_set_title() will again update the icon title as well.
- *
- * Note that some platforms don't support window icons.
- **/
-void
-gdk_surface_set_icon_name (GdkSurface *window,
- const gchar *name)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_icon_name (window, name);
-}
-
-/**
- * gdk_surface_iconify:
- * @window: a toplevel #GdkSurface
- *
- * Asks to iconify (minimize) @window. The window manager may choose
- * to ignore the request, but normally will honor it. Using
- * gtk_window_iconify() is preferred, if you have a #GtkWindow widget.
- *
- * This function only makes sense when @window is a toplevel window.
- *
- **/
-void
-gdk_surface_iconify (GdkSurface *window)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->iconify (window);
-}
-
-/**
- * gdk_surface_deiconify:
- * @window: a toplevel #GdkSurface
- *
- * Attempt to deiconify (unminimize) @window. On X11 the window manager may
- * choose to ignore the request to deiconify. When using GTK+,
- * use gtk_window_deiconify() instead of the #GdkSurface variant. Or better yet,
- * you probably want to use gtk_window_present(), which raises the window, focuses it,
- * unminimizes it, and puts it on the current desktop.
- *
- **/
-void
-gdk_surface_deiconify (GdkSurface *window)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->deiconify (window);
-}
-
-/**
- * gdk_surface_stick:
- * @window: a toplevel #GdkSurface
- *
- * “Pins” a window such that it’s on all workspaces and does not scroll
- * with viewports, for window managers that have scrollable viewports.
- * (When using #GtkWindow, gtk_window_stick() may be more useful.)
- *
- * On the X11 platform, this function depends on window manager
- * support, so may have no effect with many window managers. However,
- * GDK will do the best it can to convince the window manager to stick
- * the window. For window managers that don’t support this operation,
- * there’s nothing you can do to force it to happen.
- *
- **/
-void
-gdk_surface_stick (GdkSurface *window)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->stick (window);
-}
-
-/**
- * gdk_surface_unstick:
- * @window: a toplevel #GdkSurface
- *
- * Reverse operation for gdk_surface_stick(); see gdk_surface_stick(),
- * and gtk_window_unstick().
- *
- **/
-void
-gdk_surface_unstick (GdkSurface *window)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->unstick (window);
-}
-
-/**
- * gdk_surface_maximize:
- * @window: a toplevel #GdkSurface
- *
- * Maximizes the window. If the window was already maximized, then
- * this function does nothing.
- *
- * On X11, asks the window manager to maximize @window, if the window
- * manager supports this operation. Not all window managers support
- * this, and some deliberately ignore it or don’t have a concept of
- * “maximized”; so you can’t rely on the maximization actually
- * happening. But it will happen with most standard window managers,
- * and GDK makes a best effort to get it to happen.
- *
- * On Windows, reliably maximizes the window.
- *
- **/
-void
-gdk_surface_maximize (GdkSurface *window)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->maximize (window);
-}
-
-/**
- * gdk_surface_unmaximize:
- * @window: a toplevel #GdkSurface
- *
- * Unmaximizes the window. If the window wasn’t maximized, then this
- * function does nothing.
- *
- * On X11, asks the window manager to unmaximize @window, if the
- * window manager supports this operation. Not all window managers
- * support this, and some deliberately ignore it or don’t have a
- * concept of “maximized”; so you can’t rely on the unmaximization
- * actually happening. But it will happen with most standard window
- * managers, and GDK makes a best effort to get it to happen.
- *
- * On Windows, reliably unmaximizes the window.
- *
- **/
-void
-gdk_surface_unmaximize (GdkSurface *window)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->unmaximize (window);
-}
-
-/**
- * gdk_surface_fullscreen:
- * @window: a toplevel #GdkSurface
- *
- * Moves the window into fullscreen mode. This means the
- * window covers the entire screen and is above any panels
- * or task bars.
- *
- * If the window was already fullscreen, then this function does nothing.
- *
- * On X11, asks the window manager to put @window in a fullscreen
- * state, if the window manager supports this operation. Not all
- * window managers support this, and some deliberately ignore it or
- * don’t have a concept of “fullscreen”; so you can’t rely on the
- * fullscreenification actually happening. But it will happen with
- * most standard window managers, and GDK makes a best effort to get
- * it to happen.
- **/
-void
-gdk_surface_fullscreen (GdkSurface *window)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->fullscreen (window);
-}
-
-/**
- * gdk_surface_fullscreen_on_monitor:
- * @window: a toplevel #GdkSurface
- * @monitor: Which monitor to display fullscreen on.
- *
- * Moves the window into fullscreen mode on the given monitor. This means
- * the window covers the entire screen and is above any panels or task bars.
- *
- * If the window was already fullscreen, then this function does nothing.
- **/
-void
-gdk_surface_fullscreen_on_monitor (GdkSurface *window,
- GdkMonitor *monitor)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (GDK_IS_MONITOR (monitor));
- g_return_if_fail (gdk_monitor_get_display (monitor) == gdk_surface_get_display (window));
- g_return_if_fail (gdk_monitor_is_valid (monitor));
-
- if (GDK_SURFACE_IMPL_GET_CLASS (window->impl)->fullscreen_on_monitor != NULL)
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->fullscreen_on_monitor (window, monitor);
- else
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->fullscreen (window);
-}
-
-/**
- * gdk_surface_set_fullscreen_mode:
- * @window: a toplevel #GdkSurface
- * @mode: fullscreen mode
- *
- * Specifies whether the @window should span over all monitors (in a multi-head
- * setup) or only the current monitor when in fullscreen mode.
- *
- * The @mode argument is from the #GdkFullscreenMode enumeration.
- * If #GDK_FULLSCREEN_ON_ALL_MONITORS is specified, the fullscreen @window will
- * span over all monitors of the display.
- *
- * On X11, searches through the list of monitors display the ones
- * which delimit the 4 edges of the entire display and will ask the window
- * manager to span the @window over these monitors.
- *
- * If the XINERAMA extension is not available or not usable, this function
- * has no effect.
- *
- * Not all window managers support this, so you can’t rely on the fullscreen
- * window to span over the multiple monitors when #GDK_FULLSCREEN_ON_ALL_MONITORS
- * is specified.
- **/
-void
-gdk_surface_set_fullscreen_mode (GdkSurface *window,
- GdkFullscreenMode mode)
-{
- GdkSurfaceImplClass *impl_class;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->fullscreen_mode != mode)
- {
- window->fullscreen_mode = mode;
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
- if (impl_class->apply_fullscreen_mode != NULL)
- impl_class->apply_fullscreen_mode (window);
- }
-}
-
-/**
- * gdk_surface_get_fullscreen_mode:
- * @window: a toplevel #GdkSurface
- *
- * Obtains the #GdkFullscreenMode of the @window.
- *
- * Returns: The #GdkFullscreenMode applied to the window when fullscreen.
- **/
-GdkFullscreenMode
-gdk_surface_get_fullscreen_mode (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), GDK_FULLSCREEN_ON_CURRENT_MONITOR);
-
- return window->fullscreen_mode;
-}
-
-/**
- * gdk_surface_unfullscreen:
- * @window: a toplevel #GdkSurface
- *
- * Moves the window out of fullscreen mode. If the window was not
- * fullscreen, does nothing.
- *
- * On X11, asks the window manager to move @window out of the fullscreen
- * state, if the window manager supports this operation. Not all
- * window managers support this, and some deliberately ignore it or
- * don’t have a concept of “fullscreen”; so you can’t rely on the
- * unfullscreenification actually happening. But it will happen with
- * most standard window managers, and GDK makes a best effort to get
- * it to happen.
- **/
-void
-gdk_surface_unfullscreen (GdkSurface *window)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->unfullscreen (window);
-}
-
-/**
- * gdk_surface_set_keep_above:
- * @window: a toplevel #GdkSurface
- * @setting: whether to keep @window above other windows
- *
- * Set if @window must be kept above other windows. If the
- * window was already above, then this function does nothing.
- *
- * On X11, asks the window manager to keep @window above, if the window
- * manager supports this operation. Not all window managers support
- * this, and some deliberately ignore it or don’t have a concept of
- * “keep above”; so you can’t rely on the window being kept above.
- * But it will happen with most standard window managers,
- * and GDK makes a best effort to get it to happen.
- **/
-void
-gdk_surface_set_keep_above (GdkSurface *window,
- gboolean setting)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_keep_above (window, setting);
-}
-
-/**
- * gdk_surface_set_keep_below:
- * @window: a toplevel #GdkSurface
- * @setting: whether to keep @window below other windows
- *
- * Set if @window must be kept below other windows. If the
- * window was already below, then this function does nothing.
- *
- * On X11, asks the window manager to keep @window below, if the window
- * manager supports this operation. Not all window managers support
- * this, and some deliberately ignore it or don’t have a concept of
- * “keep below”; so you can’t rely on the window being kept below.
- * But it will happen with most standard window managers,
- * and GDK makes a best effort to get it to happen.
- **/
-void
-gdk_surface_set_keep_below (GdkSurface *window, gboolean setting)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_keep_below (window, setting);
-}
-
-/**
- * gdk_surface_get_group:
- * @window: a toplevel #GdkSurface
- *
- * Returns the group leader window for @window. See gdk_surface_set_group().
- *
- * Returns: (transfer none): the group leader window for @window
- **/
-GdkSurface *
-gdk_surface_get_group (GdkSurface *window)
-{
- return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->get_group (window);
-}
-
-/**
- * gdk_surface_set_group:
- * @window: a toplevel #GdkSurface
- * @leader: (allow-none): group leader window, or %NULL to restore the default group leader window
- *
- * Sets the group leader window for @window. By default,
- * GDK sets the group leader for all toplevel windows
- * to a global window implicitly created by GDK. With this function
- * you can override this default.
- *
- * The group leader window allows the window manager to distinguish
- * all windows that belong to a single application. It may for example
- * allow users to minimize/unminimize all windows belonging to an
- * application at once. You should only set a non-default group window
- * if your application pretends to be multiple applications.
- **/
-void
-gdk_surface_set_group (GdkSurface *window,
- GdkSurface *leader)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_group (window, leader);
-}
-
-/**
- * gdk_surface_set_decorations:
- * @window: a toplevel #GdkSurface
- * @decorations: decoration hint mask
- *
- * “Decorations” are the features the window manager adds to a toplevel #GdkSurface.
- * This function sets the traditional Motif window manager hints that tell the
- * window manager which decorations you would like your window to have.
- * Usually you should use gtk_window_set_decorated() on a #GtkWindow instead of
- * using the GDK function directly.
- *
- * The @decorations argument is the logical OR of the fields in
- * the #GdkWMDecoration enumeration. If #GDK_DECOR_ALL is included in the
- * mask, the other bits indicate which decorations should be turned off.
- * If #GDK_DECOR_ALL is not included, then the other bits indicate
- * which decorations should be turned on.
- *
- * Most window managers honor a decorations hint of 0 to disable all decorations,
- * but very few honor all possible combinations of bits.
- *
- **/
-void
-gdk_surface_set_decorations (GdkSurface *window,
- GdkWMDecoration decorations)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_decorations (window, decorations);
-}
-
-/**
- * gdk_surface_get_decorations:
- * @window: The toplevel #GdkSurface to get the decorations from
- * @decorations: (out): The window decorations will be written here
- *
- * Returns the decorations set on the GdkSurface with
- * gdk_surface_set_decorations().
- *
- * Returns: %TRUE if the window has decorations set, %FALSE otherwise.
- **/
-gboolean
-gdk_surface_get_decorations(GdkSurface *window,
- GdkWMDecoration *decorations)
-{
- return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->get_decorations (window, decorations);
-}
-
-/**
- * gdk_surface_set_functions:
- * @window: a toplevel #GdkSurface
- * @functions: bitmask of operations to allow on @window
- *
- * Sets hints about the window management functions to make available
- * via buttons on the window frame.
- *
- * On the X backend, this function sets the traditional Motif window
- * manager hint for this purpose. However, few window managers do
- * anything reliable or interesting with this hint. Many ignore it
- * entirely.
- *
- * The @functions argument is the logical OR of values from the
- * #GdkWMFunction enumeration. If the bitmask includes #GDK_FUNC_ALL,
- * then the other bits indicate which functions to disable; if
- * it doesn’t include #GDK_FUNC_ALL, it indicates which functions to
- * enable.
- *
- **/
-void
-gdk_surface_set_functions (GdkSurface *window,
- GdkWMFunction functions)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_functions (window, functions);
-}
-
-/**
- * gdk_surface_begin_resize_drag_for_device:
- * @window: a toplevel #GdkSurface
- * @edge: the edge or corner from which the drag is started
- * @device: the device used for the operation
- * @button: the button being used to drag, or 0 for a keyboard-initiated drag
- * @root_x: root window X coordinate of mouse click that began the drag
- * @root_y: root window Y coordinate of mouse click that began the drag
- * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
- *
- * Begins a window resize operation (for a toplevel window).
- * You might use this function to implement a “window resize grip,” for
- * example; in fact #GtkStatusbar uses it. The function works best
- * with window managers that support the
- * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec)
- * but has a fallback implementation for other window managers.
- */
-void
-gdk_surface_begin_resize_drag_for_device (GdkSurface *window,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->begin_resize_drag (window, edge, device, button, root_x, root_y, timestamp);
-}
-
-/**
- * gdk_surface_begin_resize_drag:
- * @window: a toplevel #GdkSurface
- * @edge: the edge or corner from which the drag is started
- * @button: the button being used to drag, or 0 for a keyboard-initiated drag
- * @root_x: root window X coordinate of mouse click that began the drag
- * @root_y: root window Y coordinate of mouse click that began the drag
- * @timestamp: timestamp of mouse click that began the drag (use gdk_event_get_time())
- *
- * Begins a window resize operation (for a toplevel window).
- *
- * This function assumes that the drag is controlled by the
- * client pointer device, use gdk_surface_begin_resize_drag_for_device()
- * to begin a drag with a different device.
- */
-void
-gdk_surface_begin_resize_drag (GdkSurface *window,
- GdkSurfaceEdge edge,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GdkDisplay *display;
- GdkDevice *device;
-
- display = gdk_surface_get_display (window);
- device = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
- gdk_surface_begin_resize_drag_for_device (window, edge,
- device, button, root_x, root_y, timestamp);
-}
-
-/**
- * gdk_surface_begin_move_drag_for_device:
- * @window: a toplevel #GdkSurface
- * @device: the device used for the operation
- * @button: the button being used to drag, or 0 for a keyboard-initiated drag
- * @root_x: root window X coordinate of mouse click that began the drag
- * @root_y: root window Y coordinate of mouse click that began the drag
- * @timestamp: timestamp of mouse click that began the drag
- *
- * Begins a window move operation (for a toplevel window).
- * You might use this function to implement a “window move grip,” for
- * example. The function works best with window managers that support the
- * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec)
- * but has a fallback implementation for other window managers.
- */
-void
-gdk_surface_begin_move_drag_for_device (GdkSurface *window,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->begin_move_drag (window,
- device, button, root_x, root_y, timestamp);
-}
-
-/**
- * gdk_surface_begin_move_drag:
- * @window: a toplevel #GdkSurface
- * @button: the button being used to drag, or 0 for a keyboard-initiated drag
- * @root_x: root window X coordinate of mouse click that began the drag
- * @root_y: root window Y coordinate of mouse click that began the drag
- * @timestamp: timestamp of mouse click that began the drag
- *
- * Begins a window move operation (for a toplevel window).
- *
- * This function assumes that the drag is controlled by the
- * client pointer device, use gdk_surface_begin_move_drag_for_device()
- * to begin a drag with a different device.
- */
-void
-gdk_surface_begin_move_drag (GdkSurface *window,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GdkDisplay *display;
- GdkDevice *device;
-
- display = gdk_surface_get_display (window);
- device = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
- gdk_surface_begin_move_drag_for_device (window, device, button, root_x, root_y, timestamp);
-}
-
-/**
- * gdk_surface_set_opacity:
- * @window: a top-level or non-native #GdkSurface
- * @opacity: opacity
- *
- * Set @window to render as partially transparent,
- * with opacity 0 being fully transparent and 1 fully opaque. (Values
- * of the opacity parameter are clamped to the [0,1] range.)
- *
- * For toplevel windows this depends on support from the windowing system
- * that may not always be there. For instance, On X11, this works only on
- * X screens with a compositing manager running. On Wayland, there is no
- * per-window opacity value that the compositor would apply. Instead, use
- * `gdk_surface_set_opaque_region (window, NULL)` to tell the compositor
- * that the entire window is (potentially) non-opaque, and draw your content
- * with alpha, or use gtk_widget_set_opacity() to set an overall opacity
- * for your widgets.
- *
- * Support for non-toplevel windows was added in 3.8.
- */
-void
-gdk_surface_set_opacity (GdkSurface *window,
- gdouble opacity)
-{
- if (opacity < 0)
- opacity = 0;
- else if (opacity > 1)
- opacity = 1;
-
- window->alpha = round (opacity * 255);
-
- if (window->destroyed)
- return;
-
- if (gdk_surface_has_impl (window))
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->set_opacity (window, opacity);
- else
- {
- recompute_visible_regions (window, FALSE);
- gdk_surface_invalidate_rect_full (window, NULL, TRUE);
- }
-}
-
-/* This function is called when the XWindow is really gone.
- */
-void
-gdk_surface_destroy_notify (GdkSurface *window)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->destroy_notify (window);
-}
-
-/**
- * gdk_surface_register_dnd:
- * @window: a #GdkSurface.
- *
- * Registers a window as a potential drop destination.
- */
-void
-gdk_surface_register_dnd (GdkSurface *window)
-{
- GDK_SURFACE_IMPL_GET_CLASS (window->impl)->register_dnd (window);
-}
-
-/**
- * gdk_drag_begin:
- * @window: the source window for this drag
- * @device: the device that controls this drag
- * @content: (transfer none): the offered content
- * @actions: the actions supported by this drag
- * @dx: the x offset to @device's position where the drag nominally started
- * @dy: the y offset to @device's position where the drag nominally started
- *
- * Starts a drag and creates a new drag context for it.
- *
- * This function is called by the drag source.
- *
- * Returns: (transfer full) (nullable): a newly created #GdkDragContext or
- * %NULL on error.
- */
-GdkDragContext *
-gdk_drag_begin (GdkSurface *window,
- GdkDevice *device,
- GdkContentProvider *content,
- GdkDragAction actions,
- gint dx,
- gint dy)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
- g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
- g_return_val_if_fail (gdk_surface_get_display (window) == gdk_device_get_display (device), NULL);
- g_return_val_if_fail (GDK_IS_CONTENT_PROVIDER (content), NULL);
-
- return GDK_SURFACE_IMPL_GET_CLASS (window->impl)->drag_begin (window, device, content, actions, dx, dy);
-}
-
-static void
-gdk_surface_flush_events (GdkFrameClock *clock,
- void *data)
-{
- GdkSurface *window;
- GdkDisplay *display;
-
- window = GDK_SURFACE (data);
-
- display = gdk_surface_get_display (window);
- _gdk_event_queue_flush (display);
- _gdk_display_pause_events (display);
-
- gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS);
-
- window->frame_clock_events_paused = TRUE;
-}
-
-static void
-gdk_surface_resume_events (GdkFrameClock *clock,
- void *data)
-{
- GdkSurface *window;
- GdkDisplay *display;
-
- window = GDK_SURFACE (data);
-
- display = gdk_surface_get_display (window);
- _gdk_display_unpause_events (display);
-
- window->frame_clock_events_paused = FALSE;
-}
-
-static void
-gdk_surface_set_frame_clock (GdkSurface *window,
- GdkFrameClock *clock)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (clock == NULL || GDK_IS_FRAME_CLOCK (clock));
- g_return_if_fail (clock == NULL || gdk_surface_is_toplevel (window));
-
- if (clock == window->frame_clock)
- return;
-
- if (clock)
- {
- g_object_ref (clock);
- g_signal_connect (G_OBJECT (clock),
- "flush-events",
- G_CALLBACK (gdk_surface_flush_events),
- window);
- g_signal_connect (G_OBJECT (clock),
- "paint",
- G_CALLBACK (gdk_surface_paint_on_clock),
- window);
- g_signal_connect (G_OBJECT (clock),
- "resume-events",
- G_CALLBACK (gdk_surface_resume_events),
- window);
- }
-
- if (window->frame_clock)
- {
- if (window->frame_clock_events_paused)
- gdk_surface_resume_events (window->frame_clock, G_OBJECT (window));
-
- g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
- G_CALLBACK (gdk_surface_flush_events),
- window);
- g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
- G_CALLBACK (gdk_surface_paint_on_clock),
- window);
- g_signal_handlers_disconnect_by_func (G_OBJECT (window->frame_clock),
- G_CALLBACK (gdk_surface_resume_events),
- window);
- g_object_unref (window->frame_clock);
- }
-
- window->frame_clock = clock;
-}
-
-/**
- * gdk_surface_get_frame_clock:
- * @window: window to get frame clock for
- *
- * Gets the frame clock for the window. The frame clock for a window
- * never changes unless the window is reparented to a new toplevel
- * window.
- *
- * Returns: (transfer none): the frame clock
- */
-GdkFrameClock*
-gdk_surface_get_frame_clock (GdkSurface *window)
-{
- GdkSurface *toplevel;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- toplevel = gdk_surface_get_toplevel (window);
-
- return toplevel->frame_clock;
-}
-
-/**
- * gdk_surface_get_scale_factor:
- * @window: window to get scale factor for
- *
- * Returns the internal scale factor that maps from window coordiantes
- * to the actual device pixels. On traditional systems this is 1, but
- * on very high density outputs this can be a higher value (often 2).
- *
- * A higher value means that drawing is automatically scaled up to
- * a higher resolution, so any code doing drawing will automatically look
- * nicer. However, if you are supplying pixel-based data the scale
- * value can be used to determine whether to use a pixel resource
- * with higher resolution data.
- *
- * The scale of a window may change during runtime, if this happens
- * a configure event will be sent to the toplevel window.
- *
- * Returns: the scale factor
- */
-gint
-gdk_surface_get_scale_factor (GdkSurface *window)
-{
- GdkSurfaceImplClass *impl_class;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), 1);
-
- if (GDK_SURFACE_DESTROYED (window))
- return 1;
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- if (impl_class->get_scale_factor)
- return impl_class->get_scale_factor (window);
-
- return 1;
-}
-
-/* Returns the *real* unscaled size, which may be a fractional size
- in window scale coordinates. We need this to properly handle GL
- coordinates which are y-flipped in the real coordinates. */
-void
-gdk_surface_get_unscaled_size (GdkSurface *window,
- int *unscaled_width,
- int *unscaled_height)
-{
- GdkSurfaceImplClass *impl_class;
- gint scale;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->impl_window == window)
- {
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- if (impl_class->get_unscaled_size)
- {
- impl_class->get_unscaled_size (window, unscaled_width, unscaled_height);
- return;
- }
- }
-
- scale = gdk_surface_get_scale_factor (window);
-
- if (unscaled_width)
- *unscaled_width = window->width * scale;
-
- if (unscaled_height)
- *unscaled_height = window->height * scale;
-}
-
-
-/**
- * gdk_surface_set_opaque_region:
- * @window: a top-level or non-native #GdkSurface
- * @region: (allow-none): a region, or %NULL
- *
- * For optimisation purposes, compositing window managers may
- * like to not draw obscured regions of windows, or turn off blending
- * during for these regions. With RGB windows with no transparency,
- * this is just the shape of the window, but with ARGB32 windows, the
- * compositor does not know what regions of the window are transparent
- * or not.
- *
- * This function only works for toplevel windows.
- *
- * GTK+ will update this property automatically if
- * the @window background is opaque, as we know where the opaque regions
- * are. If your window background is not opaque, please update this
- * property in your #GtkWidget::style-updated handler.
- */
-void
-gdk_surface_set_opaque_region (GdkSurface *window,
- cairo_region_t *region)
-{
- GdkSurfaceImplClass *impl_class;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (!GDK_SURFACE_DESTROYED (window));
-
- if (cairo_region_equal (window->opaque_region, region))
- return;
-
- g_clear_pointer (&window->opaque_region, cairo_region_destroy);
-
- if (region != NULL)
- window->opaque_region = cairo_region_reference (region);
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- if (impl_class->set_opaque_region)
- impl_class->set_opaque_region (window, region);
-}
-
-/**
- * gdk_surface_set_shadow_width:
- * @window: a #GdkSurface
- * @left: The left extent
- * @right: The right extent
- * @top: The top extent
- * @bottom: The bottom extent
- *
- * Newer GTK+ windows using client-side decorations use extra geometry
- * around their frames for effects like shadows and invisible borders.
- * Window managers that want to maximize windows or snap to edges need
- * to know where the extents of the actual frame lie, so that users
- * don’t feel like windows are snapping against random invisible edges.
- *
- * 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.
- */
-void
-gdk_surface_set_shadow_width (GdkSurface *window,
- gint left,
- gint right,
- gint top,
- gint bottom)
-{
- GdkSurfaceImplClass *impl_class;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (!GDK_SURFACE_DESTROYED (window));
- g_return_if_fail (left >= 0 && right >= 0 && top >= 0 && bottom >= 0);
-
- window->shadow_top = top;
- window->shadow_left = left;
- window->shadow_right = right;
- window->shadow_bottom = bottom;
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- if (impl_class->set_shadow_width)
- impl_class->set_shadow_width (window, left, right, top, bottom);
-}
-
-/**
- * gdk_surface_show_window_menu:
- * @window: a #GdkSurface
- * @event: a #GdkEvent to show the menu for
- *
- * Asks the windowing system to show the window menu. The window menu
- * is the menu shown when right-clicking the titlebar on traditional
- * windows managed by the window manager. This is useful for windows
- * using client-side decorations, activating it with a right-click
- * on the window decorations.
- *
- * Returns: %TRUE if the window menu was shown and %FALSE otherwise.
- */
-gboolean
-gdk_surface_show_window_menu (GdkSurface *window,
- GdkEvent *event)
-{
- GdkSurfaceImplClass *impl_class;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
- g_return_val_if_fail (!GDK_SURFACE_DESTROYED (window), FALSE);
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- if (impl_class->show_window_menu)
- return impl_class->show_window_menu (window, event);
- else
- return FALSE;
-}
-
-gboolean
-gdk_surface_supports_edge_constraints (GdkSurface *window)
-{
- GdkSurfaceImplClass *impl_class;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
- g_return_val_if_fail (!GDK_SURFACE_DESTROYED (window), FALSE);
-
- impl_class = GDK_SURFACE_IMPL_GET_CLASS (window->impl);
-
- if (impl_class->supports_edge_constraints)
- return impl_class->supports_edge_constraints (window);
- else
- return FALSE;
-}
-
-void
-gdk_surface_set_state (GdkSurface *window,
- GdkSurfaceState new_state)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (new_state == window->state)
- return; /* No actual work to do, nothing changed. */
-
- /* Actually update the field in GdkSurface, this is sort of an odd
- * place to do it, but seems like the safest since it ensures we expose no
- * inconsistent state to the user.
- */
-
- window->state = new_state;
-
- _gdk_surface_update_viewable (window);
-
- /* We only really send the event to toplevels, since
- * all the window states don't apply to non-toplevels.
- * Non-toplevels do use the GDK_SURFACE_STATE_WITHDRAWN flag
- * internally so we needed to update window->state.
- */
- switch (window->window_type)
- {
- case GDK_SURFACE_TOPLEVEL:
- case GDK_SURFACE_TEMP: /* ? */
- g_object_notify (G_OBJECT (window), "state");
- break;
- case GDK_SURFACE_FOREIGN:
- case GDK_SURFACE_ROOT:
- case GDK_SURFACE_CHILD:
- default:
- break;
- }
-}
-
-void
-gdk_synthesize_window_state (GdkSurface *window,
- GdkSurfaceState unset_flags,
- GdkSurfaceState set_flags)
-{
- gdk_surface_set_state (window, (window->state | set_flags) & ~unset_flags);
-}
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#ifndef __GDK_SURFACE_H__
-#define __GDK_SURFACE_H__
-
-#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
-#error "Only <gdk/gdk.h> can be included directly."
-#endif
-
-#include <gdk/gdkversionmacros.h>
-#include <gdk/gdktypes.h>
-#include <gdk/gdkdrawingcontext.h>
-#include <gdk/gdkevents.h>
-#include <gdk/gdkframeclock.h>
-#include <gdk/gdkmonitor.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GdkGeometry GdkGeometry;
-
-/**
- * GdkSurfaceType:
- * @GDK_SURFACE_ROOT: root window; this window has no parent, covers the entire
- * screen, and is created by the window system
- * @GDK_SURFACE_TOPLEVEL: toplevel window (used to implement #GtkWindow)
- * @GDK_SURFACE_CHILD: child window (used to implement e.g. #GtkEntry)
- * @GDK_SURFACE_TEMP: override redirect temporary window (used to implement
- * #GtkMenu)
- * @GDK_SURFACE_FOREIGN: foreign window (see gdk_surface_foreign_new())
- * @GDK_SURFACE_SUBSURFACE: subsurface-based window; This window is visually
- * tied to a toplevel, and is moved/stacked with it. Currently this window
- * type is only implemented in Wayland. Since 3.14
- *
- * Describes the kind of window.
- */
-typedef enum
-{
- GDK_SURFACE_ROOT,
- GDK_SURFACE_TOPLEVEL,
- GDK_SURFACE_CHILD,
- GDK_SURFACE_TEMP,
- GDK_SURFACE_FOREIGN,
- GDK_SURFACE_SUBSURFACE
-} GdkSurfaceType;
-
-/* Size restriction enumeration.
- */
-/**
- * GdkSurfaceHints:
- * @GDK_HINT_POS: indicates that the program has positioned the window
- * @GDK_HINT_MIN_SIZE: min size fields are set
- * @GDK_HINT_MAX_SIZE: max size fields are set
- * @GDK_HINT_BASE_SIZE: base size fields are set
- * @GDK_HINT_ASPECT: aspect ratio fields are set
- * @GDK_HINT_RESIZE_INC: resize increment fields are set
- * @GDK_HINT_WIN_GRAVITY: window gravity field is set
- * @GDK_HINT_USER_POS: indicates that the window’s position was explicitly set
- * by the user
- * @GDK_HINT_USER_SIZE: indicates that the window’s size was explicitly set by
- * the user
- *
- * Used to indicate which fields of a #GdkGeometry struct should be paid
- * attention to. Also, the presence/absence of @GDK_HINT_POS,
- * @GDK_HINT_USER_POS, and @GDK_HINT_USER_SIZE is significant, though they don't
- * directly refer to #GdkGeometry fields. @GDK_HINT_USER_POS will be set
- * automatically by #GtkWindow if you call gtk_window_move().
- * @GDK_HINT_USER_POS and @GDK_HINT_USER_SIZE should be set if the user
- * specified a size/position using a --geometry command-line argument;
- * gtk_window_parse_geometry() automatically sets these flags.
- */
-typedef enum
-{
- GDK_HINT_POS = 1 << 0,
- GDK_HINT_MIN_SIZE = 1 << 1,
- GDK_HINT_MAX_SIZE = 1 << 2,
- GDK_HINT_BASE_SIZE = 1 << 3,
- GDK_HINT_ASPECT = 1 << 4,
- GDK_HINT_RESIZE_INC = 1 << 5,
- GDK_HINT_WIN_GRAVITY = 1 << 6,
- GDK_HINT_USER_POS = 1 << 7,
- GDK_HINT_USER_SIZE = 1 << 8
-} GdkSurfaceHints;
-
-/* The next two enumeration values current match the
- * Motif constants. If this is changed, the implementation
- * of gdk_surface_set_decorations/gdk_surface_set_functions
- * will need to change as well.
- */
-/**
- * GdkWMDecoration:
- * @GDK_DECOR_ALL: all decorations should be applied.
- * @GDK_DECOR_BORDER: a frame should be drawn around the window.
- * @GDK_DECOR_RESIZEH: the frame should have resize handles.
- * @GDK_DECOR_TITLE: a titlebar should be placed above the window.
- * @GDK_DECOR_MENU: a button for opening a menu should be included.
- * @GDK_DECOR_MINIMIZE: a minimize button should be included.
- * @GDK_DECOR_MAXIMIZE: a maximize button should be included.
- *
- * These are hints originally defined by the Motif toolkit.
- * The window manager can use them when determining how to decorate
- * the window. The hint must be set before mapping the window.
- */
-typedef enum
-{
- GDK_DECOR_ALL = 1 << 0,
- GDK_DECOR_BORDER = 1 << 1,
- GDK_DECOR_RESIZEH = 1 << 2,
- GDK_DECOR_TITLE = 1 << 3,
- GDK_DECOR_MENU = 1 << 4,
- GDK_DECOR_MINIMIZE = 1 << 5,
- GDK_DECOR_MAXIMIZE = 1 << 6
-} GdkWMDecoration;
-
-/**
- * GdkWMFunction:
- * @GDK_FUNC_ALL: all functions should be offered.
- * @GDK_FUNC_RESIZE: the window should be resizable.
- * @GDK_FUNC_MOVE: the window should be movable.
- * @GDK_FUNC_MINIMIZE: the window should be minimizable.
- * @GDK_FUNC_MAXIMIZE: the window should be maximizable.
- * @GDK_FUNC_CLOSE: the window should be closable.
- *
- * These are hints originally defined by the Motif toolkit. The window manager
- * can use them when determining the functions to offer for the window. The
- * hint must be set before mapping the window.
- */
-typedef enum
-{
- GDK_FUNC_ALL = 1 << 0,
- GDK_FUNC_RESIZE = 1 << 1,
- GDK_FUNC_MOVE = 1 << 2,
- GDK_FUNC_MINIMIZE = 1 << 3,
- GDK_FUNC_MAXIMIZE = 1 << 4,
- GDK_FUNC_CLOSE = 1 << 5
-} GdkWMFunction;
-
-/* Currently, these are the same values numerically as in the
- * X protocol. If you change that, gdkwindow-x11.c/gdk_surface_set_geometry_hints()
- * will need fixing.
- */
-/**
- * GdkGravity:
- * @GDK_GRAVITY_NORTH_WEST: the reference point is at the top left corner.
- * @GDK_GRAVITY_NORTH: the reference point is in the middle of the top edge.
- * @GDK_GRAVITY_NORTH_EAST: the reference point is at the top right corner.
- * @GDK_GRAVITY_WEST: the reference point is at the middle of the left edge.
- * @GDK_GRAVITY_CENTER: the reference point is at the center of the window.
- * @GDK_GRAVITY_EAST: the reference point is at the middle of the right edge.
- * @GDK_GRAVITY_SOUTH_WEST: the reference point is at the lower left corner.
- * @GDK_GRAVITY_SOUTH: the reference point is at the middle of the lower edge.
- * @GDK_GRAVITY_SOUTH_EAST: the reference point is at the lower right corner.
- * @GDK_GRAVITY_STATIC: the reference point is at the top left corner of the
- * window itself, ignoring window manager decorations.
- *
- * Defines the reference point of a window and the meaning of coordinates
- * passed to gtk_window_move(). See gtk_window_move() and the "implementation
- * notes" section of the
- * [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec)
- * specification for more details.
- */
-typedef enum
-{
- GDK_GRAVITY_NORTH_WEST = 1,
- GDK_GRAVITY_NORTH,
- GDK_GRAVITY_NORTH_EAST,
- GDK_GRAVITY_WEST,
- GDK_GRAVITY_CENTER,
- GDK_GRAVITY_EAST,
- GDK_GRAVITY_SOUTH_WEST,
- GDK_GRAVITY_SOUTH,
- GDK_GRAVITY_SOUTH_EAST,
- GDK_GRAVITY_STATIC
-} GdkGravity;
-
-/**
- * GdkAnchorHints:
- * @GDK_ANCHOR_FLIP_X: allow flipping anchors horizontally
- * @GDK_ANCHOR_FLIP_Y: allow flipping anchors vertically
- * @GDK_ANCHOR_SLIDE_X: allow sliding window horizontally
- * @GDK_ANCHOR_SLIDE_Y: allow sliding window vertically
- * @GDK_ANCHOR_RESIZE_X: allow resizing window horizontally
- * @GDK_ANCHOR_RESIZE_Y: allow resizing window vertically
- * @GDK_ANCHOR_FLIP: allow flipping anchors on both axes
- * @GDK_ANCHOR_SLIDE: allow sliding window on both axes
- * @GDK_ANCHOR_RESIZE: allow resizing window on both axes
- *
- * Positioning hints for aligning a window relative to a rectangle.
- *
- * These hints determine how the window should be positioned in the case that
- * the window would fall off-screen if placed in its ideal position.
- *
- * For example, %GDK_ANCHOR_FLIP_X will replace %GDK_GRAVITY_NORTH_WEST with
- * %GDK_GRAVITY_NORTH_EAST and vice versa if the window extends beyond the left
- * or right edges of the monitor.
- *
- * If %GDK_ANCHOR_SLIDE_X is set, the window can be shifted horizontally to fit
- * on-screen. If %GDK_ANCHOR_RESIZE_X is set, the window can be shrunken
- * horizontally to fit.
- *
- * In general, when multiple flags are set, flipping should take precedence over
- * sliding, which should take precedence over resizing.
- *
- * Since: 3.22
- * Stability: Unstable
- */
-typedef enum
-{
- GDK_ANCHOR_FLIP_X = 1 << 0,
- GDK_ANCHOR_FLIP_Y = 1 << 1,
- GDK_ANCHOR_SLIDE_X = 1 << 2,
- GDK_ANCHOR_SLIDE_Y = 1 << 3,
- GDK_ANCHOR_RESIZE_X = 1 << 4,
- GDK_ANCHOR_RESIZE_Y = 1 << 5,
- GDK_ANCHOR_FLIP = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_FLIP_Y,
- GDK_ANCHOR_SLIDE = GDK_ANCHOR_SLIDE_X | GDK_ANCHOR_SLIDE_Y,
- GDK_ANCHOR_RESIZE = GDK_ANCHOR_RESIZE_X | GDK_ANCHOR_RESIZE_Y
-} GdkAnchorHints;
-
-/**
- * GdkSurfaceEdge:
- * @GDK_SURFACE_EDGE_NORTH_WEST: the top left corner.
- * @GDK_SURFACE_EDGE_NORTH: the top edge.
- * @GDK_SURFACE_EDGE_NORTH_EAST: the top right corner.
- * @GDK_SURFACE_EDGE_WEST: the left edge.
- * @GDK_SURFACE_EDGE_EAST: the right edge.
- * @GDK_SURFACE_EDGE_SOUTH_WEST: the lower left corner.
- * @GDK_SURFACE_EDGE_SOUTH: the lower edge.
- * @GDK_SURFACE_EDGE_SOUTH_EAST: the lower right corner.
- *
- * Determines a window edge or corner.
- */
-typedef enum
-{
- GDK_SURFACE_EDGE_NORTH_WEST,
- GDK_SURFACE_EDGE_NORTH,
- GDK_SURFACE_EDGE_NORTH_EAST,
- GDK_SURFACE_EDGE_WEST,
- GDK_SURFACE_EDGE_EAST,
- GDK_SURFACE_EDGE_SOUTH_WEST,
- GDK_SURFACE_EDGE_SOUTH,
- GDK_SURFACE_EDGE_SOUTH_EAST
-} GdkSurfaceEdge;
-
-/**
- * GdkFullscreenMode:
- * @GDK_FULLSCREEN_ON_CURRENT_MONITOR: Fullscreen on current monitor only.
- * @GDK_FULLSCREEN_ON_ALL_MONITORS: Span across all monitors when fullscreen.
- *
- * Indicates which monitor (in a multi-head setup) a window should span over
- * when in fullscreen mode.
- *
- * Since: 3.8
- **/
-typedef enum
-{
- GDK_FULLSCREEN_ON_CURRENT_MONITOR,
- GDK_FULLSCREEN_ON_ALL_MONITORS
-} GdkFullscreenMode;
-
-/**
- * GdkGeometry:
- * @min_width: minimum width of window (or -1 to use requisition, with
- * #GtkWindow only)
- * @min_height: minimum height of window (or -1 to use requisition, with
- * #GtkWindow only)
- * @max_width: maximum width of window (or -1 to use requisition, with
- * #GtkWindow only)
- * @max_height: maximum height of window (or -1 to use requisition, with
- * #GtkWindow only)
- * @base_width: allowed window widths are @base_width + @width_inc * N where N
- * is any integer (-1 allowed with #GtkWindow)
- * @base_height: allowed window widths are @base_height + @height_inc * N where
- * N is any integer (-1 allowed with #GtkWindow)
- * @width_inc: width resize increment
- * @height_inc: height resize increment
- * @min_aspect: minimum width/height ratio
- * @max_aspect: maximum width/height ratio
- * @win_gravity: window gravity, see gtk_window_set_gravity()
- *
- * The #GdkGeometry struct gives the window manager information about
- * a window’s geometry constraints. Normally you would set these on
- * the GTK+ level using gtk_window_set_geometry_hints(). #GtkWindow
- * then sets the hints on the #GdkSurface it creates.
- *
- * gdk_surface_set_geometry_hints() expects the hints to be fully valid already
- * and simply passes them to the window manager; in contrast,
- * gtk_window_set_geometry_hints() performs some interpretation. For example,
- * #GtkWindow will apply the hints to the geometry widget instead of the
- * toplevel window, if you set a geometry widget. Also, the
- * @min_width/@min_height/@max_width/@max_height fields may be set to -1, and
- * #GtkWindow will substitute the size request of the window or geometry widget.
- * If the minimum size hint is not provided, #GtkWindow will use its requisition
- * as the minimum size. If the minimum size is provided and a geometry widget is
- * set, #GtkWindow will take the minimum size as the minimum size of the
- * geometry widget rather than the entire window. The base size is treated
- * similarly.
- *
- * The canonical use-case for gtk_window_set_geometry_hints() is to get a
- * terminal widget to resize properly. Here, the terminal text area should be
- * the geometry widget; #GtkWindow will then automatically set the base size to
- * the size of other widgets in the terminal window, such as the menubar and
- * scrollbar. Then, the @width_inc and @height_inc fields should be set to the
- * size of one character in the terminal. Finally, the base size should be set
- * to the size of one character. The net effect is that the minimum size of the
- * terminal will have a 1x1 character terminal area, and only terminal sizes on
- * the “character grid” will be allowed.
- *
- * Here’s an example of how the terminal example would be implemented, assuming
- * a terminal area widget called “terminal” and a toplevel window “toplevel”:
- *
- * |[<!-- language="C" -->
- * GdkGeometry hints;
- *
- * hints.base_width = terminal->char_width;
- * hints.base_height = terminal->char_height;
- * hints.min_width = terminal->char_width;
- * hints.min_height = terminal->char_height;
- * hints.width_inc = terminal->char_width;
- * hints.height_inc = terminal->char_height;
- *
- * gtk_window_set_geometry_hints (GTK_WINDOW (toplevel),
- * GTK_WIDGET (terminal),
- * &hints,
- * GDK_HINT_RESIZE_INC |
- * GDK_HINT_MIN_SIZE |
- * GDK_HINT_BASE_SIZE);
- * ]|
- *
- * The other useful fields are the @min_aspect and @max_aspect fields; these
- * contain a width/height ratio as a floating point number. If a geometry widget
- * is set, the aspect applies to the geometry widget rather than the entire
- * window. The most common use of these hints is probably to set @min_aspect and
- * @max_aspect to the same value, thus forcing the window to keep a constant
- * aspect ratio.
- */
-struct _GdkGeometry
-{
- gint min_width;
- gint min_height;
- gint max_width;
- gint max_height;
- gint base_width;
- gint base_height;
- gint width_inc;
- gint height_inc;
- gdouble min_aspect;
- gdouble max_aspect;
- GdkGravity win_gravity;
-};
-
-/**
- * GdkSurfaceState:
- * @GDK_SURFACE_STATE_WITHDRAWN: the window is not shown.
- * @GDK_SURFACE_STATE_ICONIFIED: the window is minimized.
- * @GDK_SURFACE_STATE_MAXIMIZED: the window is maximized.
- * @GDK_SURFACE_STATE_STICKY: the window is sticky.
- * @GDK_SURFACE_STATE_FULLSCREEN: the window is maximized without
- * decorations.
- * @GDK_SURFACE_STATE_ABOVE: the window is kept above other windows.
- * @GDK_SURFACE_STATE_BELOW: the window is kept below other windows.
- * @GDK_SURFACE_STATE_FOCUSED: the window is presented as focused (with active decorations).
- * @GDK_SURFACE_STATE_TILED: the window is in a tiled state, Since 3.10. Since 3.91.2, this
- * is deprecated in favor of per-edge information.
- * @GDK_SURFACE_STATE_TOP_TILED: whether the top edge is tiled, Since 3.91.2
- * @GDK_SURFACE_STATE_TOP_RESIZABLE: whether the top edge is resizable, Since 3.91.2
- * @GDK_SURFACE_STATE_RIGHT_TILED: whether the right edge is tiled, Since 3.91.2
- * @GDK_SURFACE_STATE_RIGHT_RESIZABLE: whether the right edge is resizable, Since 3.91.2
- * @GDK_SURFACE_STATE_BOTTOM_TILED: whether the bottom edge is tiled, Since 3.91.2
- * @GDK_SURFACE_STATE_BOTTOM_RESIZABLE: whether the bottom edge is resizable, Since 3.91.2
- * @GDK_SURFACE_STATE_LEFT_TILED: whether the left edge is tiled, Since 3.91.2
- * @GDK_SURFACE_STATE_LEFT_RESIZABLE: whether the left edge is resizable, Since 3.91.2
- *
- * Specifies the state of a toplevel window.
- */
-typedef enum
-{
- GDK_SURFACE_STATE_WITHDRAWN = 1 << 0,
- GDK_SURFACE_STATE_ICONIFIED = 1 << 1,
- GDK_SURFACE_STATE_MAXIMIZED = 1 << 2,
- GDK_SURFACE_STATE_STICKY = 1 << 3,
- GDK_SURFACE_STATE_FULLSCREEN = 1 << 4,
- GDK_SURFACE_STATE_ABOVE = 1 << 5,
- GDK_SURFACE_STATE_BELOW = 1 << 6,
- GDK_SURFACE_STATE_FOCUSED = 1 << 7,
- GDK_SURFACE_STATE_TILED = 1 << 8,
- GDK_SURFACE_STATE_TOP_TILED = 1 << 9,
- GDK_SURFACE_STATE_TOP_RESIZABLE = 1 << 10,
- GDK_SURFACE_STATE_RIGHT_TILED = 1 << 11,
- GDK_SURFACE_STATE_RIGHT_RESIZABLE = 1 << 12,
- GDK_SURFACE_STATE_BOTTOM_TILED = 1 << 13,
- GDK_SURFACE_STATE_BOTTOM_RESIZABLE = 1 << 14,
- GDK_SURFACE_STATE_LEFT_TILED = 1 << 15,
- GDK_SURFACE_STATE_LEFT_RESIZABLE = 1 << 16
-} GdkSurfaceState;
-
-
-typedef struct _GdkSurfaceClass GdkSurfaceClass;
-
-#define GDK_TYPE_SURFACE (gdk_surface_get_type ())
-#define GDK_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE, GdkSurface))
-#define GDK_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE, GdkSurfaceClass))
-#define GDK_IS_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE))
-#define GDK_IS_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE))
-#define GDK_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE, GdkSurfaceClass))
-
-
-struct _GdkSurfaceClass
-{
- GObjectClass parent_class;
-
- /* Padding for future expansion */
- void (*_gdk_reserved1) (void);
- void (*_gdk_reserved2) (void);
- void (*_gdk_reserved3) (void);
- void (*_gdk_reserved4) (void);
- void (*_gdk_reserved5) (void);
- void (*_gdk_reserved6) (void);
- void (*_gdk_reserved7) (void);
- void (*_gdk_reserved8) (void);
-};
-
-/* Windows
- */
-GDK_AVAILABLE_IN_ALL
-GType gdk_surface_get_type (void) G_GNUC_CONST;
-GDK_AVAILABLE_IN_ALL
-GdkSurface * gdk_surface_new_toplevel (GdkDisplay *display,
- int width,
- int height);
-GDK_AVAILABLE_IN_ALL
-GdkSurface * gdk_surface_new_popup (GdkDisplay *display,
- const GdkRectangle *position);
-GDK_AVAILABLE_IN_ALL
-GdkSurface * gdk_surface_new_temp (GdkDisplay *display);
-GDK_AVAILABLE_IN_ALL
-GdkSurface * gdk_surface_new_child (GdkSurface *parent,
- const GdkRectangle *position);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_destroy (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-GdkSurfaceType gdk_surface_get_window_type (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_is_destroyed (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-GdkDisplay * gdk_surface_get_display (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_show (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_hide (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_withdraw (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_show_unraised (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_move (GdkSurface *window,
- gint x,
- gint y);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_resize (GdkSurface *window,
- gint width,
- gint height);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_move_resize (GdkSurface *window,
- gint x,
- gint y,
- gint width,
- gint height);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_raise (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_lower (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_restack (GdkSurface *window,
- GdkSurface *sibling,
- gboolean above);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_focus (GdkSurface *window,
- guint32 timestamp);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_user_data (GdkSurface *window,
- gpointer user_data);
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_get_accept_focus (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_accept_focus (GdkSurface *window,
- gboolean accept_focus);
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_get_focus_on_map (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_focus_on_map (GdkSurface *window,
- gboolean focus_on_map);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_scroll (GdkSurface *window,
- gint dx,
- gint dy);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_move_region (GdkSurface *window,
- const cairo_region_t *region,
- gint dx,
- gint dy);
-
-/*
- * This allows for making shaped (partially transparent) windows
- * - cool feature, needed for Drag and Drag for example.
- */
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y);
-
-/*
- * This routine allows you to quickly take the shapes of all the child windows
- * of a window and use their shapes as the shape mask for this window - useful
- * for container windows that dont want to look like a big box
- *
- * - Raster
- */
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_child_shapes (GdkSurface *window);
-
-/*
- * This routine allows you to merge (ie ADD) child shapes to your
- * own window’s shape keeping its current shape and ADDING the child
- * shapes to it.
- *
- * - Raster
- */
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_merge_child_shapes (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_input_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_child_input_shapes (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_merge_child_input_shapes (GdkSurface *window);
-
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_pass_through (GdkSurface *window,
- gboolean pass_through);
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_get_pass_through (GdkSurface *window);
-
-/*
- * Check if a window has been shown, and whether all its
- * parents up to a toplevel have been shown, respectively.
- * Note that a window that is_viewable below is not necessarily
- * viewable in the X sense.
- */
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_is_visible (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_is_viewable (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_is_input_only (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_is_shaped (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-GdkSurfaceState gdk_surface_get_state (GdkSurface *window);
-
-
-/* GdkSurface */
-
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_has_native (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_type_hint (GdkSurface *window,
- GdkSurfaceTypeHint hint);
-GDK_AVAILABLE_IN_ALL
-GdkSurfaceTypeHint gdk_surface_get_type_hint (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_get_modal_hint (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_modal_hint (GdkSurface *window,
- gboolean modal);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_skip_taskbar_hint (GdkSurface *window,
- gboolean skips_taskbar);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_skip_pager_hint (GdkSurface *window,
- gboolean skips_pager);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_urgency_hint (GdkSurface *window,
- gboolean urgent);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_geometry_hints (GdkSurface *window,
- const GdkGeometry *geometry,
- GdkSurfaceHints geom_mask);
-
-GDK_AVAILABLE_IN_ALL
-cairo_region_t *gdk_surface_get_clip_region (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-cairo_region_t *gdk_surface_get_visible_region(GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-GdkDrawingContext *gdk_surface_begin_draw_frame (GdkSurface *window,
- GdkDrawContext *context,
- const cairo_region_t *region);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_end_draw_frame (GdkSurface *window,
- GdkDrawingContext *context);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_title (GdkSurface *window,
- const gchar *title);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_role (GdkSurface *window,
- const gchar *role);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_startup_id (GdkSurface *window,
- const gchar *startup_id);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_transient_for (GdkSurface *window,
- GdkSurface *parent);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_cursor (GdkSurface *window,
- GdkCursor *cursor);
-GDK_AVAILABLE_IN_ALL
-GdkCursor *gdk_surface_get_cursor (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_device_cursor (GdkSurface *window,
- GdkDevice *device,
- GdkCursor *cursor);
-GDK_AVAILABLE_IN_ALL
-GdkCursor *gdk_surface_get_device_cursor (GdkSurface *window,
- GdkDevice *device);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_get_user_data (GdkSurface *window,
- gpointer *data);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_get_geometry (GdkSurface *window,
- gint *x,
- gint *y,
- gint *width,
- gint *height);
-GDK_AVAILABLE_IN_ALL
-int gdk_surface_get_width (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-int gdk_surface_get_height (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_get_position (GdkSurface *window,
- gint *x,
- gint *y);
-GDK_AVAILABLE_IN_ALL
-gint gdk_surface_get_origin (GdkSurface *window,
- gint *x,
- gint *y);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_get_root_coords (GdkSurface *window,
- gint x,
- gint y,
- gint *root_x,
- gint *root_y);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_coords_to_parent (GdkSurface *window,
- gdouble x,
- gdouble y,
- gdouble *parent_x,
- gdouble *parent_y);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_coords_from_parent (GdkSurface *window,
- gdouble parent_x,
- gdouble parent_y,
- gdouble *x,
- gdouble *y);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_get_root_origin (GdkSurface *window,
- gint *x,
- gint *y);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_get_frame_extents (GdkSurface *window,
- GdkRectangle *rect);
-
-GDK_AVAILABLE_IN_ALL
-gint gdk_surface_get_scale_factor (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-GdkSurface * gdk_surface_get_device_position (GdkSurface *window,
- GdkDevice *device,
- gint *x,
- gint *y,
- GdkModifierType *mask);
-GDK_AVAILABLE_IN_ALL
-GdkSurface * gdk_surface_get_device_position_double (GdkSurface *window,
- GdkDevice *device,
- gdouble *x,
- gdouble *y,
- GdkModifierType *mask);
-GDK_AVAILABLE_IN_ALL
-GdkSurface * gdk_surface_get_parent (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-GdkSurface * gdk_surface_get_toplevel (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-GList * gdk_surface_get_children (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-GList * gdk_surface_peek_children (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-GList * gdk_surface_get_children_with_user_data (GdkSurface *window,
- gpointer user_data);
-
-GDK_AVAILABLE_IN_ALL
-GdkEventMask gdk_surface_get_events (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_events (GdkSurface *window,
- GdkEventMask event_mask);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_device_events (GdkSurface *window,
- GdkDevice *device,
- GdkEventMask event_mask);
-GDK_AVAILABLE_IN_ALL
-GdkEventMask gdk_surface_get_device_events (GdkSurface *window,
- GdkDevice *device);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_icon_list (GdkSurface *window,
- GList *surfaces);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_icon_name (GdkSurface *window,
- const gchar *name);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_group (GdkSurface *window,
- GdkSurface *leader);
-GDK_AVAILABLE_IN_ALL
-GdkSurface* gdk_surface_get_group (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_decorations (GdkSurface *window,
- GdkWMDecoration decorations);
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_get_decorations (GdkSurface *window,
- GdkWMDecoration *decorations);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_functions (GdkSurface *window,
- GdkWMFunction functions);
-
-GDK_AVAILABLE_IN_ALL
-cairo_surface_t *
- gdk_surface_create_similar_surface (GdkSurface *window,
- cairo_content_t content,
- int width,
- int height);
-GDK_AVAILABLE_IN_ALL
-cairo_surface_t *
- gdk_surface_create_similar_image_surface (GdkSurface *window,
- cairo_format_t format,
- int width,
- int height,
- int scale);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_beep (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_iconify (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_deiconify (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_stick (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_unstick (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_maximize (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_unmaximize (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_fullscreen (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_fullscreen_on_monitor (GdkSurface *window,
- GdkMonitor *monitor);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_fullscreen_mode (GdkSurface *window,
- GdkFullscreenMode mode);
-GDK_AVAILABLE_IN_ALL
-GdkFullscreenMode
- gdk_surface_get_fullscreen_mode (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_unfullscreen (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_keep_above (GdkSurface *window,
- gboolean setting);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_keep_below (GdkSurface *window,
- gboolean setting);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_opacity (GdkSurface *window,
- gdouble opacity);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_register_dnd (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_begin_resize_drag (GdkSurface *window,
- GdkSurfaceEdge edge,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_begin_resize_drag_for_device (GdkSurface *window,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_begin_move_drag (GdkSurface *window,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_begin_move_drag_for_device (GdkSurface *window,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp);
-
-/* Interface for dirty-region queueing */
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_invalidate_rect (GdkSurface *window,
- const GdkRectangle *rect,
- gboolean invalidate_children);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_invalidate_region (GdkSurface *window,
- const cairo_region_t *region,
- gboolean invalidate_children);
-
-/**
- * GdkSurfaceChildFunc:
- * @window: a #GdkSurface
- * @user_data: user data
- *
- * A function of this type is passed to gdk_surface_invalidate_maybe_recurse().
- * It gets called for each child of the window to determine whether to
- * recursively invalidate it or now.
- *
- * Returns: %TRUE to invalidate @window recursively
- */
-typedef gboolean (*GdkSurfaceChildFunc) (GdkSurface *window,
- gpointer user_data);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_invalidate_maybe_recurse (GdkSurface *window,
- const cairo_region_t *region,
- GdkSurfaceChildFunc child_func,
- gpointer user_data);
-GDK_AVAILABLE_IN_ALL
-cairo_region_t *gdk_surface_get_update_area (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_freeze_updates (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_thaw_updates (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_constrain_size (GdkGeometry *geometry,
- GdkSurfaceHints flags,
- gint width,
- gint height,
- gint *new_width,
- gint *new_height);
-
-/* Multidevice support */
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_support_multidevice (GdkSurface *window,
- gboolean support_multidevice);
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_get_support_multidevice (GdkSurface *window);
-
-/* Frame clock */
-GDK_AVAILABLE_IN_ALL
-GdkFrameClock* gdk_surface_get_frame_clock (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_opaque_region (GdkSurface *window,
- cairo_region_t *region);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_surface_set_shadow_width (GdkSurface *window,
- gint left,
- gint right,
- gint top,
- gint bottom);
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_surface_show_window_menu (GdkSurface *window,
- GdkEvent *event);
-
-GDK_AVAILABLE_IN_ALL
-GdkGLContext * gdk_surface_create_gl_context (GdkSurface *window,
- GError **error);
-GDK_AVAILABLE_IN_ALL
-GdkVulkanContext *
- gdk_surface_create_vulkan_context(GdkSurface *window,
- GError **error);
-
-G_END_DECLS
-
-#endif /* __GDK_SURFACE_H__ */
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#include "config.h"
-
-#include "gdkwindowimpl.h"
-
-#include "gdkinternals.h"
-
-
-G_DEFINE_TYPE (GdkSurfaceImpl, gdk_surface_impl, G_TYPE_OBJECT);
-
-static gboolean
-gdk_surface_impl_beep (GdkSurface *window)
-{
- /* FALSE means windows can't beep, so the display will be
- * made to beep instead. */
- return FALSE;
-}
-
-static GdkDisplay *
-get_display_for_window (GdkSurface *primary,
- GdkSurface *secondary)
-{
- GdkDisplay *display = gdk_surface_get_display (primary);
-
- if (display)
- return display;
-
- display = gdk_surface_get_display (secondary);
-
- if (display)
- return display;
-
- g_warning ("no display for window, using default");
- return gdk_display_get_default ();
-}
-
-static GdkMonitor *
-get_monitor_for_rect (GdkDisplay *display,
- const GdkRectangle *rect)
-{
- gint biggest_area = G_MININT;
- GdkMonitor *best_monitor = NULL;
- GdkMonitor *monitor;
- GdkRectangle workarea;
- GdkRectangle intersection;
- gint x;
- gint y;
- gint i;
-
- for (i = 0; i < gdk_display_get_n_monitors (display); i++)
- {
- monitor = gdk_display_get_monitor (display, i);
- gdk_monitor_get_workarea (monitor, &workarea);
-
- if (gdk_rectangle_intersect (&workarea, rect, &intersection))
- {
- if (intersection.width * intersection.height > biggest_area)
- {
- biggest_area = intersection.width * intersection.height;
- best_monitor = monitor;
- }
- }
- }
-
- if (best_monitor)
- return best_monitor;
-
- x = rect->x + rect->width / 2;
- y = rect->y + rect->height / 2;
-
- return gdk_display_get_monitor_at_point (display, x, y);
-}
-
-static gint
-get_anchor_x_sign (GdkGravity anchor)
-{
- switch (anchor)
- {
- case GDK_GRAVITY_STATIC:
- case GDK_GRAVITY_NORTH_WEST:
- case GDK_GRAVITY_WEST:
- case GDK_GRAVITY_SOUTH_WEST:
- return -1;
-
- default:
- case GDK_GRAVITY_NORTH:
- case GDK_GRAVITY_CENTER:
- case GDK_GRAVITY_SOUTH:
- return 0;
-
- case GDK_GRAVITY_NORTH_EAST:
- case GDK_GRAVITY_EAST:
- case GDK_GRAVITY_SOUTH_EAST:
- return 1;
- }
-}
-
-static gint
-get_anchor_y_sign (GdkGravity anchor)
-{
- switch (anchor)
- {
- case GDK_GRAVITY_STATIC:
- case GDK_GRAVITY_NORTH_WEST:
- case GDK_GRAVITY_NORTH:
- case GDK_GRAVITY_NORTH_EAST:
- return -1;
-
- default:
- case GDK_GRAVITY_WEST:
- case GDK_GRAVITY_CENTER:
- case GDK_GRAVITY_EAST:
- return 0;
-
- case GDK_GRAVITY_SOUTH_WEST:
- case GDK_GRAVITY_SOUTH:
- case GDK_GRAVITY_SOUTH_EAST:
- return 1;
- }
-}
-
-static gint
-maybe_flip_position (gint bounds_pos,
- gint bounds_size,
- gint rect_pos,
- gint rect_size,
- gint window_size,
- gint rect_sign,
- gint window_sign,
- gint offset,
- gboolean flip,
- gboolean *flipped)
-{
- gint primary;
- gint secondary;
-
- *flipped = FALSE;
- primary = rect_pos + (1 + rect_sign) * rect_size / 2 + offset - (1 + window_sign) * window_size / 2;
-
- if (!flip || (primary >= bounds_pos && primary + window_size <= bounds_pos + bounds_size))
- return primary;
-
- *flipped = TRUE;
- secondary = rect_pos + (1 - rect_sign) * rect_size / 2 - offset - (1 - window_sign) * window_size / 2;
-
- if (secondary >= bounds_pos && secondary + window_size <= bounds_pos + bounds_size)
- return secondary;
-
- *flipped = FALSE;
- return primary;
-}
-
-static GdkSurface *
-traverse_to_toplevel (GdkSurface *window,
- gint x,
- gint y,
- gint *toplevel_x,
- gint *toplevel_y)
-{
- GdkSurface *parent;
- gdouble xf = x;
- gdouble yf = y;
-
- while ((parent = window->parent) != NULL &&
- (gdk_surface_get_window_type (parent) != GDK_SURFACE_ROOT))
- {
- gdk_surface_coords_to_parent (window, xf, yf, &xf, &yf);
- window = parent;
- }
-
- *toplevel_x = (gint) xf;
- *toplevel_y = (gint) yf;
- return window;
-}
-
-static void
-gdk_surface_impl_move_to_rect (GdkSurface *window,
- const GdkRectangle *rect,
- GdkGravity rect_anchor,
- GdkGravity window_anchor,
- GdkAnchorHints anchor_hints,
- gint rect_anchor_dx,
- gint rect_anchor_dy)
-{
- GdkSurface *transient_for_toplevel;
- GdkDisplay *display;
- GdkMonitor *monitor;
- GdkRectangle bounds;
- GdkRectangle root_rect = *rect;
- GdkRectangle flipped_rect;
- GdkRectangle final_rect;
- gboolean flipped_x;
- gboolean flipped_y;
-
- /*
- * First translate the anchor rect to toplevel coordinates. This is needed
- * because not all backends will be able to get root coordinates for
- * non-toplevel windows.
- */
- transient_for_toplevel = traverse_to_toplevel (window->transient_for,
- root_rect.x,
- root_rect.y,
- &root_rect.x,
- &root_rect.y);
-
- gdk_surface_get_root_coords (transient_for_toplevel,
- root_rect.x,
- root_rect.y,
- &root_rect.x,
- &root_rect.y);
-
- display = get_display_for_window (window, window->transient_for);
- monitor = get_monitor_for_rect (display, &root_rect);
- gdk_monitor_get_workarea (monitor, &bounds);
-
- flipped_rect.width = window->width - window->shadow_left - window->shadow_right;
- flipped_rect.height = window->height - window->shadow_top - window->shadow_bottom;
- flipped_rect.x = maybe_flip_position (bounds.x,
- bounds.width,
- root_rect.x,
- root_rect.width,
- flipped_rect.width,
- get_anchor_x_sign (rect_anchor),
- get_anchor_x_sign (window_anchor),
- rect_anchor_dx,
- anchor_hints & GDK_ANCHOR_FLIP_X,
- &flipped_x);
- flipped_rect.y = maybe_flip_position (bounds.y,
- bounds.height,
- root_rect.y,
- root_rect.height,
- flipped_rect.height,
- get_anchor_y_sign (rect_anchor),
- get_anchor_y_sign (window_anchor),
- rect_anchor_dy,
- anchor_hints & GDK_ANCHOR_FLIP_Y,
- &flipped_y);
-
- final_rect = flipped_rect;
-
- if (anchor_hints & GDK_ANCHOR_SLIDE_X)
- {
- if (final_rect.x + final_rect.width > bounds.x + bounds.width)
- final_rect.x = bounds.x + bounds.width - final_rect.width;
-
- if (final_rect.x < bounds.x)
- final_rect.x = bounds.x;
- }
-
- if (anchor_hints & GDK_ANCHOR_SLIDE_Y)
- {
- if (final_rect.y + final_rect.height > bounds.y + bounds.height)
- final_rect.y = bounds.y + bounds.height - final_rect.height;
-
- if (final_rect.y < bounds.y)
- final_rect.y = bounds.y;
- }
-
- if (anchor_hints & GDK_ANCHOR_RESIZE_X)
- {
- if (final_rect.x < bounds.x)
- {
- final_rect.width -= bounds.x - final_rect.x;
- final_rect.x = bounds.x;
- }
-
- if (final_rect.x + final_rect.width > bounds.x + bounds.width)
- final_rect.width = bounds.x + bounds.width - final_rect.x;
- }
-
- if (anchor_hints & GDK_ANCHOR_RESIZE_Y)
- {
- if (final_rect.y < bounds.y)
- {
- final_rect.height -= bounds.y - final_rect.y;
- final_rect.y = bounds.y;
- }
-
- if (final_rect.y + final_rect.height > bounds.y + bounds.height)
- final_rect.height = bounds.y + bounds.height - final_rect.y;
- }
-
- flipped_rect.x -= window->shadow_left;
- flipped_rect.y -= window->shadow_top;
- flipped_rect.width += window->shadow_left + window->shadow_right;
- flipped_rect.height += window->shadow_top + window->shadow_bottom;
-
- final_rect.x -= window->shadow_left;
- final_rect.y -= window->shadow_top;
- final_rect.width += window->shadow_left + window->shadow_right;
- final_rect.height += window->shadow_top + window->shadow_bottom;
-
- if (final_rect.width != window->width || final_rect.height != window->height)
- gdk_surface_move_resize (window, final_rect.x, final_rect.y, final_rect.width, final_rect.height);
- else
- gdk_surface_move (window, final_rect.x, final_rect.y);
-
- g_signal_emit_by_name (window,
- "moved-to-rect",
- &flipped_rect,
- &final_rect,
- flipped_x,
- flipped_y);
-}
-
-static void
-gdk_surface_impl_process_updates_recurse (GdkSurface *window,
- cairo_region_t *region)
-{
- _gdk_surface_process_updates_recurse (window, region);
-}
-
-static void
-gdk_surface_impl_class_init (GdkSurfaceImplClass *impl_class)
-{
- impl_class->beep = gdk_surface_impl_beep;
- impl_class->move_to_rect = gdk_surface_impl_move_to_rect;
- impl_class->process_updates_recurse = gdk_surface_impl_process_updates_recurse;
-}
-
-static void
-gdk_surface_impl_init (GdkSurfaceImpl *impl)
-{
-}
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#ifndef __GDK_SURFACE_IMPL_H__
-#define __GDK_SURFACE_IMPL_H__
-
-#include <gdk/gdkwindow.h>
-#include <gdk/gdkproperty.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_SURFACE_IMPL (gdk_surface_impl_get_type ())
-#define GDK_SURFACE_IMPL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL, GdkSurfaceImpl))
-#define GDK_SURFACE_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL, GdkSurfaceImplClass))
-#define GDK_IS_SURFACE_IMPL(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL))
-#define GDK_IS_SURFACE_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL))
-#define GDK_SURFACE_IMPL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL, GdkSurfaceImplClass))
-
-typedef struct _GdkSurfaceImpl GdkSurfaceImpl;
-typedef struct _GdkSurfaceImplClass GdkSurfaceImplClass;
-
-struct _GdkSurfaceImpl
-{
- GObject parent;
-};
-
-struct _GdkSurfaceImplClass
-{
- GObjectClass parent_class;
-
- cairo_surface_t *
- (* ref_cairo_surface) (GdkSurface *window);
- cairo_surface_t *
- (* create_similar_image_surface) (GdkSurface * window,
- cairo_format_t format,
- int width,
- int height);
-
- void (* show) (GdkSurface *window,
- gboolean already_mapped);
- void (* hide) (GdkSurface *window);
- void (* withdraw) (GdkSurface *window);
- void (* raise) (GdkSurface *window);
- void (* lower) (GdkSurface *window);
- void (* restack_toplevel) (GdkSurface *window,
- GdkSurface *sibling,
- gboolean above);
-
- void (* move_resize) (GdkSurface *window,
- gboolean with_move,
- gint x,
- gint y,
- gint width,
- gint height);
- void (* move_to_rect) (GdkSurface *window,
- const GdkRectangle *rect,
- GdkGravity rect_anchor,
- GdkGravity window_anchor,
- GdkAnchorHints anchor_hints,
- gint rect_anchor_dx,
- gint rect_anchor_dy);
-
- GdkEventMask (* get_events) (GdkSurface *window);
- void (* set_events) (GdkSurface *window,
- GdkEventMask event_mask);
-
- void (* get_geometry) (GdkSurface *window,
- gint *x,
- gint *y,
- gint *width,
- gint *height);
- void (* get_root_coords) (GdkSurface *window,
- gint x,
- gint y,
- gint *root_x,
- gint *root_y);
- gboolean (* get_device_state) (GdkSurface *window,
- GdkDevice *device,
- gdouble *x,
- gdouble *y,
- GdkModifierType *mask);
- gboolean (* begin_paint) (GdkSurface *window);
- void (* end_paint) (GdkSurface *window);
-
- void (* shape_combine_region) (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y);
- void (* input_shape_combine_region) (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y);
-
- /* Called before processing updates for a window. This gives the windowing
- * layer a chance to save the region for later use in avoiding duplicate
- * exposes.
- */
- void (* queue_antiexpose) (GdkSurface *window,
- cairo_region_t *update_area);
-
-/* Called to do the windowing system specific part of gdk_surface_destroy(),
- *
- * window: The window being destroyed
- * recursing: If TRUE, then this is being called because a parent
- * was destroyed. This generally means that the call to the windowing
- * system to destroy the window can be omitted, since it will be
- * destroyed as a result of the parent being destroyed.
- * Unless @foreign_destroy
- * foreign_destroy: If TRUE, the window or a parent was destroyed by some
- * external agency. The window has already been destroyed and no
- * windowing system calls should be made. (This may never happen
- * for some windowing systems.)
- */
- void (* destroy) (GdkSurface *window,
- gboolean recursing,
- gboolean foreign_destroy);
-
-
- /* optional */
- gboolean (* beep) (GdkSurface *window);
-
- void (* focus) (GdkSurface *window,
- guint32 timestamp);
- void (* set_type_hint) (GdkSurface *window,
- GdkSurfaceTypeHint hint);
- GdkSurfaceTypeHint (* get_type_hint) (GdkSurface *window);
- void (* set_modal_hint) (GdkSurface *window,
- gboolean modal);
- void (* set_skip_taskbar_hint) (GdkSurface *window,
- gboolean skips_taskbar);
- void (* set_skip_pager_hint) (GdkSurface *window,
- gboolean skips_pager);
- void (* set_urgency_hint) (GdkSurface *window,
- gboolean urgent);
- void (* set_geometry_hints) (GdkSurface *window,
- const GdkGeometry *geometry,
- GdkSurfaceHints geom_mask);
- void (* set_title) (GdkSurface *window,
- const gchar *title);
- void (* set_role) (GdkSurface *window,
- const gchar *role);
- void (* set_startup_id) (GdkSurface *window,
- const gchar *startup_id);
- void (* set_transient_for) (GdkSurface *window,
- GdkSurface *parent);
- void (* get_frame_extents) (GdkSurface *window,
- GdkRectangle *rect);
- void (* set_accept_focus) (GdkSurface *window,
- gboolean accept_focus);
- void (* set_focus_on_map) (GdkSurface *window,
- gboolean focus_on_map);
- void (* set_icon_list) (GdkSurface *window,
- GList *pixbufs);
- void (* set_icon_name) (GdkSurface *window,
- const gchar *name);
- void (* iconify) (GdkSurface *window);
- void (* deiconify) (GdkSurface *window);
- void (* stick) (GdkSurface *window);
- void (* unstick) (GdkSurface *window);
- void (* maximize) (GdkSurface *window);
- void (* unmaximize) (GdkSurface *window);
- void (* fullscreen) (GdkSurface *window);
- void (* fullscreen_on_monitor) (GdkSurface *window,
- GdkMonitor *monitor);
- void (* apply_fullscreen_mode) (GdkSurface *window);
- void (* unfullscreen) (GdkSurface *window);
- void (* set_keep_above) (GdkSurface *window,
- gboolean setting);
- void (* set_keep_below) (GdkSurface *window,
- gboolean setting);
- GdkSurface * (* get_group) (GdkSurface *window);
- void (* set_group) (GdkSurface *window,
- GdkSurface *leader);
- void (* set_decorations) (GdkSurface *window,
- GdkWMDecoration decorations);
- gboolean (* get_decorations) (GdkSurface *window,
- GdkWMDecoration *decorations);
- void (* set_functions) (GdkSurface *window,
- GdkWMFunction functions);
- void (* begin_resize_drag) (GdkSurface *window,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp);
- void (* begin_move_drag) (GdkSurface *window,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp);
- void (* enable_synchronized_configure) (GdkSurface *window);
- void (* configure_finished) (GdkSurface *window);
- void (* set_opacity) (GdkSurface *window,
- gdouble opacity);
- void (* destroy_notify) (GdkSurface *window);
- void (* register_dnd) (GdkSurface *window);
- GdkDragContext * (*drag_begin) (GdkSurface *window,
- GdkDevice *device,
- GdkContentProvider*content,
- GdkDragAction actions,
- gint dx,
- gint dy);
-
- void (*process_updates_recurse) (GdkSurface *window,
- cairo_region_t *region);
-
- gint (* get_scale_factor) (GdkSurface *window);
- void (* get_unscaled_size) (GdkSurface *window,
- int *unscaled_width,
- int *unscaled_height);
-
- void (* set_opaque_region) (GdkSurface *window,
- cairo_region_t *region);
- void (* set_shadow_width) (GdkSurface *window,
- gint left,
- gint right,
- gint top,
- gint bottom);
- gboolean (* show_window_menu) (GdkSurface *window,
- GdkEvent *event);
- GdkGLContext *(*create_gl_context) (GdkSurface *window,
- gboolean attached,
- GdkGLContext *share,
- GError **error);
- gboolean (* supports_edge_constraints)(GdkSurface *window);
-};
-
-/* Interface Functions */
-GType gdk_surface_impl_get_type (void) G_GNUC_CONST;
-
-G_END_DECLS
-
-#endif /* __GDK_SURFACE_IMPL_H__ */
'gdksnapshot.c',
'gdktexture.c',
'gdkvulkancontext.c',
- 'gdkwindow.c',
- 'gdkwindowimpl.c',
+ 'gdksurface.c',
+ 'gdksurfaceimpl.c',
])
gdk_public_headers = files([
'gdktexture.h',
'gdktypes.h',
'gdkvulkancontext.h',
- 'gdkwindow.h',
+ 'gdksurface.h',
])
install_headers(gdk_public_headers, subdir: 'gtk-4.0/gdk/')
#include "config.h"
#import "GdkQuartzNSWindow.h"
-#include "gdkquartzwindow.h"
+#include "gdkquartzsurface.h"
#include "gdkdnd-quartz.h"
#include "gdkprivate-quartz.h"
#include "config.h"
#import "GdkQuartzView.h"
-#include "gdkquartzwindow.h"
+#include "gdkquartzsurface.h"
#include "gdkprivate-quartz.h"
#include "gdkquartz.h"
#include <gdk/gdkdisplayprivate.h>
#import "GdkQuartzView.h"
-#include "gdkquartzwindow.h"
+#include "gdkquartzsurface.h"
#include "gdkquartzcursor.h"
#include "gdkprivate-quartz.h"
#include "gdkquartzdevice-core.h"
#include "gdkprivate-quartz.h"
#include "gdkquartzscreen.h"
-#include "gdkquartzwindow.h"
+#include "gdkquartzsurface.h"
#include "gdkquartzdisplay.h"
#include "gdkquartzdevicemanager-core.h"
#include "gdkmonitorprivate.h"
#include "gdkdisplayprivate.h"
#include "gdkkeys.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkinternals.h"
G_BEGIN_DECLS
* under the pointer and we thus return NULL. This can occur when
* toplevel under pointer has not yet been updated due to a very recent
* window resize. Alternatively, we should no longer be relying on
- * the toplevel_under_pointer value which is maintained in gdkwindow.c.
+ * the toplevel_under_pointer value which is maintained in gdksurface.c.
*/
if (*x < 0 || *y < 0 || *x >= toplevel->width || *y >= toplevel->height)
return NULL;
#define __GDK_QUARTZ_GL_CONTEXT__
#include "gdkglcontextprivate.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkinternals.h"
G_BEGIN_DECLS
-/* gdkwindow-quartz.c
+/* gdksurface-quartz.c
*
* Copyright (C) 2005-2007 Imendio AB
*
#include <gdk/quartz/gdkdevicemanager-core-quartz.h>
#include <gdk/quartz/gdkdnd-quartz.h>
#include <gdk/quartz/gdkscreen-quartz.h>
-#include <gdk/quartz/gdkwindow-quartz.h>
+#include <gdk/quartz/gdksurface-quartz.h>
#include <gdk/gdk.h>
#include <gdk/quartz/gdkquartzmonitor.h>
#include <gdk/quartz/gdkquartzscreen.h>
#include <gdk/quartz/gdkquartzutils.h>
-#include <gdk/quartz/gdkquartzwindow.h>
+#include <gdk/quartz/gdkquartzsurface.h>
#undef __GDKQUARTZ_H_INSIDE__
--- /dev/null
+/* gdkquartzsurface.h
+ *
+ * Copyright (C) 2005 Imendio AB
+ * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_QUARTZ_SURFACE_H__
+#define __GDK_QUARTZ_SURFACE_H__
+
+#if !defined (__GDKQUARTZ_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdkquartz.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_QUARTZ_SURFACE (gdk_quartz_surface_get_type ())
+#define GDK_QUARTZ_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_SURFACE, GdkQuartzSurface))
+#define GDK_QUARTZ_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_SURFACE, GdkQuartzSurfaceClass))
+#define GDK_IS_QUARTZ_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_SURFACE))
+#define GDK_IS_QUARTZ_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_SURFACE))
+#define GDK_QUARTZ_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_SURFACE, GdkQuartzSurfaceClass))
+
+#ifdef GDK_COMPILATION
+typedef struct _GdkQuartzSurface GdkQuartzSurface;
+#else
+typedef GdkSurface GdkQuartzSurface;
+#endif
+typedef struct _GdkQuartzSurfaceClass GdkQuartzSurfaceClass;
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_quartz_surface_get_type (void);
+
+GDK_AVAILABLE_IN_ALL
+NSWindow *gdk_quartz_surface_get_nswindow (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+NSView *gdk_quartz_surface_get_nsview (GdkSurface *window);
+
+G_END_DECLS
+
+#endif /* __GDK_QUARTZ_SURFACE_H__ */
+++ /dev/null
-/* gdkquartzwindow.h
- *
- * Copyright (C) 2005 Imendio AB
- * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_SURFACE_H__
-#define __GDK_QUARTZ_SURFACE_H__
-
-#if !defined (__GDKQUARTZ_H_INSIDE__) && !defined (GDK_COMPILATION)
-#error "Only <gdk/gdkquartz.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_QUARTZ_SURFACE (gdk_quartz_surface_get_type ())
-#define GDK_QUARTZ_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_SURFACE, GdkQuartzSurface))
-#define GDK_QUARTZ_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_SURFACE, GdkQuartzSurfaceClass))
-#define GDK_IS_QUARTZ_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_SURFACE))
-#define GDK_IS_QUARTZ_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_SURFACE))
-#define GDK_QUARTZ_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_SURFACE, GdkQuartzSurfaceClass))
-
-#ifdef GDK_COMPILATION
-typedef struct _GdkQuartzSurface GdkQuartzSurface;
-#else
-typedef GdkSurface GdkQuartzSurface;
-#endif
-typedef struct _GdkQuartzSurfaceClass GdkQuartzSurfaceClass;
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_surface_get_type (void);
-
-GDK_AVAILABLE_IN_ALL
-NSWindow *gdk_quartz_surface_get_nswindow (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-NSView *gdk_quartz_surface_get_nsview (GdkSurface *window);
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_SURFACE_H__ */
* coordinate space. Such coordinates are mapped to their respective
* position in the GdkScreen root window (_gdk_quartz_surface_xy_to_gdk_xy)
* and vice versa (_gdk_quartz_surface_gdk_xy_to_xy). Both functions can
- * be found in gdkwindow-quartz.c. Note that Cocoa coordinates can have
+ * be found in gdksurface-quartz.c. Note that Cocoa coordinates can have
* negative values (in case a monitor is located left or below of screen 0),
* but GDK coordinates can *not*!
*/
--- /dev/null
+/* gdksurface-quartz.c
+ *
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 2005-2007 Imendio AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gdk/gdk.h>
+#include <gdk/gdkdeviceprivate.h>
+#include <gdk/gdkdisplayprivate.h>
+
+#include "gdksurfaceimpl.h"
+#include "gdkprivate-quartz.h"
+#include "gdkglcontext-quartz.h"
+#include "gdkquartzscreen.h"
+#include "gdkquartzcursor.h"
+
+#include <Carbon/Carbon.h>
+#include <AvailabilityMacros.h>
+
+#include <sys/time.h>
+#include <cairo-quartz.h>
+
+static gpointer parent_class;
+static gpointer root_window_parent_class;
+
+static GSList *update_nswindows;
+static gboolean in_process_all_updates = FALSE;
+
+static GSList *main_window_stack;
+
+void _gdk_quartz_surface_flush (GdkSurfaceImplQuartz *window_impl);
+
+typedef struct
+{
+ gint x, y;
+ gint width, height;
+ GdkWMDecoration decor;
+} FullscreenSavedGeometry;
+
+
+#ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+static FullscreenSavedGeometry *get_fullscreen_geometry (GdkSurface *window);
+#endif
+
+#define FULLSCREEN_DATA "fullscreen-data"
+
+static void update_toplevel_order (void);
+static void clear_toplevel_order (void);
+
+#define WINDOW_IS_TOPLEVEL(window) (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD)
+
+/*
+ * GdkQuartzSurface
+ */
+
+struct _GdkQuartzSurface
+{
+ GdkSurface parent;
+};
+
+struct _GdkQuartzSurfaceClass
+{
+ GdkSurfaceClass parent_class;
+};
+
+G_DEFINE_TYPE (GdkQuartzSurface, gdk_quartz_surface, GDK_TYPE_SURFACE);
+
+static void
+gdk_quartz_surface_class_init (GdkQuartzSurfaceClass *quartz_surface_class)
+{
+}
+
+static void
+gdk_quartz_surface_init (GdkQuartzSurface *quartz_surface)
+{
+}
+
+
+/*
+ * GdkQuartzSurfaceImpl
+ */
+
+NSView *
+gdk_quartz_surface_get_nsview (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window))
+ return NULL;
+
+ return ((GdkSurfaceImplQuartz *)window->impl)->view;
+}
+
+NSWindow *
+gdk_quartz_surface_get_nswindow (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window))
+ return NULL;
+
+ return ((GdkSurfaceImplQuartz *)window->impl)->toplevel;
+}
+
+static CGContextRef
+gdk_surface_impl_quartz_get_context (GdkSurfaceImplQuartz *window_impl,
+ gboolean antialias)
+{
+ CGContextRef cg_context;
+ CGSize scale;
+
+ if (GDK_SURFACE_DESTROYED (window_impl->wrapper))
+ return NULL;
+
+ /* Lock focus when not called as part of a drawRect call. This
+ * is needed when called from outside "real" expose events, for
+ * example for synthesized expose events when realizing windows
+ * and for widgets that send fake expose events like the arrow
+ * buttons in spinbuttons or the position marker in rulers.
+ */
+ if (window_impl->in_paint_rect_count == 0)
+ {
+ if (![window_impl->view lockFocusIfCanDraw])
+ return NULL;
+ }
+
+ cg_context = [[NSGraphicsContext currentContext] graphicsPort];
+ CGContextSaveGState (cg_context);
+ CGContextSetAllowsAntialiasing (cg_context, antialias);
+
+ /* Undo the default scaling transform, since we apply our own
+ * in gdk_quartz_ref_cairo_surface () */
+ scale = CGContextConvertSizeToDeviceSpace (cg_context,
+ CGSizeMake (1.0, 1.0));
+ CGContextScaleCTM (cg_context, 1.0 / scale.width, 1.0 / scale.height);
+
+ return cg_context;
+}
+
+static void
+gdk_surface_impl_quartz_release_context (GdkSurfaceImplQuartz *window_impl,
+ CGContextRef cg_context)
+{
+ CGContextRestoreGState (cg_context);
+ CGContextSetAllowsAntialiasing (cg_context, TRUE);
+
+ /* See comment in gdk_quartz_surface_get_context(). */
+ if (window_impl->in_paint_rect_count == 0)
+ {
+ _gdk_quartz_surface_flush (window_impl);
+ [window_impl->view unlockFocus];
+ }
+}
+
+static void
+check_grab_destroy (GdkSurface *window)
+{
+ GList *devices = NULL, *l;
+ GdkDisplay *display = gdk_surface_get_display (window);
+ GdkSeat *seat;
+
+ seat = gdk_display_get_default_seat (display);
+
+ devices = g_list_prepend (devices, gdk_seat_get_keyboard (seat));
+ devices = g_list_prepend (devices, gdk_seat_get_pointer (seat));
+
+ for (l = devices; l; l = l->next)
+ {
+ GdkDeviceGrabInfo *grab;
+
+ grab = _gdk_display_get_last_device_grab (display, l->data);
+ if (grab && grab->native_window == window)
+ {
+ /* Serials are always 0 in quartz, but for clarity: */
+ grab->serial_end = grab->serial_start;
+ grab->implicit_ungrab = TRUE;
+ }
+ }
+
+ g_list_free (devices);
+}
+
+static void
+gdk_surface_impl_quartz_finalize (GObject *object)
+{
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (object);
+
+ check_grab_destroy (GDK_SURFACE_IMPL_QUARTZ (object)->wrapper);
+
+ if (impl->transient_for)
+ g_object_unref (impl->transient_for);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* Help preventing "beam sync penalty" where CG makes all graphics code
+ * block until the next vsync if we try to flush (including call display on
+ * a view) too often. We do this by limiting the manual flushing done
+ * outside of expose calls to less than some frequency when measured over
+ * the last 4 flushes. This is a bit arbitray, but seems to make it possible
+ * for some quick manual flushes (such as gtkruler or gimp’s marching ants)
+ * without hitting the max flush frequency.
+ *
+ * If drawable NULL, no flushing is done, only registering that a flush was
+ * done externally.
+ */
+void
+_gdk_quartz_surface_flush (GdkSurfaceImplQuartz *window_impl)
+{
+ static struct timeval prev_tv;
+ static gint intervals[4];
+ static gint index;
+ struct timeval tv;
+ gint ms;
+
+ gettimeofday (&tv, NULL);
+ ms = (tv.tv_sec - prev_tv.tv_sec) * 1000 + (tv.tv_usec - prev_tv.tv_usec) / 1000;
+ intervals[index++ % 4] = ms;
+
+ if (window_impl)
+ {
+ ms = intervals[0] + intervals[1] + intervals[2] + intervals[3];
+
+ /* ~25Hz on average. */
+ if (ms > 4*40)
+ {
+ if (window_impl)
+ [window_impl->toplevel flushWindow];
+
+ prev_tv = tv;
+ }
+ }
+ else
+ prev_tv = tv;
+}
+
+static cairo_user_data_key_t gdk_quartz_cairo_key;
+
+typedef struct {
+ GdkSurfaceImplQuartz *window_impl;
+ CGContextRef cg_context;
+} GdkQuartzCairoSurfaceData;
+
+static void
+gdk_quartz_cairo_surface_destroy (void *data)
+{
+ GdkQuartzCairoSurfaceData *surface_data = data;
+
+ surface_data->window_impl->cairo_surface = NULL;
+
+ gdk_quartz_surface_release_context (surface_data->window_impl,
+ surface_data->cg_context);
+
+ g_free (surface_data);
+}
+
+static cairo_surface_t *
+gdk_quartz_create_cairo_surface (GdkSurfaceImplQuartz *impl,
+ int width,
+ int height)
+{
+ CGContextRef cg_context;
+ GdkQuartzCairoSurfaceData *surface_data;
+ cairo_surface_t *surface;
+
+ cg_context = gdk_quartz_surface_get_context (impl, TRUE);
+
+ if (!cg_context)
+ return NULL;
+
+ surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
+ surface_data->window_impl = impl;
+ surface_data->cg_context = cg_context;
+
+ surface = cairo_quartz_surface_create_for_cg_context (cg_context,
+ width, height);
+
+ cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key,
+ surface_data,
+ gdk_quartz_cairo_surface_destroy);
+
+ return surface;
+}
+
+static cairo_surface_t *
+gdk_quartz_ref_cairo_surface (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return NULL;
+
+ if (!impl->cairo_surface)
+ {
+ gint scale = gdk_surface_get_scale_factor (impl->wrapper);
+
+ impl->cairo_surface =
+ gdk_quartz_create_cairo_surface (impl,
+ gdk_surface_get_width (impl->wrapper) * scale,
+ gdk_surface_get_height (impl->wrapper) * scale);
+
+ cairo_surface_set_device_scale (impl->cairo_surface, scale, scale);
+ }
+ else
+ cairo_surface_reference (impl->cairo_surface);
+
+ return impl->cairo_surface;
+}
+
+static void
+gdk_surface_impl_quartz_init (GdkSurfaceImplQuartz *impl)
+{
+ impl->type_hint = GDK_SURFACE_TYPE_HINT_NORMAL;
+}
+
+static gboolean
+gdk_surface_impl_quartz_begin_paint (GdkSurface *window)
+{
+ return FALSE;
+}
+
+static void
+gdk_quartz_surface_set_needs_display_in_region (GdkSurface *window,
+ cairo_region_t *region)
+{
+ GdkSurfaceImplQuartz *impl;
+ int i, n_rects;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (!impl->needs_display_region)
+ impl->needs_display_region = cairo_region_create ();
+
+ cairo_region_union (impl->needs_display_region, region);
+
+ n_rects = cairo_region_num_rectangles (region);
+ for (i = 0; i < n_rects; i++)
+ {
+ cairo_rectangle_int_t rect;
+ cairo_region_get_rectangle (region, i, &rect);
+ [impl->view setNeedsDisplayInRect:NSMakeRect (rect.x, rect.y,
+ rect.width, rect.height)];
+ }
+}
+
+void
+_gdk_quartz_surface_process_updates_recurse (GdkSurface *window,
+ cairo_region_t *region)
+{
+ /* Make sure to only flush each toplevel at most once if we're called
+ * from process_all_updates.
+ */
+ if (in_process_all_updates)
+ {
+ GdkSurface *toplevel;
+
+ toplevel = gdk_surface_get_toplevel (window);
+ if (toplevel && WINDOW_IS_TOPLEVEL (toplevel))
+ {
+ GdkSurfaceImplQuartz *toplevel_impl;
+ NSWindow *nswindow;
+
+ toplevel_impl = (GdkSurfaceImplQuartz *)toplevel->impl;
+ nswindow = toplevel_impl->toplevel;
+
+ /* In theory, we could skip the flush disabling, since we only
+ * have one NSView.
+ */
+ if (nswindow && ![nswindow isFlushWindowDisabled])
+ {
+ [nswindow retain];
+ [nswindow disableFlushWindow];
+ update_nswindows = g_slist_prepend (update_nswindows, nswindow);
+ }
+ }
+ }
+
+ if (WINDOW_IS_TOPLEVEL (window))
+ gdk_quartz_surface_set_needs_display_in_region (window, region);
+ else
+ _gdk_surface_process_updates_recurse (window, region);
+
+ /* NOTE: I'm not sure if we should displayIfNeeded here. It slows down a
+ * lot (since it triggers the beam syncing) and things seem to work
+ * without it.
+ */
+}
+
+static const gchar *
+get_default_title (void)
+{
+ const char *title;
+
+ title = g_get_application_name ();
+ if (!title)
+ title = g_get_prgname ();
+
+ return title;
+}
+
+static void
+get_ancestor_coordinates_from_child (GdkSurface *child_window,
+ gint child_x,
+ gint child_y,
+ GdkSurface *ancestor_window,
+ gint *ancestor_x,
+ gint *ancestor_y)
+{
+ while (child_window != ancestor_window)
+ {
+ child_x += child_window->x;
+ child_y += child_window->y;
+
+ child_window = child_window->parent;
+ }
+
+ *ancestor_x = child_x;
+ *ancestor_y = child_y;
+}
+
+void
+_gdk_quartz_surface_debug_highlight (GdkSurface *window, gint number)
+{
+ gint x, y;
+ gint gx, gy;
+ GdkSurface *toplevel;
+ gint tx, ty;
+ static NSWindow *debug_window[10];
+ static NSRect old_rect[10];
+ NSRect rect;
+ NSColor *color;
+
+ g_return_if_fail (number >= 0 && number <= 9);
+
+ if (window == _gdk_root)
+ return;
+
+ if (window == NULL)
+ {
+ if (debug_window[number])
+ [debug_window[number] close];
+ debug_window[number] = NULL;
+
+ return;
+ }
+
+ toplevel = gdk_surface_get_toplevel (window);
+ get_ancestor_coordinates_from_child (window, 0, 0, toplevel, &x, &y);
+
+ gdk_surface_get_origin (toplevel, &tx, &ty);
+ x += tx;
+ y += ty;
+
+ _gdk_quartz_surface_gdk_xy_to_xy (x, y + window->height,
+ &gx, &gy);
+
+ rect = NSMakeRect (gx, gy, window->width, window->height);
+
+ if (debug_window[number] && NSEqualRects (rect, old_rect[number]))
+ return;
+
+ old_rect[number] = rect;
+
+ if (debug_window[number])
+ [debug_window[number] close];
+
+ debug_window[number] = [[NSWindow alloc] initWithContentRect:rect
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+
+ switch (number)
+ {
+ case 0:
+ color = [NSColor redColor];
+ break;
+ case 1:
+ color = [NSColor blueColor];
+ break;
+ case 2:
+ color = [NSColor greenColor];
+ break;
+ case 3:
+ color = [NSColor yellowColor];
+ break;
+ case 4:
+ color = [NSColor brownColor];
+ break;
+ case 5:
+ color = [NSColor purpleColor];
+ break;
+ default:
+ color = [NSColor blackColor];
+ break;
+ }
+
+ [debug_window[number] setBackgroundColor:color];
+ [debug_window[number] setAlphaValue:0.4];
+ [debug_window[number] setOpaque:NO];
+ [debug_window[number] setReleasedWhenClosed:YES];
+ [debug_window[number] setIgnoresMouseEvents:YES];
+ [debug_window[number] setLevel:NSFloatingWindowLevel];
+
+ [debug_window[number] orderFront:nil];
+}
+
+gboolean
+_gdk_quartz_surface_is_ancestor (GdkSurface *ancestor,
+ GdkSurface *window)
+{
+ if (ancestor == NULL || window == NULL)
+ return FALSE;
+
+ return (gdk_surface_get_parent (window) == ancestor ||
+ _gdk_quartz_surface_is_ancestor (ancestor,
+ gdk_surface_get_parent (window)));
+}
+
+
+/* See notes on top of gdkscreen-quartz.c */
+void
+_gdk_quartz_surface_gdk_xy_to_xy (gint gdk_x,
+ gint gdk_y,
+ gint *ns_x,
+ gint *ns_y)
+{
+ GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
+
+ if (ns_y)
+ *ns_y = screen_quartz->height - gdk_y + screen_quartz->min_y;
+
+ if (ns_x)
+ *ns_x = gdk_x + screen_quartz->min_x;
+}
+
+void
+_gdk_quartz_surface_xy_to_gdk_xy (gint ns_x,
+ gint ns_y,
+ gint *gdk_x,
+ gint *gdk_y)
+{
+ GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
+
+ if (gdk_y)
+ *gdk_y = screen_quartz->height - ns_y + screen_quartz->min_y;
+
+ if (gdk_x)
+ *gdk_x = ns_x - screen_quartz->min_x;
+}
+
+void
+_gdk_quartz_surface_nspoint_to_gdk_xy (NSPoint point,
+ gint *x,
+ gint *y)
+{
+ _gdk_quartz_surface_xy_to_gdk_xy (point.x, point.y,
+ x, y);
+}
+
+static GdkSurface *
+find_child_window_helper (GdkSurface *window,
+ gint x,
+ gint y,
+ gint x_offset,
+ gint y_offset,
+ gboolean get_toplevel)
+{
+ GdkSurfaceImplQuartz *impl;
+ GList *l;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (window == _gdk_root)
+ update_toplevel_order ();
+
+ for (l = impl->sorted_children; l; l = l->next)
+ {
+ GdkSurface *child = l->data;
+ GdkSurfaceImplQuartz *child_impl = GDK_SURFACE_IMPL_QUARTZ (child->impl);
+ int temp_x, temp_y;
+
+ if (!GDK_SURFACE_IS_MAPPED (child))
+ continue;
+
+ temp_x = x_offset + child->x;
+ temp_y = y_offset + child->y;
+
+ /* Special-case the root window. We have to include the title
+ * bar in the checks, otherwise the window below the title bar
+ * will be found i.e. events punch through. (If we can find a
+ * better way to deal with the events in gdkevents-quartz, this
+ * might not be needed.)
+ */
+ if (window == _gdk_root)
+ {
+ NSRect frame = NSMakeRect (0, 0, 100, 100);
+ NSRect content;
+ NSUInteger mask;
+ int titlebar_height;
+
+ mask = [child_impl->toplevel styleMask];
+
+ /* Get the title bar height. */
+ content = [NSWindow contentRectForFrameRect:frame
+ styleMask:mask];
+ titlebar_height = frame.size.height - content.size.height;
+
+ if (titlebar_height > 0 &&
+ x >= temp_x && y >= temp_y - titlebar_height &&
+ x < temp_x + child->width && y < temp_y)
+ {
+ /* The root means "unknown" i.e. a window not managed by
+ * GDK.
+ */
+ return (GdkSurface *)_gdk_root;
+ }
+ }
+
+ if ((!get_toplevel || (get_toplevel && window == _gdk_root)) &&
+ x >= temp_x && y >= temp_y &&
+ x < temp_x + child->width && y < temp_y + child->height)
+ {
+ /* Look for child windows. */
+ return find_child_window_helper (l->data,
+ x, y,
+ temp_x, temp_y,
+ get_toplevel);
+ }
+ }
+
+ return window;
+}
+
+/* Given a GdkSurface and coordinates relative to it, returns the
+ * innermost subwindow that contains the point. If the coordinates are
+ * outside the passed in window, NULL is returned.
+ */
+GdkSurface *
+_gdk_quartz_surface_find_child (GdkSurface *window,
+ gint x,
+ gint y,
+ gboolean get_toplevel)
+{
+ if (x >= 0 && y >= 0 && x < window->width && y < window->height)
+ return find_child_window_helper (window, x, y, 0, 0, get_toplevel);
+
+ return NULL;
+}
+
+
+void
+_gdk_quartz_surface_did_become_main (GdkSurface *window)
+{
+ main_window_stack = g_slist_remove (main_window_stack, window);
+
+ if (window->window_type != GDK_SURFACE_TEMP)
+ main_window_stack = g_slist_prepend (main_window_stack, window);
+
+ clear_toplevel_order ();
+}
+
+void
+_gdk_quartz_surface_did_resign_main (GdkSurface *window)
+{
+ GdkSurface *new_window = NULL;
+
+ if (main_window_stack)
+ new_window = main_window_stack->data;
+ else
+ {
+ GList *toplevels;
+
+ toplevels = get_toplevels ();
+ if (toplevels)
+ new_window = toplevels->data;
+ }
+
+ if (new_window &&
+ new_window != window &&
+ GDK_SURFACE_IS_MAPPED (new_window) &&
+ WINDOW_IS_TOPLEVEL (new_window))
+ {
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (new_window->impl);
+
+ [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
+ }
+
+ clear_toplevel_order ();
+}
+
+static NSScreen *
+get_nsscreen_for_point (gint x, gint y)
+{
+ int i;
+ NSArray *screens;
+ NSScreen *screen = NULL;
+
+ GDK_QUARTZ_ALLOC_POOL;
+
+ screens = [NSScreen screens];
+
+ for (i = 0; i < [screens count]; i++)
+ {
+ NSRect rect = [[screens objectAtIndex:i] frame];
+
+ if (x >= rect.origin.x && x <= rect.origin.x + rect.size.width &&
+ y >= rect.origin.y && y <= rect.origin.y + rect.size.height)
+ {
+ screen = [screens objectAtIndex:i];
+ break;
+ }
+ }
+
+ GDK_QUARTZ_RELEASE_POOL;
+
+ return screen;
+}
+
+void
+_gdk_quartz_display_create_window_impl (GdkDisplay *display,
+ GdkSurface *window,
+ GdkSurface *real_parent,
+ GdkEventMask event_mask,
+ GdkSurfaceAttr *attributes)
+{
+ GdkSurfaceImplQuartz *impl;
+ GdkSurfaceImplQuartz *parent_impl;
+
+ GDK_QUARTZ_ALLOC_POOL;
+
+ impl = g_object_new (GDK_TYPE_SURFACE_IMPL_QUARTZ, NULL);
+ window->impl = GDK_SURFACE_IMPL (impl);
+ impl->wrapper = window;
+
+ parent_impl = GDK_SURFACE_IMPL_QUARTZ (window->parent->impl);
+
+ switch (window->window_type)
+ {
+ case GDK_SURFACE_TOPLEVEL:
+ case GDK_SURFACE_TEMP:
+ if (GDK_SURFACE_TYPE (window->parent) != GDK_SURFACE_ROOT)
+ {
+ /* The common code warns for this case */
+ parent_impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
+ }
+ }
+
+ /* Maintain the z-ordered list of children. */
+ if (window->parent != _gdk_root)
+ parent_impl->sorted_children = g_list_prepend (parent_impl->sorted_children, window);
+ else
+ clear_toplevel_order ();
+
+ impl->view = NULL;
+
+ switch (window->window_type)
+ {
+ case GDK_SURFACE_TOPLEVEL:
+ case GDK_SURFACE_TEMP:
+ {
+ NSScreen *screen;
+ NSRect screen_rect;
+ NSRect content_rect;
+ NSUInteger style_mask;
+ int nx, ny;
+
+ /* initWithContentRect will place on the mainScreen by default.
+ * We want to select the screen to place on ourselves. We need
+ * to find the screen the window will be on and correct the
+ * content_rect coordinates to be relative to that screen.
+ */
+ _gdk_quartz_surface_gdk_xy_to_xy (window->x, window->y, &nx, &ny);
+
+ screen = get_nsscreen_for_point (nx, ny);
+ screen_rect = [screen frame];
+ nx -= screen_rect.origin.x;
+ ny -= screen_rect.origin.y;
+
+ content_rect = NSMakeRect (nx, ny - window->height,
+ window->width,
+ window->height);
+
+ if (window->window_type == GDK_SURFACE_TEMP)
+ {
+ style_mask = NSBorderlessWindowMask;
+ }
+ else
+ {
+ style_mask = (NSTitledWindowMask |
+ NSClosableWindowMask |
+ NSMiniaturizableWindowMask |
+ NSResizableWindowMask);
+ }
+
+ impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:content_rect
+ styleMask:style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO
+ screen:screen];
+
+ gdk_surface_set_title (window, get_default_title ());
+
+ [impl->toplevel setOpaque:NO];
+ [impl->toplevel setBackgroundColor:[NSColor clearColor]];
+
+ content_rect.origin.x = 0;
+ content_rect.origin.y = 0;
+
+ impl->view = [[GdkQuartzView alloc] initWithFrame:content_rect];
+ [impl->view setGdkSurface:window];
+ [impl->toplevel setContentView:impl->view];
+ [impl->view release];
+ }
+ break;
+
+ case GDK_SURFACE_CHILD:
+ {
+ GdkSurfaceImplQuartz *parent_impl = GDK_SURFACE_IMPL_QUARTZ (window->parent->impl);
+
+ if (!window->input_only)
+ {
+ NSRect frame_rect = NSMakeRect (window->x + window->parent->abs_x,
+ window->y + window->parent->abs_y,
+ window->width,
+ window->height);
+
+ impl->view = [[GdkQuartzView alloc] initWithFrame:frame_rect];
+
+ [impl->view setGdkSurface:window];
+
+ /* GdkSurfaces should be hidden by default */
+ [impl->view setHidden:YES];
+ [parent_impl->view addSubview:impl->view];
+ [impl->view release];
+ }
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ GDK_QUARTZ_RELEASE_POOL;
+}
+
+void
+_gdk_quartz_surface_update_position (GdkSurface *window)
+{
+ NSRect frame_rect;
+ NSRect content_rect;
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ GDK_QUARTZ_ALLOC_POOL;
+
+ frame_rect = [impl->toplevel frame];
+ content_rect = [impl->toplevel contentRectForFrameRect:frame_rect];
+
+ _gdk_quartz_surface_xy_to_gdk_xy (content_rect.origin.x,
+ content_rect.origin.y + content_rect.size.height,
+ &window->x, &window->y);
+
+
+ GDK_QUARTZ_RELEASE_POOL;
+}
+
+void
+_gdk_quartz_surface_init_windowing (GdkDisplay *display)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ g_assert (_gdk_root == NULL);
+
+ _gdk_root = _gdk_display_create_window (display);
+
+ _gdk_root->impl = g_object_new (_gdk_root_window_impl_quartz_get_type (), NULL);
+ _gdk_root->impl_window = _gdk_root;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
+
+ _gdk_quartz_screen_update_window_sizes (screen);
+
+ _gdk_root->state = 0; /* We don't want GDK_SURFACE_STATE_WITHDRAWN here */
+ _gdk_root->window_type = GDK_SURFACE_ROOT;
+ _gdk_root->viewable = TRUE;
+
+ impl->wrapper = _gdk_root;
+}
+
+static void
+gdk_quartz_surface_destroy (GdkSurface *window,
+ gboolean recursing,
+ gboolean foreign_destroy)
+{
+ GdkSurfaceImplQuartz *impl;
+ GdkSurface *parent;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ main_window_stack = g_slist_remove (main_window_stack, window);
+
+ g_list_free (impl->sorted_children);
+ impl->sorted_children = NULL;
+
+ parent = window->parent;
+ if (parent)
+ {
+ GdkSurfaceImplQuartz *parent_impl = GDK_SURFACE_IMPL_QUARTZ (parent->impl);
+
+ parent_impl->sorted_children = g_list_remove (parent_impl->sorted_children, window);
+ }
+
+ if (impl->cairo_surface)
+ {
+ cairo_surface_finish (impl->cairo_surface);
+ cairo_surface_set_user_data (impl->cairo_surface, &gdk_quartz_cairo_key,
+ NULL, NULL);
+ impl->cairo_surface = NULL;
+ }
+
+ if (!recursing && !foreign_destroy)
+ {
+ GDK_QUARTZ_ALLOC_POOL;
+
+ if (impl->toplevel)
+ [impl->toplevel close];
+ else if (impl->view)
+ [impl->view removeFromSuperview];
+
+ GDK_QUARTZ_RELEASE_POOL;
+ }
+}
+
+/* FIXME: This might be possible to simplify with client-side windows. Also
+ * note that already_mapped is not used yet, see the x11 backend.
+*/
+static void
+gdk_surface_quartz_show (GdkSurface *window, gboolean already_mapped)
+{
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ gboolean focus_on_map;
+
+ GDK_QUARTZ_ALLOC_POOL;
+
+ if (!GDK_SURFACE_IS_MAPPED (window))
+ focus_on_map = window->focus_on_map;
+ else
+ focus_on_map = TRUE;
+
+ if (WINDOW_IS_TOPLEVEL (window) && impl->toplevel)
+ {
+ gboolean make_key;
+
+ make_key = (window->accept_focus && focus_on_map &&
+ window->window_type != GDK_SURFACE_TEMP);
+
+ [(GdkQuartzNSWindow*)impl->toplevel showAndMakeKey:make_key];
+ clear_toplevel_order ();
+
+ _gdk_quartz_events_send_map_event (window);
+ }
+ else
+ {
+ [impl->view setHidden:NO];
+ }
+
+ [impl->view setNeedsDisplay:YES];
+
+ gdk_synthesize_window_state (window, GDK_SURFACE_STATE_WITHDRAWN, 0);
+
+ if (window->state & GDK_SURFACE_STATE_MAXIMIZED)
+ gdk_surface_maximize (window);
+
+ if (window->state & GDK_SURFACE_STATE_ICONIFIED)
+ gdk_surface_iconify (window);
+
+ if (impl->transient_for && !GDK_SURFACE_DESTROYED (impl->transient_for))
+ _gdk_quartz_surface_attach_to_parent (window);
+
+ GDK_QUARTZ_RELEASE_POOL;
+}
+
+/* Temporarily unsets the parent window, if the window is a
+ * transient.
+ */
+void
+_gdk_quartz_surface_detach_from_parent (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ g_return_if_fail (impl->toplevel != NULL);
+
+ if (impl->transient_for && !GDK_SURFACE_DESTROYED (impl->transient_for))
+ {
+ GdkSurfaceImplQuartz *parent_impl;
+
+ parent_impl = GDK_SURFACE_IMPL_QUARTZ (impl->transient_for->impl);
+ [parent_impl->toplevel removeChildWindow:impl->toplevel];
+ clear_toplevel_order ();
+ }
+}
+
+/* Re-sets the parent window, if the window is a transient. */
+void
+_gdk_quartz_surface_attach_to_parent (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ g_return_if_fail (impl->toplevel != NULL);
+
+ if (impl->transient_for && !GDK_SURFACE_DESTROYED (impl->transient_for))
+ {
+ GdkSurfaceImplQuartz *parent_impl;
+
+ parent_impl = GDK_SURFACE_IMPL_QUARTZ (impl->transient_for->impl);
+ [parent_impl->toplevel addChildWindow:impl->toplevel ordered:NSWindowAbove];
+ clear_toplevel_order ();
+ }
+}
+
+void
+gdk_surface_quartz_hide (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ /* Make sure we're not stuck in fullscreen mode. */
+#ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+ if (get_fullscreen_geometry (window))
+ SetSystemUIMode (kUIModeNormal, 0);
+#endif
+
+ _gdk_surface_clear_update_area (window);
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (WINDOW_IS_TOPLEVEL (window))
+ {
+ /* Update main window. */
+ main_window_stack = g_slist_remove (main_window_stack, window);
+ if ([NSApp mainWindow] == impl->toplevel)
+ _gdk_quartz_surface_did_resign_main (window);
+
+ if (impl->transient_for)
+ _gdk_quartz_surface_detach_from_parent (window);
+
+ [(GdkQuartzNSWindow*)impl->toplevel hide];
+ }
+ else if (impl->view)
+ {
+ [impl->view setHidden:YES];
+ }
+}
+
+void
+gdk_surface_quartz_withdraw (GdkSurface *window)
+{
+ gdk_surface_hide (window);
+}
+
+static void
+move_resize_window_internal (GdkSurface *window,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GdkSurfaceImplQuartz *impl;
+ GdkRectangle old_visible;
+ GdkRectangle new_visible;
+ GdkRectangle scroll_rect;
+ cairo_region_t *old_region;
+ cairo_region_t *expose_region;
+ NSSize delta;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if ((x == -1 || (x == window->x)) &&
+ (y == -1 || (y == window->y)) &&
+ (width == -1 || (width == window->width)) &&
+ (height == -1 || (height == window->height)))
+ {
+ return;
+ }
+
+ if (!impl->toplevel)
+ {
+ /* The previously visible area of this window in a coordinate
+ * system rooted at the origin of this window.
+ */
+ old_visible.x = -window->x;
+ old_visible.y = -window->y;
+
+ old_visible.width = window->width;
+ old_visible.height = window->height;
+ }
+
+ if (x != -1)
+ {
+ delta.width = x - window->x;
+ window->x = x;
+ }
+ else
+ {
+ delta.width = 0;
+ }
+
+ if (y != -1)
+ {
+ delta.height = y - window->y;
+ window->y = y;
+ }
+ else
+ {
+ delta.height = 0;
+ }
+
+ if (width != -1)
+ window->width = width;
+
+ if (height != -1)
+ window->height = height;
+
+ GDK_QUARTZ_ALLOC_POOL;
+
+ if (impl->toplevel)
+ {
+ NSRect content_rect;
+ NSRect frame_rect;
+ gint gx, gy;
+
+ _gdk_quartz_surface_gdk_xy_to_xy (window->x, window->y + window->height,
+ &gx, &gy);
+
+ content_rect = NSMakeRect (gx, gy, window->width, window->height);
+
+ frame_rect = [impl->toplevel frameRectForContentRect:content_rect];
+ [impl->toplevel setFrame:frame_rect display:YES];
+ }
+ else
+ {
+ if (!window->input_only)
+ {
+ NSRect nsrect;
+
+ nsrect = NSMakeRect (window->x, window->y, window->width, window->height);
+
+ /* The newly visible area of this window in a coordinate
+ * system rooted at the origin of this window.
+ */
+ new_visible.x = -window->x;
+ new_visible.y = -window->y;
+ new_visible.width = old_visible.width; /* parent has not changed size */
+ new_visible.height = old_visible.height; /* parent has not changed size */
+
+ expose_region = cairo_region_create_rectangle (&new_visible);
+ old_region = cairo_region_create_rectangle (&old_visible);
+ cairo_region_subtract (expose_region, old_region);
+
+ /* Determine what (if any) part of the previously visible
+ * part of the window can be copied without a redraw
+ */
+ scroll_rect = old_visible;
+ scroll_rect.x -= delta.width;
+ scroll_rect.y -= delta.height;
+ gdk_rectangle_intersect (&scroll_rect, &old_visible, &scroll_rect);
+
+ if (!cairo_region_is_empty (expose_region))
+ {
+ if (scroll_rect.width != 0 && scroll_rect.height != 0)
+ {
+ [impl->view scrollRect:NSMakeRect (scroll_rect.x,
+ scroll_rect.y,
+ scroll_rect.width,
+ scroll_rect.height)
+ by:delta];
+ }
+
+ [impl->view setFrame:nsrect];
+
+ gdk_quartz_surface_set_needs_display_in_region (window, expose_region);
+ }
+ else
+ {
+ [impl->view setFrame:nsrect];
+ [impl->view setNeedsDisplay:YES];
+ }
+
+ cairo_region_destroy (expose_region);
+ cairo_region_destroy (old_region);
+ }
+ }
+
+ GDK_QUARTZ_RELEASE_POOL;
+}
+
+static inline void
+window_quartz_move (GdkSurface *window,
+ gint x,
+ gint y)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
+ return;
+
+ move_resize_window_internal (window, x, y, -1, -1);
+}
+
+static inline void
+window_quartz_resize (GdkSurface *window,
+ gint width,
+ gint height)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
+ return;
+
+ if (width < 1)
+ width = 1;
+ if (height < 1)
+ height = 1;
+
+ move_resize_window_internal (window, -1, -1, width, height);
+}
+
+static inline void
+window_quartz_move_resize (GdkSurface *window,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ if (width < 1)
+ width = 1;
+ if (height < 1)
+ height = 1;
+
+ move_resize_window_internal (window, x, y, width, height);
+}
+
+static void
+gdk_surface_quartz_move_resize (GdkSurface *window,
+ gboolean with_move,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ if (with_move && (width < 0 && height < 0))
+ window_quartz_move (window, x, y);
+ else
+ {
+ if (with_move)
+ window_quartz_move_resize (window, x, y, width, height);
+ else
+ window_quartz_resize (window, width, height);
+ }
+}
+
+/* Get the toplevel ordering from NSApp and update our own list. We do
+ * this on demand since the NSApp’s list is not up to date directly
+ * after we get windowDidBecomeMain.
+ */
+static void
+update_toplevel_order (void)
+{
+ GdkSurfaceImplQuartz *root_impl;
+ NSEnumerator *enumerator;
+ id nswindow;
+ GList *toplevels = NULL;
+
+ root_impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
+
+ if (root_impl->sorted_children)
+ return;
+
+ GDK_QUARTZ_ALLOC_POOL;
+
+ enumerator = [[NSApp orderedWindows] objectEnumerator];
+ while ((nswindow = [enumerator nextObject]))
+ {
+ GdkSurface *window;
+
+ if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
+ continue;
+
+ window = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
+ toplevels = g_list_prepend (toplevels, window);
+ }
+
+ GDK_QUARTZ_RELEASE_POOL;
+
+ root_impl->sorted_children = g_list_reverse (toplevels);
+}
+
+static void
+clear_toplevel_order (void)
+{
+ GdkSurfaceImplQuartz *root_impl;
+
+ root_impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
+
+ g_list_free (root_impl->sorted_children);
+ root_impl->sorted_children = NULL;
+}
+
+static void
+gdk_surface_quartz_raise (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (WINDOW_IS_TOPLEVEL (window))
+ {
+ GdkSurfaceImplQuartz *impl;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ [impl->toplevel orderFront:impl->toplevel];
+
+ clear_toplevel_order ();
+ }
+ else
+ {
+ GdkSurface *parent = window->parent;
+
+ if (parent)
+ {
+ GdkSurfaceImplQuartz *impl;
+
+ impl = (GdkSurfaceImplQuartz *)parent->impl;
+
+ impl->sorted_children = g_list_remove (impl->sorted_children, window);
+ impl->sorted_children = g_list_prepend (impl->sorted_children, window);
+ }
+ }
+}
+
+static void
+gdk_surface_quartz_lower (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (WINDOW_IS_TOPLEVEL (window))
+ {
+ GdkSurfaceImplQuartz *impl;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ [impl->toplevel orderBack:impl->toplevel];
+
+ clear_toplevel_order ();
+ }
+ else
+ {
+ GdkSurface *parent = window->parent;
+
+ if (parent)
+ {
+ GdkSurfaceImplQuartz *impl;
+
+ impl = (GdkSurfaceImplQuartz *)parent->impl;
+
+ impl->sorted_children = g_list_remove (impl->sorted_children, window);
+ impl->sorted_children = g_list_append (impl->sorted_children, window);
+ }
+ }
+}
+
+static void
+gdk_surface_quartz_restack_toplevel (GdkSurface *window,
+ GdkSurface *sibling,
+ gboolean above)
+{
+ GdkSurfaceImplQuartz *impl;
+ gint sibling_num;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (sibling->impl);
+ sibling_num = [impl->toplevel windowNumber];
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (above)
+ [impl->toplevel orderWindow:NSWindowAbove relativeTo:sibling_num];
+ else
+ [impl->toplevel orderWindow:NSWindowBelow relativeTo:sibling_num];
+}
+
+static void
+gdk_surface_quartz_get_geometry (GdkSurface *window,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height)
+{
+ GdkSurfaceImplQuartz *impl;
+ NSRect ns_rect;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ if (window == _gdk_root)
+ {
+ if (x)
+ *x = 0;
+ if (y)
+ *y = 0;
+
+ if (width)
+ *width = window->width;
+ if (height)
+ *height = window->height;
+ }
+ else if (WINDOW_IS_TOPLEVEL (window))
+ {
+ ns_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
+
+ /* This doesn't work exactly as in X. There doesn't seem to be a
+ * way to get the coords relative to the parent window (usually
+ * the window frame), but that seems useless except for
+ * borderless windows where it's relative to the root window. So
+ * we return (0, 0) (should be something like (0, 22)) for
+ * windows with borders and the root relative coordinates
+ * otherwise.
+ */
+ if ([impl->toplevel styleMask] == NSBorderlessWindowMask)
+ {
+ _gdk_quartz_surface_xy_to_gdk_xy (ns_rect.origin.x,
+ ns_rect.origin.y + ns_rect.size.height,
+ x, y);
+ }
+ else
+ {
+ if (x)
+ *x = 0;
+ if (y)
+ *y = 0;
+ }
+
+ if (width)
+ *width = ns_rect.size.width;
+ if (height)
+ *height = ns_rect.size.height;
+ }
+ else
+ {
+ ns_rect = [impl->view frame];
+
+ if (x)
+ *x = ns_rect.origin.x;
+ if (y)
+ *y = ns_rect.origin.y;
+ if (width)
+ *width = ns_rect.size.width;
+ if (height)
+ *height = ns_rect.size.height;
+ }
+}
+
+static void
+gdk_surface_quartz_get_root_coords (GdkSurface *window,
+ gint x,
+ gint y,
+ gint *root_x,
+ gint *root_y)
+{
+ int tmp_x = 0, tmp_y = 0;
+ GdkSurface *toplevel;
+ NSRect content_rect;
+ GdkSurfaceImplQuartz *impl;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ {
+ if (root_x)
+ *root_x = 0;
+ if (root_y)
+ *root_y = 0;
+
+ return;
+ }
+
+ if (window == _gdk_root)
+ {
+ if (root_x)
+ *root_x = x;
+ if (root_y)
+ *root_y = y;
+
+ return;
+ }
+
+ toplevel = gdk_surface_get_toplevel (window);
+ impl = GDK_SURFACE_IMPL_QUARTZ (toplevel->impl);
+
+ content_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
+
+ _gdk_quartz_surface_xy_to_gdk_xy (content_rect.origin.x,
+ content_rect.origin.y + content_rect.size.height,
+ &tmp_x, &tmp_y);
+
+ tmp_x += x;
+ tmp_y += y;
+
+ while (window != toplevel)
+ {
+ if (_gdk_surface_has_impl ((GdkSurface *)window))
+ {
+ tmp_x += window->x;
+ tmp_y += window->y;
+ }
+
+ window = window->parent;
+ }
+
+ if (root_x)
+ *root_x = tmp_x;
+ if (root_y)
+ *root_y = tmp_y;
+}
+
+/* Returns coordinates relative to the passed in window. */
+static GdkSurface *
+gdk_surface_quartz_get_device_state_helper (GdkSurface *window,
+ GdkDevice *device,
+ gdouble *x,
+ gdouble *y,
+ GdkModifierType *mask)
+{
+ NSPoint point;
+ gint x_tmp, y_tmp;
+ GdkSurface *toplevel;
+ GdkSurface *found_window;
+
+ g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), NULL);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ {
+ *x = 0;
+ *y = 0;
+ *mask = 0;
+ return NULL;
+ }
+
+ toplevel = gdk_surface_get_toplevel (window);
+
+ *mask = _gdk_quartz_events_get_current_keyboard_modifiers () |
+ _gdk_quartz_events_get_current_mouse_modifiers ();
+
+ /* Get the y coordinate, needs to be flipped. */
+ if (window == _gdk_root)
+ {
+ point = [NSEvent mouseLocation];
+ _gdk_quartz_surface_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
+ }
+ else
+ {
+ GdkSurfaceImplQuartz *impl;
+ NSWindow *nswindow;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (toplevel->impl);
+ nswindow = impl->toplevel;
+
+ point = [nswindow mouseLocationOutsideOfEventStream];
+
+ x_tmp = point.x;
+ y_tmp = toplevel->height - point.y;
+
+ window = (GdkSurface *)toplevel;
+ }
+
+ found_window = _gdk_quartz_surface_find_child (window, x_tmp, y_tmp,
+ FALSE);
+
+ /* We never return the root window. */
+ if (found_window == _gdk_root)
+ found_window = NULL;
+
+ *x = x_tmp;
+ *y = y_tmp;
+
+ return found_window;
+}
+
+static gboolean
+gdk_surface_quartz_get_device_state (GdkSurface *window,
+ GdkDevice *device,
+ gdouble *x,
+ gdouble *y,
+ GdkModifierType *mask)
+{
+ return gdk_surface_quartz_get_device_state_helper (window,
+ device,
+ x, y, mask) != NULL;
+}
+
+static GdkEventMask
+gdk_surface_quartz_get_events (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window))
+ return 0;
+ else
+ return window->event_mask;
+}
+
+static void
+gdk_surface_quartz_set_events (GdkSurface *window,
+ GdkEventMask event_mask)
+{
+ /* The mask is set in the common code. */
+}
+
+static void
+gdk_quartz_surface_set_urgency_hint (GdkSurface *window,
+ gboolean urgent)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ /* FIXME: Implement */
+}
+
+static void
+gdk_quartz_surface_set_geometry_hints (GdkSurface *window,
+ const GdkGeometry *geometry,
+ GdkSurfaceHints geom_mask)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ g_return_if_fail (geometry != NULL);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ if (!impl->toplevel)
+ return;
+
+ if (geom_mask & GDK_HINT_POS)
+ {
+ /* FIXME: Implement */
+ }
+
+ if (geom_mask & GDK_HINT_USER_POS)
+ {
+ /* FIXME: Implement */
+ }
+
+ if (geom_mask & GDK_HINT_USER_SIZE)
+ {
+ /* FIXME: Implement */
+ }
+
+ if (geom_mask & GDK_HINT_MIN_SIZE)
+ {
+ NSSize size;
+
+ size.width = geometry->min_width;
+ size.height = geometry->min_height;
+
+ [impl->toplevel setContentMinSize:size];
+ }
+
+ if (geom_mask & GDK_HINT_MAX_SIZE)
+ {
+ NSSize size;
+
+ size.width = geometry->max_width;
+ size.height = geometry->max_height;
+
+ [impl->toplevel setContentMaxSize:size];
+ }
+
+ if (geom_mask & GDK_HINT_BASE_SIZE)
+ {
+ /* FIXME: Implement */
+ }
+
+ if (geom_mask & GDK_HINT_RESIZE_INC)
+ {
+ NSSize size;
+
+ size.width = geometry->width_inc;
+ size.height = geometry->height_inc;
+
+ [impl->toplevel setContentResizeIncrements:size];
+ }
+
+ if (geom_mask & GDK_HINT_ASPECT)
+ {
+ NSSize size;
+
+ if (geometry->min_aspect != geometry->max_aspect)
+ {
+ g_warning ("Only equal minimum and maximum aspect ratios are supported on Mac OS. Using minimum aspect ratio...");
+ }
+
+ size.width = geometry->min_aspect;
+ size.height = 1.0;
+
+ [impl->toplevel setContentAspectRatio:size];
+ }
+
+ if (geom_mask & GDK_HINT_WIN_GRAVITY)
+ {
+ /* FIXME: Implement */
+ }
+}
+
+static void
+gdk_quartz_surface_set_title (GdkSurface *window,
+ const gchar *title)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ g_return_if_fail (title != NULL);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (impl->toplevel)
+ {
+ GDK_QUARTZ_ALLOC_POOL;
+ [impl->toplevel setTitle:[NSString stringWithUTF8String:title]];
+ GDK_QUARTZ_RELEASE_POOL;
+ }
+}
+
+static void
+gdk_quartz_surface_set_role (GdkSurface *window,
+ const gchar *role)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ /* FIXME: Implement */
+}
+
+static void
+gdk_quartz_surface_set_startup_id (GdkSurface *window,
+ const gchar *startup_id)
+{
+ /* FIXME: Implement? */
+}
+
+static void
+gdk_quartz_surface_set_transient_for (GdkSurface *window,
+ GdkSurface *parent)
+{
+ GdkSurfaceImplQuartz *window_impl;
+ GdkSurfaceImplQuartz *parent_impl;
+
+ if (GDK_SURFACE_DESTROYED (window) || GDK_SURFACE_DESTROYED (parent) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ window_impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ if (!window_impl->toplevel)
+ return;
+
+ GDK_QUARTZ_ALLOC_POOL;
+
+ if (window_impl->transient_for)
+ {
+ _gdk_quartz_surface_detach_from_parent (window);
+
+ g_object_unref (window_impl->transient_for);
+ window_impl->transient_for = NULL;
+ }
+
+ parent_impl = GDK_SURFACE_IMPL_QUARTZ (parent->impl);
+ if (parent_impl->toplevel)
+ {
+ /* We save the parent because it needs to be unset/reset when
+ * hiding and showing the window.
+ */
+
+ /* We don't set transients for tooltips, they are already
+ * handled by the window level being the top one. If we do, then
+ * the parent window will be brought to the top just because the
+ * tooltip is, which is not what we want.
+ */
+ if (gdk_surface_get_type_hint (window) != GDK_SURFACE_TYPE_HINT_TOOLTIP)
+ {
+ window_impl->transient_for = g_object_ref (parent);
+
+ /* We only add the window if it is shown, otherwise it will
+ * be shown unconditionally here. If it is not shown, the
+ * window will be added in show() instead.
+ */
+ if (!(window->state & GDK_SURFACE_STATE_WITHDRAWN))
+ _gdk_quartz_surface_attach_to_parent (window);
+ }
+ }
+
+ GDK_QUARTZ_RELEASE_POOL;
+}
+
+static void
+gdk_surface_quartz_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape,
+ gint x,
+ gint y)
+{
+ /* FIXME: Implement */
+}
+
+static void
+gdk_surface_quartz_input_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+ /* FIXME: Implement */
+}
+
+static void
+gdk_quartz_surface_set_accept_focus (GdkSurface *window,
+ gboolean accept_focus)
+{
+ window->accept_focus = accept_focus != FALSE;
+}
+
+static void
+gdk_quartz_surface_set_focus_on_map (GdkSurface *window,
+ gboolean focus_on_map)
+{
+ window->focus_on_map = focus_on_map != FALSE;
+}
+
+static void
+gdk_quartz_surface_set_icon_name (GdkSurface *window,
+ const gchar *name)
+{
+ /* FIXME: Implement */
+}
+
+static void
+gdk_quartz_surface_focus (GdkSurface *window,
+ guint32 timestamp)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ if (window->accept_focus && window->window_type != GDK_SURFACE_TEMP)
+ {
+ GDK_QUARTZ_ALLOC_POOL;
+ [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
+ clear_toplevel_order ();
+ GDK_QUARTZ_RELEASE_POOL;
+ }
+}
+
+static gint
+window_type_hint_to_level (GdkSurfaceTypeHint hint)
+{
+ /* the order in this switch statement corresponds to the actual
+ * stacking order: the first group is top, the last group is bottom
+ */
+ switch (hint)
+ {
+ case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
+ case GDK_SURFACE_TYPE_HINT_COMBO:
+ case GDK_SURFACE_TYPE_HINT_DND:
+ case GDK_SURFACE_TYPE_HINT_TOOLTIP:
+ return NSPopUpMenuWindowLevel;
+
+ case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
+ case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
+ return NSStatusWindowLevel;
+
+ case GDK_SURFACE_TYPE_HINT_MENU: /* Torn-off menu */
+ case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
+ return NSTornOffMenuWindowLevel;
+
+ case GDK_SURFACE_TYPE_HINT_DOCK:
+ return NSFloatingWindowLevel; /* NSDockWindowLevel is deprecated, and not replaced */
+
+ case GDK_SURFACE_TYPE_HINT_UTILITY:
+ case GDK_SURFACE_TYPE_HINT_DIALOG: /* Dialog window */
+ case GDK_SURFACE_TYPE_HINT_NORMAL: /* Normal toplevel window */
+ case GDK_SURFACE_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
+ return NSNormalWindowLevel;
+
+ case GDK_SURFACE_TYPE_HINT_DESKTOP:
+ return kCGDesktopWindowLevelKey; /* doesn't map to any real Cocoa model */
+
+ default:
+ break;
+ }
+
+ return NSNormalWindowLevel;
+}
+
+static gboolean
+window_type_hint_to_shadow (GdkSurfaceTypeHint hint)
+{
+ switch (hint)
+ {
+ case GDK_SURFACE_TYPE_HINT_NORMAL: /* Normal toplevel window */
+ case GDK_SURFACE_TYPE_HINT_DIALOG: /* Dialog window */
+ case GDK_SURFACE_TYPE_HINT_DOCK:
+ case GDK_SURFACE_TYPE_HINT_UTILITY:
+ case GDK_SURFACE_TYPE_HINT_MENU: /* Torn-off menu */
+ case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
+ case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
+ case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
+ case GDK_SURFACE_TYPE_HINT_COMBO:
+ case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
+ case GDK_SURFACE_TYPE_HINT_TOOLTIP:
+ return TRUE;
+
+ case GDK_SURFACE_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
+ case GDK_SURFACE_TYPE_HINT_DESKTOP: /* N/A */
+ case GDK_SURFACE_TYPE_HINT_DND:
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+window_type_hint_to_hides_on_deactivate (GdkSurfaceTypeHint hint)
+{
+ switch (hint)
+ {
+ case GDK_SURFACE_TYPE_HINT_UTILITY:
+ case GDK_SURFACE_TYPE_HINT_MENU: /* Torn-off menu */
+ case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
+ case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
+ case GDK_SURFACE_TYPE_HINT_TOOLTIP:
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+_gdk_quartz_surface_update_has_shadow (GdkSurfaceImplQuartz *impl)
+{
+ gboolean has_shadow;
+
+ /* In case there is any shadow set we have to turn off the
+ * NSWindow setHasShadow as the system drawn ones wont match our
+ * window boundary anymore */
+ has_shadow = (window_type_hint_to_shadow (impl->type_hint) && !impl->shadow_max);
+
+ [impl->toplevel setHasShadow: has_shadow];
+}
+
+static void
+gdk_quartz_surface_set_type_hint (GdkSurface *window,
+ GdkSurfaceTypeHint hint)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ impl->type_hint = hint;
+
+ /* Match the documentation, only do something if we're not mapped yet. */
+ if (GDK_SURFACE_IS_MAPPED (window))
+ return;
+
+ _gdk_quartz_surface_update_has_shadow (impl);
+ [impl->toplevel setLevel: window_type_hint_to_level (hint)];
+ [impl->toplevel setHidesOnDeactivate: window_type_hint_to_hides_on_deactivate (hint)];
+}
+
+static GdkSurfaceTypeHint
+gdk_quartz_surface_get_type_hint (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return GDK_SURFACE_TYPE_HINT_NORMAL;
+
+ return GDK_SURFACE_IMPL_QUARTZ (window->impl)->type_hint;
+}
+
+static void
+gdk_quartz_surface_set_modal_hint (GdkSurface *window,
+ gboolean modal)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ /* FIXME: Implement */
+}
+
+static void
+gdk_quartz_surface_set_skip_taskbar_hint (GdkSurface *window,
+ gboolean skips_taskbar)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ /* FIXME: Implement */
+}
+
+static void
+gdk_quartz_surface_set_skip_pager_hint (GdkSurface *window,
+ gboolean skips_pager)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ /* FIXME: Implement */
+}
+
+static void
+gdk_quartz_surface_begin_resize_drag (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (!impl->toplevel)
+ {
+ g_warning ("Can't call gdk_surface_begin_resize_drag on non-toplevel window");
+ return;
+ }
+
+ [(GdkQuartzNSWindow *)impl->toplevel beginManualResize:edge];
+}
+
+static void
+gdk_quartz_surface_begin_move_drag (GdkSurface *window,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (!impl->toplevel)
+ {
+ g_warning ("Can't call gdk_surface_begin_move_drag on non-toplevel window");
+ return;
+ }
+
+ [(GdkQuartzNSWindow *)impl->toplevel beginManualMove];
+}
+
+static void
+gdk_quartz_surface_set_icon_list (GdkSurface *window,
+ GList *surfaces)
+{
+ /* FIXME: Implement */
+}
+
+static void
+gdk_quartz_surface_get_frame_extents (GdkSurface *window,
+ GdkRectangle *rect)
+{
+ GdkSurface *toplevel;
+ GdkSurfaceImplQuartz *impl;
+ NSRect ns_rect;
+
+ g_return_if_fail (rect != NULL);
+
+
+ rect->x = 0;
+ rect->y = 0;
+ rect->width = 1;
+ rect->height = 1;
+
+ toplevel = gdk_surface_get_toplevel (window);
+ impl = GDK_SURFACE_IMPL_QUARTZ (toplevel->impl);
+
+ ns_rect = [impl->toplevel frame];
+
+ _gdk_quartz_surface_xy_to_gdk_xy (ns_rect.origin.x,
+ ns_rect.origin.y + ns_rect.size.height,
+ &rect->x, &rect->y);
+
+ rect->width = ns_rect.size.width;
+ rect->height = ns_rect.size.height;
+}
+
+/* Fake protocol to make gcc think that it's OK to call setStyleMask
+ even if it isn't. We check to make sure before actually calling
+ it. */
+
+@protocol CanSetStyleMask
+- (void)setStyleMask:(int)mask;
+@end
+
+static void
+gdk_quartz_surface_set_decorations (GdkSurface *window,
+ GdkWMDecoration decorations)
+{
+ GdkSurfaceImplQuartz *impl;
+ NSUInteger old_mask, new_mask;
+ NSView *old_view;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (decorations == 0 || GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP ||
+ impl->type_hint == GDK_SURFACE_TYPE_HINT_SPLASHSCREEN )
+ {
+ new_mask = NSBorderlessWindowMask;
+ }
+ else
+ {
+ /* FIXME: Honor other GDK_DECOR_* flags. */
+ new_mask = (NSTitledWindowMask | NSClosableWindowMask |
+ NSMiniaturizableWindowMask | NSResizableWindowMask);
+ }
+
+ GDK_QUARTZ_ALLOC_POOL;
+
+ old_mask = [impl->toplevel styleMask];
+
+ if (old_mask != new_mask)
+ {
+ NSRect rect;
+
+ old_view = [[impl->toplevel contentView] retain];
+
+ rect = [impl->toplevel frame];
+
+ /* Properly update the size of the window when the titlebar is
+ * added or removed.
+ */
+ if (old_mask == NSBorderlessWindowMask &&
+ new_mask != NSBorderlessWindowMask)
+ {
+ rect = [NSWindow frameRectForContentRect:rect styleMask:new_mask];
+
+ }
+ else if (old_mask != NSBorderlessWindowMask &&
+ new_mask == NSBorderlessWindowMask)
+ {
+ rect = [NSWindow contentRectForFrameRect:rect styleMask:old_mask];
+ }
+
+ /* Note, before OS 10.6 there doesn't seem to be a way to change this
+ * without recreating the toplevel. From 10.6 onward, a simple call to
+ * setStyleMask takes care of most of this, except for ensuring that the
+ * title is set.
+ */
+ if ([impl->toplevel respondsToSelector:@selector(setStyleMask:)])
+ {
+ NSString *title = [impl->toplevel title];
+
+ [(id<CanSetStyleMask>)impl->toplevel setStyleMask:new_mask];
+
+ /* It appears that unsetting and then resetting NSTitledWindowMask
+ * does not reset the title in the title bar as might be expected.
+ *
+ * In theory we only need to set this if new_mask includes
+ * NSTitledWindowMask. This behaved extremely oddly when
+ * conditionalized upon that and since it has no side effects (i.e.
+ * if NSTitledWindowMask is not requested, the title will not be
+ * displayed) just do it unconditionally. We also must null check
+ * 'title' before setting it to avoid crashing.
+ */
+ if (title)
+ [impl->toplevel setTitle:title];
+ }
+ else
+ {
+ NSString *title = [impl->toplevel title];
+ NSColor *bg = [impl->toplevel backgroundColor];
+ NSScreen *screen = [impl->toplevel screen];
+
+ /* Make sure the old window is closed, recall that releasedWhenClosed
+ * is set on GdkQuartzSurfaces.
+ */
+ [impl->toplevel close];
+
+ impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:rect
+ styleMask:new_mask
+ backing:NSBackingStoreBuffered
+ defer:NO
+ screen:screen];
+ _gdk_quartz_surface_update_has_shadow (impl);
+
+ [impl->toplevel setLevel: window_type_hint_to_level (impl->type_hint)];
+ if (title)
+ [impl->toplevel setTitle:title];
+ [impl->toplevel setBackgroundColor:bg];
+ [impl->toplevel setHidesOnDeactivate: window_type_hint_to_hides_on_deactivate (impl->type_hint)];
+ [impl->toplevel setContentView:old_view];
+ }
+
+ if (new_mask == NSBorderlessWindowMask)
+ {
+ [impl->toplevel setContentSize:rect.size];
+ [impl->toplevel setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+ }
+ else
+ [impl->toplevel setFrame:rect display:YES];
+
+ /* Invalidate the window shadow for non-opaque views that have shadow
+ * enabled, to get the shadow shape updated.
+ */
+ if (![old_view isOpaque] && [impl->toplevel hasShadow])
+ [(GdkQuartzView*)old_view setNeedsInvalidateShadow:YES];
+
+ [old_view release];
+ }
+
+ GDK_QUARTZ_RELEASE_POOL;
+}
+
+static gboolean
+gdk_quartz_surface_get_decorations (GdkSurface *window,
+ GdkWMDecoration *decorations)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return FALSE;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (decorations)
+ {
+ /* Borderless is 0, so we can't check it as a bit being set. */
+ if ([impl->toplevel styleMask] == NSBorderlessWindowMask)
+ {
+ *decorations = 0;
+ }
+ else
+ {
+ /* FIXME: Honor the other GDK_DECOR_* flags. */
+ *decorations = GDK_DECOR_ALL;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+gdk_quartz_surface_set_functions (GdkSurface *window,
+ GdkWMFunction functions)
+{
+ GdkSurfaceImplQuartz *impl;
+ gboolean min, max, close;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (functions & GDK_FUNC_ALL)
+ {
+ min = !(functions & GDK_FUNC_MINIMIZE);
+ max = !(functions & GDK_FUNC_MAXIMIZE);
+ close = !(functions & GDK_FUNC_CLOSE);
+ }
+ else
+ {
+ min = (functions & GDK_FUNC_MINIMIZE);
+ max = (functions & GDK_FUNC_MAXIMIZE);
+ close = (functions & GDK_FUNC_CLOSE);
+ }
+
+ if (impl->toplevel)
+ {
+ NSUInteger mask = [impl->toplevel styleMask];
+
+ if (min)
+ mask = mask | NSMiniaturizableWindowMask;
+ else
+ mask = mask & ~NSMiniaturizableWindowMask;
+
+ if (max)
+ mask = mask | NSResizableWindowMask;
+ else
+ mask = mask & ~NSResizableWindowMask;
+
+ if (close)
+ mask = mask | NSClosableWindowMask;
+ else
+ mask = mask & ~NSClosableWindowMask;
+
+ [impl->toplevel setStyleMask:mask];
+ }
+}
+
+static void
+gdk_quartz_surface_stick (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+}
+
+static void
+gdk_quartz_surface_unstick (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+}
+
+static void
+gdk_quartz_surface_maximize (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl;
+ gboolean maximized;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ GDK_QUARTZ_ALLOC_POOL;
+
+ if (impl->toplevel && !maximized)
+ [impl->toplevel zoom:nil];
+
+ GDK_QUARTZ_RELEASE_POOL;
+ }
+}
+
+static void
+gdk_quartz_surface_unmaximize (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl;
+ gboolean maximized;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ GDK_QUARTZ_ALLOC_POOL;
+
+ if (impl->toplevel && maximized)
+ [impl->toplevel zoom:nil];
+
+ GDK_QUARTZ_RELEASE_POOL;
+ }
+}
+
+static void
+gdk_quartz_surface_iconify (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ GDK_QUARTZ_ALLOC_POOL;
+
+ if (impl->toplevel)
+ [impl->toplevel miniaturize:nil];
+
+ GDK_QUARTZ_RELEASE_POOL;
+ }
+ else
+ {
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_SURFACE_STATE_ICONIFIED);
+ }
+}
+
+static void
+gdk_quartz_surface_deiconify (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ GDK_QUARTZ_ALLOC_POOL;
+
+ if (impl->toplevel)
+ [impl->toplevel deminiaturize:nil];
+
+ GDK_QUARTZ_RELEASE_POOL;
+ }
+ else
+ {
+ gdk_synthesize_window_state (window,
+ GDK_SURFACE_STATE_ICONIFIED,
+ 0);
+ }
+}
+
+#ifdef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
+
+static gboolean
+window_is_fullscreen (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ return ([impl->toplevel styleMask] & NSFullScreenWindowMask) != 0;
+}
+
+static void
+gdk_quartz_surface_fullscreen (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (!window_is_fullscreen (window))
+ [impl->toplevel toggleFullScreen:nil];
+}
+
+static void
+gdk_quartz_surface_unfullscreen (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (window_is_fullscreen (window))
+ [impl->toplevel toggleFullScreen:nil];
+}
+
+void
+_gdk_quartz_surface_update_fullscreen_state (GdkSurface *window)
+{
+ gboolean is_fullscreen;
+ gboolean was_fullscreen;
+
+ is_fullscreen = window_is_fullscreen (window);
+ was_fullscreen = (gdk_surface_get_state (window) & GDK_SURFACE_STATE_FULLSCREEN) != 0;
+
+ if (is_fullscreen != was_fullscreen)
+ {
+ if (is_fullscreen)
+ gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
+ else
+ gdk_synthesize_window_state (window, GDK_SURFACE_STATE_FULLSCREEN, 0);
+ }
+}
+
+#else
+
+static FullscreenSavedGeometry *
+get_fullscreen_geometry (GdkSurface *window)
+{
+ return g_object_get_data (G_OBJECT (window), FULLSCREEN_DATA);
+}
+
+static void
+gdk_quartz_surface_fullscreen (GdkSurface *window)
+{
+ FullscreenSavedGeometry *geometry;
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ NSRect frame;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ geometry = get_fullscreen_geometry (window);
+ if (!geometry)
+ {
+ geometry = g_new (FullscreenSavedGeometry, 1);
+
+ geometry->x = window->x;
+ geometry->y = window->y;
+ geometry->width = window->width;
+ geometry->height = window->height;
+
+ if (!gdk_surface_get_decorations (window, &geometry->decor))
+ geometry->decor = GDK_DECOR_ALL;
+
+ g_object_set_data_full (G_OBJECT (window),
+ FULLSCREEN_DATA, geometry,
+ g_free);
+
+ gdk_surface_set_decorations (window, 0);
+
+ frame = [[impl->toplevel screen] frame];
+ move_resize_window_internal (window,
+ 0, 0,
+ frame.size.width, frame.size.height);
+ [impl->toplevel setContentSize:frame.size];
+ [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
+
+ clear_toplevel_order ();
+ }
+
+ SetSystemUIMode (kUIModeAllHidden, kUIOptionAutoShowMenuBar);
+
+ gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
+}
+
+static void
+gdk_quartz_surface_unfullscreen (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ FullscreenSavedGeometry *geometry;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ geometry = get_fullscreen_geometry (window);
+ if (geometry)
+ {
+ SetSystemUIMode (kUIModeNormal, 0);
+
+ move_resize_window_internal (window,
+ geometry->x,
+ geometry->y,
+ geometry->width,
+ geometry->height);
+
+ gdk_surface_set_decorations (window, geometry->decor);
+
+ g_object_set_data (G_OBJECT (window), FULLSCREEN_DATA, NULL);
+
+ [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
+ clear_toplevel_order ();
+
+ gdk_synthesize_window_state (window, GDK_SURFACE_STATE_FULLSCREEN, 0);
+ }
+}
+
+#endif
+
+static void
+gdk_quartz_surface_set_keep_above (GdkSurface *window,
+ gboolean setting)
+{
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ gint level;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ level = window_type_hint_to_level (gdk_surface_get_type_hint (window));
+
+ /* Adjust normal window level by one if necessary. */
+ [impl->toplevel setLevel: level + (setting ? 1 : 0)];
+}
+
+static void
+gdk_quartz_surface_set_keep_below (GdkSurface *window,
+ gboolean setting)
+{
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+ gint level;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ level = window_type_hint_to_level (gdk_surface_get_type_hint (window));
+
+ /* Adjust normal window level by one if necessary. */
+ [impl->toplevel setLevel: level - (setting ? 1 : 0)];
+}
+
+static GdkSurface *
+gdk_quartz_surface_get_group (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD, NULL);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return NULL;
+
+ /* FIXME: Implement */
+
+ return NULL;
+}
+
+static void
+gdk_quartz_surface_set_group (GdkSurface *window,
+ GdkSurface *leader)
+{
+ /* FIXME: Implement */
+}
+
+static void
+gdk_quartz_surface_destroy_notify (GdkSurface *window)
+{
+ check_grab_destroy (window);
+}
+
+static void
+gdk_quartz_surface_set_opacity (GdkSurface *window,
+ gdouble opacity)
+{
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ if (opacity < 0)
+ opacity = 0;
+ else if (opacity > 1)
+ opacity = 1;
+
+ [impl->toplevel setAlphaValue: opacity];
+}
+
+static void
+gdk_quartz_surface_set_shadow_width (GdkSurface *window,
+ gint left,
+ gint right,
+ gint top,
+ gint bottom)
+{
+ GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl->shadow_top = top;
+ impl->shadow_max = MAX (MAX (left, right), MAX (top, bottom));
+ _gdk_quartz_surface_update_has_shadow (impl);
+}
+
+/* Protocol to build cleanly for OSX < 10.7 */
+@protocol ScaleFactor
+- (CGFloat) backingScaleFactor;
+@end
+
+static gint
+gdk_quartz_surface_get_scale_factor (GdkSurface *window)
+{
+ GdkSurfaceImplQuartz *impl;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return 1;
+
+ impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
+
+ if (impl->toplevel != NULL && gdk_quartz_osx_version() >= GDK_OSX_LION)
+ return [(id <ScaleFactor>) impl->toplevel backingScaleFactor];
+
+ return 1;
+}
+
+static void
+gdk_surface_impl_quartz_class_init (GdkSurfaceImplQuartzClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_CLASS (klass);
+ GdkSurfaceImplQuartzClass *impl_quartz_class = GDK_SURFACE_IMPL_QUARTZ_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = gdk_surface_impl_quartz_finalize;
+
+ impl_class->ref_cairo_surface = gdk_quartz_ref_cairo_surface;
+ impl_class->show = gdk_surface_quartz_show;
+ impl_class->hide = gdk_surface_quartz_hide;
+ impl_class->withdraw = gdk_surface_quartz_withdraw;
+ impl_class->set_events = gdk_surface_quartz_set_events;
+ impl_class->get_events = gdk_surface_quartz_get_events;
+ impl_class->raise = gdk_surface_quartz_raise;
+ impl_class->lower = gdk_surface_quartz_lower;
+ impl_class->restack_toplevel = gdk_surface_quartz_restack_toplevel;
+ impl_class->move_resize = gdk_surface_quartz_move_resize;
+ impl_class->get_geometry = gdk_surface_quartz_get_geometry;
+ impl_class->get_root_coords = gdk_surface_quartz_get_root_coords;
+ impl_class->get_device_state = gdk_surface_quartz_get_device_state;
+ impl_class->shape_combine_region = gdk_surface_quartz_shape_combine_region;
+ impl_class->input_shape_combine_region = gdk_surface_quartz_input_shape_combine_region;
+ impl_class->destroy = gdk_quartz_surface_destroy;
+ impl_class->begin_paint = gdk_surface_impl_quartz_begin_paint;
+ impl_class->get_scale_factor = gdk_quartz_surface_get_scale_factor;
+
+ impl_class->focus = gdk_quartz_surface_focus;
+ impl_class->set_type_hint = gdk_quartz_surface_set_type_hint;
+ impl_class->get_type_hint = gdk_quartz_surface_get_type_hint;
+ impl_class->set_modal_hint = gdk_quartz_surface_set_modal_hint;
+ impl_class->set_skip_taskbar_hint = gdk_quartz_surface_set_skip_taskbar_hint;
+ impl_class->set_skip_pager_hint = gdk_quartz_surface_set_skip_pager_hint;
+ impl_class->set_urgency_hint = gdk_quartz_surface_set_urgency_hint;
+ impl_class->set_geometry_hints = gdk_quartz_surface_set_geometry_hints;
+ impl_class->set_title = gdk_quartz_surface_set_title;
+ impl_class->set_role = gdk_quartz_surface_set_role;
+ impl_class->set_startup_id = gdk_quartz_surface_set_startup_id;
+ impl_class->set_transient_for = gdk_quartz_surface_set_transient_for;
+ impl_class->get_frame_extents = gdk_quartz_surface_get_frame_extents;
+ impl_class->set_accept_focus = gdk_quartz_surface_set_accept_focus;
+ impl_class->set_focus_on_map = gdk_quartz_surface_set_focus_on_map;
+ impl_class->set_icon_list = gdk_quartz_surface_set_icon_list;
+ impl_class->set_icon_name = gdk_quartz_surface_set_icon_name;
+ impl_class->iconify = gdk_quartz_surface_iconify;
+ impl_class->deiconify = gdk_quartz_surface_deiconify;
+ impl_class->stick = gdk_quartz_surface_stick;
+ impl_class->unstick = gdk_quartz_surface_unstick;
+ impl_class->maximize = gdk_quartz_surface_maximize;
+ impl_class->unmaximize = gdk_quartz_surface_unmaximize;
+ impl_class->fullscreen = gdk_quartz_surface_fullscreen;
+ impl_class->unfullscreen = gdk_quartz_surface_unfullscreen;
+ impl_class->set_keep_above = gdk_quartz_surface_set_keep_above;
+ impl_class->set_keep_below = gdk_quartz_surface_set_keep_below;
+ impl_class->get_group = gdk_quartz_surface_get_group;
+ impl_class->set_group = gdk_quartz_surface_set_group;
+ impl_class->set_decorations = gdk_quartz_surface_set_decorations;
+ impl_class->get_decorations = gdk_quartz_surface_get_decorations;
+ impl_class->set_functions = gdk_quartz_surface_set_functions;
+ impl_class->set_functions = gdk_quartz_surface_set_functions;
+ impl_class->begin_resize_drag = gdk_quartz_surface_begin_resize_drag;
+ impl_class->begin_move_drag = gdk_quartz_surface_begin_move_drag;
+ impl_class->set_opacity = gdk_quartz_surface_set_opacity;
+ impl_class->set_shadow_width = gdk_quartz_surface_set_shadow_width;
+ impl_class->destroy_notify = gdk_quartz_surface_destroy_notify;
+ impl_class->register_dnd = _gdk_quartz_surface_register_dnd;
+ impl_class->drag_begin = _gdk_quartz_surface_drag_begin;
+ impl_class->process_updates_recurse = _gdk_quartz_surface_process_updates_recurse;
+
+ impl_class->create_gl_context = gdk_quartz_surface_create_gl_context;
+
+ impl_quartz_class->get_context = gdk_surface_impl_quartz_get_context;
+ impl_quartz_class->release_context = gdk_surface_impl_quartz_release_context;
+}
+
+GType
+_gdk_surface_impl_quartz_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (!object_type)
+ {
+ const GTypeInfo object_info =
+ {
+ sizeof (GdkSurfaceImplQuartzClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gdk_surface_impl_quartz_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdkSurfaceImplQuartz),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gdk_surface_impl_quartz_init,
+ };
+
+ object_type = g_type_register_static (GDK_TYPE_SURFACE_IMPL,
+ "GdkSurfaceImplQuartz",
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+CGContextRef
+gdk_quartz_surface_get_context (GdkSurfaceImplQuartz *window,
+ gboolean antialias)
+{
+ if (!GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->get_context)
+ {
+ g_warning ("%s doesn't implement GdkSurfaceImplQuartzClass::get_context()",
+ G_OBJECT_TYPE_NAME (window));
+ return NULL;
+ }
+
+ return GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->get_context (window, antialias);
+}
+
+void
+gdk_quartz_surface_release_context (GdkSurfaceImplQuartz *window,
+ CGContextRef cg_context)
+{
+ if (!GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->release_context)
+ {
+ g_warning ("%s doesn't implement GdkSurfaceImplQuartzClass::release_context()",
+ G_OBJECT_TYPE_NAME (window));
+ return;
+ }
+
+ GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->release_context (window, cg_context);
+}
+
+
+
+static CGContextRef
+gdk_root_window_impl_quartz_get_context (GdkSurfaceImplQuartz *window,
+ gboolean antialias)
+{
+ CGColorSpaceRef colorspace;
+ CGContextRef cg_context;
+ GdkSurfaceImplQuartz *window_impl = GDK_SURFACE_IMPL_QUARTZ (window);
+
+ if (GDK_SURFACE_DESTROYED (window_impl->wrapper))
+ return NULL;
+
+ /* We do not have the notion of a root window on OS X. We fake this
+ * by creating a 1x1 bitmap and return a context to that.
+ */
+ colorspace = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
+ cg_context = CGBitmapContextCreate (NULL,
+ 1, 1, 8, 4, colorspace,
+ kCGImageAlphaPremultipliedLast);
+ CGColorSpaceRelease (colorspace);
+
+ return cg_context;
+}
+
+static void
+gdk_root_window_impl_quartz_release_context (GdkSurfaceImplQuartz *window,
+ CGContextRef cg_context)
+{
+ CGContextRelease (cg_context);
+}
+
+static void
+gdk_root_window_impl_quartz_class_init (GdkRootWindowImplQuartzClass *klass)
+{
+ GdkSurfaceImplQuartzClass *window_quartz_class = GDK_SURFACE_IMPL_QUARTZ_CLASS (klass);
+
+ root_window_parent_class = g_type_class_peek_parent (klass);
+
+ window_quartz_class->get_context = gdk_root_window_impl_quartz_get_context;
+ window_quartz_class->release_context = gdk_root_window_impl_quartz_release_context;
+}
+
+static void
+gdk_root_window_impl_quartz_init (GdkRootWindowImplQuartz *impl)
+{
+}
+
+GType
+_gdk_root_window_impl_quartz_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (!object_type)
+ {
+ const GTypeInfo object_info =
+ {
+ sizeof (GdkRootWindowImplQuartzClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gdk_root_window_impl_quartz_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdkRootWindowImplQuartz),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gdk_root_window_impl_quartz_init,
+ };
+
+ object_type = g_type_register_static (GDK_TYPE_SURFACE_IMPL_QUARTZ,
+ "GdkRootWindowQuartz",
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+GList *
+get_toplevels (void)
+{
+ update_toplevel_order ();
+ return GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl)->sorted_children;
+}
--- /dev/null
+/* gdkdrawable-quartz.h
+ *
+ * Copyright (C) 2005 Imendio AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_SURFACE_QUARTZ_H__
+#define __GDK_SURFACE_QUARTZ_H__
+
+#import <gdk/quartz/GdkQuartzView.h>
+#import <gdk/quartz/GdkQuartzNSWindow.h>
+#include "gdk/gdksurfaceimpl.h"
+
+G_BEGIN_DECLS
+
+/* Window implementation for Quartz
+ */
+
+typedef struct _GdkSurfaceImplQuartz GdkSurfaceImplQuartz;
+typedef struct _GdkSurfaceImplQuartzClass GdkSurfaceImplQuartzClass;
+
+#define GDK_TYPE_SURFACE_IMPL_QUARTZ (_gdk_surface_impl_quartz_get_type ())
+#define GDK_SURFACE_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL_QUARTZ, GdkSurfaceImplQuartz))
+#define GDK_SURFACE_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL_QUARTZ, GdkSurfaceImplQuartzClass))
+#define GDK_IS_SURFACE_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL_QUARTZ))
+#define GDK_IS_SURFACE_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL_QUARTZ))
+#define GDK_SURFACE_IMPL_QUARTZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL_QUARTZ, GdkSurfaceImplQuartzClass))
+
+struct _GdkSurfaceImplQuartz
+{
+ GdkSurfaceImpl parent_instance;
+
+ GdkSurface *wrapper;
+
+ NSWindow *toplevel;
+ NSTrackingRectTag tracking_rect;
+ GdkQuartzView *view;
+
+ GdkSurfaceTypeHint type_hint;
+
+ gint in_paint_rect_count;
+
+ GdkSurface *transient_for;
+
+ /* Sorted by z-order */
+ GList *sorted_children;
+
+ cairo_region_t *needs_display_region;
+
+ cairo_surface_t *cairo_surface;
+
+ gint shadow_top;
+
+ gint shadow_max;
+};
+
+struct _GdkSurfaceImplQuartzClass
+{
+ GdkSurfaceImplClass parent_class;
+
+ CGContextRef (* get_context) (GdkSurfaceImplQuartz *window,
+ gboolean antialias);
+ void (* release_context) (GdkSurfaceImplQuartz *window,
+ CGContextRef cg_context);
+};
+
+GType _gdk_surface_impl_quartz_get_type (void);
+
+CGContextRef gdk_quartz_surface_get_context (GdkSurfaceImplQuartz *window,
+ gboolean antialias);
+void gdk_quartz_surface_release_context (GdkSurfaceImplQuartz *window,
+ CGContextRef context);
+
+/* Root window implementation for Quartz
+ */
+
+typedef struct _GdkRootWindowImplQuartz GdkRootWindowImplQuartz;
+typedef struct _GdkRootWindowImplQuartzClass GdkRootWindowImplQuartzClass;
+
+#define GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ (_gdk_root_window_impl_quartz_get_type ())
+#define GDK_ROOT_WINDOW_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ, GdkRootWindowImplQuartz))
+#define GDK_ROOT_WINDOW_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ, GdkRootWindowImplQuartzClass))
+#define GDK_IS_ROOT_WINDOW_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ))
+#define GDK_IS_ROOT_WINDOW_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ))
+#define GDK_ROOT_WINDOW_IMPL_QUARTZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ, GdkRootWindowImplQuartzClass))
+
+struct _GdkRootWindowImplQuartz
+{
+ GdkSurfaceImplQuartz parent_instance;
+};
+
+struct _GdkRootWindowImplQuartzClass
+{
+ GdkSurfaceImplQuartzClass parent_class;
+};
+
+GType _gdk_root_window_impl_quartz_get_type (void);
+
+GList *get_toplevels (void);
+
+G_END_DECLS
+
+#endif /* __GDK_SURFACE_QUARTZ_H__ */
+++ /dev/null
-/* gdkwindow-quartz.c
- *
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- * Copyright (C) 2005-2007 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <gdk/gdk.h>
-#include <gdk/gdkdeviceprivate.h>
-#include <gdk/gdkdisplayprivate.h>
-
-#include "gdkwindowimpl.h"
-#include "gdkprivate-quartz.h"
-#include "gdkglcontext-quartz.h"
-#include "gdkquartzscreen.h"
-#include "gdkquartzcursor.h"
-
-#include <Carbon/Carbon.h>
-#include <AvailabilityMacros.h>
-
-#include <sys/time.h>
-#include <cairo-quartz.h>
-
-static gpointer parent_class;
-static gpointer root_window_parent_class;
-
-static GSList *update_nswindows;
-static gboolean in_process_all_updates = FALSE;
-
-static GSList *main_window_stack;
-
-void _gdk_quartz_surface_flush (GdkSurfaceImplQuartz *window_impl);
-
-typedef struct
-{
- gint x, y;
- gint width, height;
- GdkWMDecoration decor;
-} FullscreenSavedGeometry;
-
-
-#ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
-static FullscreenSavedGeometry *get_fullscreen_geometry (GdkSurface *window);
-#endif
-
-#define FULLSCREEN_DATA "fullscreen-data"
-
-static void update_toplevel_order (void);
-static void clear_toplevel_order (void);
-
-#define WINDOW_IS_TOPLEVEL(window) (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD)
-
-/*
- * GdkQuartzSurface
- */
-
-struct _GdkQuartzSurface
-{
- GdkSurface parent;
-};
-
-struct _GdkQuartzSurfaceClass
-{
- GdkSurfaceClass parent_class;
-};
-
-G_DEFINE_TYPE (GdkQuartzSurface, gdk_quartz_surface, GDK_TYPE_SURFACE);
-
-static void
-gdk_quartz_surface_class_init (GdkQuartzSurfaceClass *quartz_surface_class)
-{
-}
-
-static void
-gdk_quartz_surface_init (GdkQuartzSurface *quartz_surface)
-{
-}
-
-
-/*
- * GdkQuartzSurfaceImpl
- */
-
-NSView *
-gdk_quartz_surface_get_nsview (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- return ((GdkSurfaceImplQuartz *)window->impl)->view;
-}
-
-NSWindow *
-gdk_quartz_surface_get_nswindow (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- return ((GdkSurfaceImplQuartz *)window->impl)->toplevel;
-}
-
-static CGContextRef
-gdk_surface_impl_quartz_get_context (GdkSurfaceImplQuartz *window_impl,
- gboolean antialias)
-{
- CGContextRef cg_context;
- CGSize scale;
-
- if (GDK_SURFACE_DESTROYED (window_impl->wrapper))
- return NULL;
-
- /* Lock focus when not called as part of a drawRect call. This
- * is needed when called from outside "real" expose events, for
- * example for synthesized expose events when realizing windows
- * and for widgets that send fake expose events like the arrow
- * buttons in spinbuttons or the position marker in rulers.
- */
- if (window_impl->in_paint_rect_count == 0)
- {
- if (![window_impl->view lockFocusIfCanDraw])
- return NULL;
- }
-
- cg_context = [[NSGraphicsContext currentContext] graphicsPort];
- CGContextSaveGState (cg_context);
- CGContextSetAllowsAntialiasing (cg_context, antialias);
-
- /* Undo the default scaling transform, since we apply our own
- * in gdk_quartz_ref_cairo_surface () */
- scale = CGContextConvertSizeToDeviceSpace (cg_context,
- CGSizeMake (1.0, 1.0));
- CGContextScaleCTM (cg_context, 1.0 / scale.width, 1.0 / scale.height);
-
- return cg_context;
-}
-
-static void
-gdk_surface_impl_quartz_release_context (GdkSurfaceImplQuartz *window_impl,
- CGContextRef cg_context)
-{
- CGContextRestoreGState (cg_context);
- CGContextSetAllowsAntialiasing (cg_context, TRUE);
-
- /* See comment in gdk_quartz_surface_get_context(). */
- if (window_impl->in_paint_rect_count == 0)
- {
- _gdk_quartz_surface_flush (window_impl);
- [window_impl->view unlockFocus];
- }
-}
-
-static void
-check_grab_destroy (GdkSurface *window)
-{
- GList *devices = NULL, *l;
- GdkDisplay *display = gdk_surface_get_display (window);
- GdkSeat *seat;
-
- seat = gdk_display_get_default_seat (display);
-
- devices = g_list_prepend (devices, gdk_seat_get_keyboard (seat));
- devices = g_list_prepend (devices, gdk_seat_get_pointer (seat));
-
- for (l = devices; l; l = l->next)
- {
- GdkDeviceGrabInfo *grab;
-
- grab = _gdk_display_get_last_device_grab (display, l->data);
- if (grab && grab->native_window == window)
- {
- /* Serials are always 0 in quartz, but for clarity: */
- grab->serial_end = grab->serial_start;
- grab->implicit_ungrab = TRUE;
- }
- }
-
- g_list_free (devices);
-}
-
-static void
-gdk_surface_impl_quartz_finalize (GObject *object)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (object);
-
- check_grab_destroy (GDK_SURFACE_IMPL_QUARTZ (object)->wrapper);
-
- if (impl->transient_for)
- g_object_unref (impl->transient_for);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-/* Help preventing "beam sync penalty" where CG makes all graphics code
- * block until the next vsync if we try to flush (including call display on
- * a view) too often. We do this by limiting the manual flushing done
- * outside of expose calls to less than some frequency when measured over
- * the last 4 flushes. This is a bit arbitray, but seems to make it possible
- * for some quick manual flushes (such as gtkruler or gimp’s marching ants)
- * without hitting the max flush frequency.
- *
- * If drawable NULL, no flushing is done, only registering that a flush was
- * done externally.
- */
-void
-_gdk_quartz_surface_flush (GdkSurfaceImplQuartz *window_impl)
-{
- static struct timeval prev_tv;
- static gint intervals[4];
- static gint index;
- struct timeval tv;
- gint ms;
-
- gettimeofday (&tv, NULL);
- ms = (tv.tv_sec - prev_tv.tv_sec) * 1000 + (tv.tv_usec - prev_tv.tv_usec) / 1000;
- intervals[index++ % 4] = ms;
-
- if (window_impl)
- {
- ms = intervals[0] + intervals[1] + intervals[2] + intervals[3];
-
- /* ~25Hz on average. */
- if (ms > 4*40)
- {
- if (window_impl)
- [window_impl->toplevel flushWindow];
-
- prev_tv = tv;
- }
- }
- else
- prev_tv = tv;
-}
-
-static cairo_user_data_key_t gdk_quartz_cairo_key;
-
-typedef struct {
- GdkSurfaceImplQuartz *window_impl;
- CGContextRef cg_context;
-} GdkQuartzCairoSurfaceData;
-
-static void
-gdk_quartz_cairo_surface_destroy (void *data)
-{
- GdkQuartzCairoSurfaceData *surface_data = data;
-
- surface_data->window_impl->cairo_surface = NULL;
-
- gdk_quartz_surface_release_context (surface_data->window_impl,
- surface_data->cg_context);
-
- g_free (surface_data);
-}
-
-static cairo_surface_t *
-gdk_quartz_create_cairo_surface (GdkSurfaceImplQuartz *impl,
- int width,
- int height)
-{
- CGContextRef cg_context;
- GdkQuartzCairoSurfaceData *surface_data;
- cairo_surface_t *surface;
-
- cg_context = gdk_quartz_surface_get_context (impl, TRUE);
-
- if (!cg_context)
- return NULL;
-
- surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
- surface_data->window_impl = impl;
- surface_data->cg_context = cg_context;
-
- surface = cairo_quartz_surface_create_for_cg_context (cg_context,
- width, height);
-
- cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key,
- surface_data,
- gdk_quartz_cairo_surface_destroy);
-
- return surface;
-}
-
-static cairo_surface_t *
-gdk_quartz_ref_cairo_surface (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- if (!impl->cairo_surface)
- {
- gint scale = gdk_surface_get_scale_factor (impl->wrapper);
-
- impl->cairo_surface =
- gdk_quartz_create_cairo_surface (impl,
- gdk_surface_get_width (impl->wrapper) * scale,
- gdk_surface_get_height (impl->wrapper) * scale);
-
- cairo_surface_set_device_scale (impl->cairo_surface, scale, scale);
- }
- else
- cairo_surface_reference (impl->cairo_surface);
-
- return impl->cairo_surface;
-}
-
-static void
-gdk_surface_impl_quartz_init (GdkSurfaceImplQuartz *impl)
-{
- impl->type_hint = GDK_SURFACE_TYPE_HINT_NORMAL;
-}
-
-static gboolean
-gdk_surface_impl_quartz_begin_paint (GdkSurface *window)
-{
- return FALSE;
-}
-
-static void
-gdk_quartz_surface_set_needs_display_in_region (GdkSurface *window,
- cairo_region_t *region)
-{
- GdkSurfaceImplQuartz *impl;
- int i, n_rects;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (!impl->needs_display_region)
- impl->needs_display_region = cairo_region_create ();
-
- cairo_region_union (impl->needs_display_region, region);
-
- n_rects = cairo_region_num_rectangles (region);
- for (i = 0; i < n_rects; i++)
- {
- cairo_rectangle_int_t rect;
- cairo_region_get_rectangle (region, i, &rect);
- [impl->view setNeedsDisplayInRect:NSMakeRect (rect.x, rect.y,
- rect.width, rect.height)];
- }
-}
-
-void
-_gdk_quartz_surface_process_updates_recurse (GdkSurface *window,
- cairo_region_t *region)
-{
- /* Make sure to only flush each toplevel at most once if we're called
- * from process_all_updates.
- */
- if (in_process_all_updates)
- {
- GdkSurface *toplevel;
-
- toplevel = gdk_surface_get_toplevel (window);
- if (toplevel && WINDOW_IS_TOPLEVEL (toplevel))
- {
- GdkSurfaceImplQuartz *toplevel_impl;
- NSWindow *nswindow;
-
- toplevel_impl = (GdkSurfaceImplQuartz *)toplevel->impl;
- nswindow = toplevel_impl->toplevel;
-
- /* In theory, we could skip the flush disabling, since we only
- * have one NSView.
- */
- if (nswindow && ![nswindow isFlushWindowDisabled])
- {
- [nswindow retain];
- [nswindow disableFlushWindow];
- update_nswindows = g_slist_prepend (update_nswindows, nswindow);
- }
- }
- }
-
- if (WINDOW_IS_TOPLEVEL (window))
- gdk_quartz_surface_set_needs_display_in_region (window, region);
- else
- _gdk_surface_process_updates_recurse (window, region);
-
- /* NOTE: I'm not sure if we should displayIfNeeded here. It slows down a
- * lot (since it triggers the beam syncing) and things seem to work
- * without it.
- */
-}
-
-static const gchar *
-get_default_title (void)
-{
- const char *title;
-
- title = g_get_application_name ();
- if (!title)
- title = g_get_prgname ();
-
- return title;
-}
-
-static void
-get_ancestor_coordinates_from_child (GdkSurface *child_window,
- gint child_x,
- gint child_y,
- GdkSurface *ancestor_window,
- gint *ancestor_x,
- gint *ancestor_y)
-{
- while (child_window != ancestor_window)
- {
- child_x += child_window->x;
- child_y += child_window->y;
-
- child_window = child_window->parent;
- }
-
- *ancestor_x = child_x;
- *ancestor_y = child_y;
-}
-
-void
-_gdk_quartz_surface_debug_highlight (GdkSurface *window, gint number)
-{
- gint x, y;
- gint gx, gy;
- GdkSurface *toplevel;
- gint tx, ty;
- static NSWindow *debug_window[10];
- static NSRect old_rect[10];
- NSRect rect;
- NSColor *color;
-
- g_return_if_fail (number >= 0 && number <= 9);
-
- if (window == _gdk_root)
- return;
-
- if (window == NULL)
- {
- if (debug_window[number])
- [debug_window[number] close];
- debug_window[number] = NULL;
-
- return;
- }
-
- toplevel = gdk_surface_get_toplevel (window);
- get_ancestor_coordinates_from_child (window, 0, 0, toplevel, &x, &y);
-
- gdk_surface_get_origin (toplevel, &tx, &ty);
- x += tx;
- y += ty;
-
- _gdk_quartz_surface_gdk_xy_to_xy (x, y + window->height,
- &gx, &gy);
-
- rect = NSMakeRect (gx, gy, window->width, window->height);
-
- if (debug_window[number] && NSEqualRects (rect, old_rect[number]))
- return;
-
- old_rect[number] = rect;
-
- if (debug_window[number])
- [debug_window[number] close];
-
- debug_window[number] = [[NSWindow alloc] initWithContentRect:rect
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO];
-
- switch (number)
- {
- case 0:
- color = [NSColor redColor];
- break;
- case 1:
- color = [NSColor blueColor];
- break;
- case 2:
- color = [NSColor greenColor];
- break;
- case 3:
- color = [NSColor yellowColor];
- break;
- case 4:
- color = [NSColor brownColor];
- break;
- case 5:
- color = [NSColor purpleColor];
- break;
- default:
- color = [NSColor blackColor];
- break;
- }
-
- [debug_window[number] setBackgroundColor:color];
- [debug_window[number] setAlphaValue:0.4];
- [debug_window[number] setOpaque:NO];
- [debug_window[number] setReleasedWhenClosed:YES];
- [debug_window[number] setIgnoresMouseEvents:YES];
- [debug_window[number] setLevel:NSFloatingWindowLevel];
-
- [debug_window[number] orderFront:nil];
-}
-
-gboolean
-_gdk_quartz_surface_is_ancestor (GdkSurface *ancestor,
- GdkSurface *window)
-{
- if (ancestor == NULL || window == NULL)
- return FALSE;
-
- return (gdk_surface_get_parent (window) == ancestor ||
- _gdk_quartz_surface_is_ancestor (ancestor,
- gdk_surface_get_parent (window)));
-}
-
-
-/* See notes on top of gdkscreen-quartz.c */
-void
-_gdk_quartz_surface_gdk_xy_to_xy (gint gdk_x,
- gint gdk_y,
- gint *ns_x,
- gint *ns_y)
-{
- GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
-
- if (ns_y)
- *ns_y = screen_quartz->height - gdk_y + screen_quartz->min_y;
-
- if (ns_x)
- *ns_x = gdk_x + screen_quartz->min_x;
-}
-
-void
-_gdk_quartz_surface_xy_to_gdk_xy (gint ns_x,
- gint ns_y,
- gint *gdk_x,
- gint *gdk_y)
-{
- GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
-
- if (gdk_y)
- *gdk_y = screen_quartz->height - ns_y + screen_quartz->min_y;
-
- if (gdk_x)
- *gdk_x = ns_x - screen_quartz->min_x;
-}
-
-void
-_gdk_quartz_surface_nspoint_to_gdk_xy (NSPoint point,
- gint *x,
- gint *y)
-{
- _gdk_quartz_surface_xy_to_gdk_xy (point.x, point.y,
- x, y);
-}
-
-static GdkSurface *
-find_child_window_helper (GdkSurface *window,
- gint x,
- gint y,
- gint x_offset,
- gint y_offset,
- gboolean get_toplevel)
-{
- GdkSurfaceImplQuartz *impl;
- GList *l;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (window == _gdk_root)
- update_toplevel_order ();
-
- for (l = impl->sorted_children; l; l = l->next)
- {
- GdkSurface *child = l->data;
- GdkSurfaceImplQuartz *child_impl = GDK_SURFACE_IMPL_QUARTZ (child->impl);
- int temp_x, temp_y;
-
- if (!GDK_SURFACE_IS_MAPPED (child))
- continue;
-
- temp_x = x_offset + child->x;
- temp_y = y_offset + child->y;
-
- /* Special-case the root window. We have to include the title
- * bar in the checks, otherwise the window below the title bar
- * will be found i.e. events punch through. (If we can find a
- * better way to deal with the events in gdkevents-quartz, this
- * might not be needed.)
- */
- if (window == _gdk_root)
- {
- NSRect frame = NSMakeRect (0, 0, 100, 100);
- NSRect content;
- NSUInteger mask;
- int titlebar_height;
-
- mask = [child_impl->toplevel styleMask];
-
- /* Get the title bar height. */
- content = [NSWindow contentRectForFrameRect:frame
- styleMask:mask];
- titlebar_height = frame.size.height - content.size.height;
-
- if (titlebar_height > 0 &&
- x >= temp_x && y >= temp_y - titlebar_height &&
- x < temp_x + child->width && y < temp_y)
- {
- /* The root means "unknown" i.e. a window not managed by
- * GDK.
- */
- return (GdkSurface *)_gdk_root;
- }
- }
-
- if ((!get_toplevel || (get_toplevel && window == _gdk_root)) &&
- x >= temp_x && y >= temp_y &&
- x < temp_x + child->width && y < temp_y + child->height)
- {
- /* Look for child windows. */
- return find_child_window_helper (l->data,
- x, y,
- temp_x, temp_y,
- get_toplevel);
- }
- }
-
- return window;
-}
-
-/* Given a GdkSurface and coordinates relative to it, returns the
- * innermost subwindow that contains the point. If the coordinates are
- * outside the passed in window, NULL is returned.
- */
-GdkSurface *
-_gdk_quartz_surface_find_child (GdkSurface *window,
- gint x,
- gint y,
- gboolean get_toplevel)
-{
- if (x >= 0 && y >= 0 && x < window->width && y < window->height)
- return find_child_window_helper (window, x, y, 0, 0, get_toplevel);
-
- return NULL;
-}
-
-
-void
-_gdk_quartz_surface_did_become_main (GdkSurface *window)
-{
- main_window_stack = g_slist_remove (main_window_stack, window);
-
- if (window->window_type != GDK_SURFACE_TEMP)
- main_window_stack = g_slist_prepend (main_window_stack, window);
-
- clear_toplevel_order ();
-}
-
-void
-_gdk_quartz_surface_did_resign_main (GdkSurface *window)
-{
- GdkSurface *new_window = NULL;
-
- if (main_window_stack)
- new_window = main_window_stack->data;
- else
- {
- GList *toplevels;
-
- toplevels = get_toplevels ();
- if (toplevels)
- new_window = toplevels->data;
- }
-
- if (new_window &&
- new_window != window &&
- GDK_SURFACE_IS_MAPPED (new_window) &&
- WINDOW_IS_TOPLEVEL (new_window))
- {
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (new_window->impl);
-
- [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
- }
-
- clear_toplevel_order ();
-}
-
-static NSScreen *
-get_nsscreen_for_point (gint x, gint y)
-{
- int i;
- NSArray *screens;
- NSScreen *screen = NULL;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- screens = [NSScreen screens];
-
- for (i = 0; i < [screens count]; i++)
- {
- NSRect rect = [[screens objectAtIndex:i] frame];
-
- if (x >= rect.origin.x && x <= rect.origin.x + rect.size.width &&
- y >= rect.origin.y && y <= rect.origin.y + rect.size.height)
- {
- screen = [screens objectAtIndex:i];
- break;
- }
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-
- return screen;
-}
-
-void
-_gdk_quartz_display_create_window_impl (GdkDisplay *display,
- GdkSurface *window,
- GdkSurface *real_parent,
- GdkEventMask event_mask,
- GdkSurfaceAttr *attributes)
-{
- GdkSurfaceImplQuartz *impl;
- GdkSurfaceImplQuartz *parent_impl;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- impl = g_object_new (GDK_TYPE_SURFACE_IMPL_QUARTZ, NULL);
- window->impl = GDK_SURFACE_IMPL (impl);
- impl->wrapper = window;
-
- parent_impl = GDK_SURFACE_IMPL_QUARTZ (window->parent->impl);
-
- switch (window->window_type)
- {
- case GDK_SURFACE_TOPLEVEL:
- case GDK_SURFACE_TEMP:
- if (GDK_SURFACE_TYPE (window->parent) != GDK_SURFACE_ROOT)
- {
- /* The common code warns for this case */
- parent_impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
- }
- }
-
- /* Maintain the z-ordered list of children. */
- if (window->parent != _gdk_root)
- parent_impl->sorted_children = g_list_prepend (parent_impl->sorted_children, window);
- else
- clear_toplevel_order ();
-
- impl->view = NULL;
-
- switch (window->window_type)
- {
- case GDK_SURFACE_TOPLEVEL:
- case GDK_SURFACE_TEMP:
- {
- NSScreen *screen;
- NSRect screen_rect;
- NSRect content_rect;
- NSUInteger style_mask;
- int nx, ny;
-
- /* initWithContentRect will place on the mainScreen by default.
- * We want to select the screen to place on ourselves. We need
- * to find the screen the window will be on and correct the
- * content_rect coordinates to be relative to that screen.
- */
- _gdk_quartz_surface_gdk_xy_to_xy (window->x, window->y, &nx, &ny);
-
- screen = get_nsscreen_for_point (nx, ny);
- screen_rect = [screen frame];
- nx -= screen_rect.origin.x;
- ny -= screen_rect.origin.y;
-
- content_rect = NSMakeRect (nx, ny - window->height,
- window->width,
- window->height);
-
- if (window->window_type == GDK_SURFACE_TEMP)
- {
- style_mask = NSBorderlessWindowMask;
- }
- else
- {
- style_mask = (NSTitledWindowMask |
- NSClosableWindowMask |
- NSMiniaturizableWindowMask |
- NSResizableWindowMask);
- }
-
- impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:content_rect
- styleMask:style_mask
- backing:NSBackingStoreBuffered
- defer:NO
- screen:screen];
-
- gdk_surface_set_title (window, get_default_title ());
-
- [impl->toplevel setOpaque:NO];
- [impl->toplevel setBackgroundColor:[NSColor clearColor]];
-
- content_rect.origin.x = 0;
- content_rect.origin.y = 0;
-
- impl->view = [[GdkQuartzView alloc] initWithFrame:content_rect];
- [impl->view setGdkSurface:window];
- [impl->toplevel setContentView:impl->view];
- [impl->view release];
- }
- break;
-
- case GDK_SURFACE_CHILD:
- {
- GdkSurfaceImplQuartz *parent_impl = GDK_SURFACE_IMPL_QUARTZ (window->parent->impl);
-
- if (!window->input_only)
- {
- NSRect frame_rect = NSMakeRect (window->x + window->parent->abs_x,
- window->y + window->parent->abs_y,
- window->width,
- window->height);
-
- impl->view = [[GdkQuartzView alloc] initWithFrame:frame_rect];
-
- [impl->view setGdkSurface:window];
-
- /* GdkSurfaces should be hidden by default */
- [impl->view setHidden:YES];
- [parent_impl->view addSubview:impl->view];
- [impl->view release];
- }
- }
- break;
-
- default:
- g_assert_not_reached ();
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-void
-_gdk_quartz_surface_update_position (GdkSurface *window)
-{
- NSRect frame_rect;
- NSRect content_rect;
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- GDK_QUARTZ_ALLOC_POOL;
-
- frame_rect = [impl->toplevel frame];
- content_rect = [impl->toplevel contentRectForFrameRect:frame_rect];
-
- _gdk_quartz_surface_xy_to_gdk_xy (content_rect.origin.x,
- content_rect.origin.y + content_rect.size.height,
- &window->x, &window->y);
-
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-void
-_gdk_quartz_surface_init_windowing (GdkDisplay *display)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_assert (_gdk_root == NULL);
-
- _gdk_root = _gdk_display_create_window (display);
-
- _gdk_root->impl = g_object_new (_gdk_root_window_impl_quartz_get_type (), NULL);
- _gdk_root->impl_window = _gdk_root;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
-
- _gdk_quartz_screen_update_window_sizes (screen);
-
- _gdk_root->state = 0; /* We don't want GDK_SURFACE_STATE_WITHDRAWN here */
- _gdk_root->window_type = GDK_SURFACE_ROOT;
- _gdk_root->viewable = TRUE;
-
- impl->wrapper = _gdk_root;
-}
-
-static void
-gdk_quartz_surface_destroy (GdkSurface *window,
- gboolean recursing,
- gboolean foreign_destroy)
-{
- GdkSurfaceImplQuartz *impl;
- GdkSurface *parent;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- main_window_stack = g_slist_remove (main_window_stack, window);
-
- g_list_free (impl->sorted_children);
- impl->sorted_children = NULL;
-
- parent = window->parent;
- if (parent)
- {
- GdkSurfaceImplQuartz *parent_impl = GDK_SURFACE_IMPL_QUARTZ (parent->impl);
-
- parent_impl->sorted_children = g_list_remove (parent_impl->sorted_children, window);
- }
-
- if (impl->cairo_surface)
- {
- cairo_surface_finish (impl->cairo_surface);
- cairo_surface_set_user_data (impl->cairo_surface, &gdk_quartz_cairo_key,
- NULL, NULL);
- impl->cairo_surface = NULL;
- }
-
- if (!recursing && !foreign_destroy)
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel)
- [impl->toplevel close];
- else if (impl->view)
- [impl->view removeFromSuperview];
-
- GDK_QUARTZ_RELEASE_POOL;
- }
-}
-
-/* FIXME: This might be possible to simplify with client-side windows. Also
- * note that already_mapped is not used yet, see the x11 backend.
-*/
-static void
-gdk_surface_quartz_show (GdkSurface *window, gboolean already_mapped)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- gboolean focus_on_map;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- if (!GDK_SURFACE_IS_MAPPED (window))
- focus_on_map = window->focus_on_map;
- else
- focus_on_map = TRUE;
-
- if (WINDOW_IS_TOPLEVEL (window) && impl->toplevel)
- {
- gboolean make_key;
-
- make_key = (window->accept_focus && focus_on_map &&
- window->window_type != GDK_SURFACE_TEMP);
-
- [(GdkQuartzNSWindow*)impl->toplevel showAndMakeKey:make_key];
- clear_toplevel_order ();
-
- _gdk_quartz_events_send_map_event (window);
- }
- else
- {
- [impl->view setHidden:NO];
- }
-
- [impl->view setNeedsDisplay:YES];
-
- gdk_synthesize_window_state (window, GDK_SURFACE_STATE_WITHDRAWN, 0);
-
- if (window->state & GDK_SURFACE_STATE_MAXIMIZED)
- gdk_surface_maximize (window);
-
- if (window->state & GDK_SURFACE_STATE_ICONIFIED)
- gdk_surface_iconify (window);
-
- if (impl->transient_for && !GDK_SURFACE_DESTROYED (impl->transient_for))
- _gdk_quartz_surface_attach_to_parent (window);
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-/* Temporarily unsets the parent window, if the window is a
- * transient.
- */
-void
-_gdk_quartz_surface_detach_from_parent (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- g_return_if_fail (impl->toplevel != NULL);
-
- if (impl->transient_for && !GDK_SURFACE_DESTROYED (impl->transient_for))
- {
- GdkSurfaceImplQuartz *parent_impl;
-
- parent_impl = GDK_SURFACE_IMPL_QUARTZ (impl->transient_for->impl);
- [parent_impl->toplevel removeChildWindow:impl->toplevel];
- clear_toplevel_order ();
- }
-}
-
-/* Re-sets the parent window, if the window is a transient. */
-void
-_gdk_quartz_surface_attach_to_parent (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- g_return_if_fail (impl->toplevel != NULL);
-
- if (impl->transient_for && !GDK_SURFACE_DESTROYED (impl->transient_for))
- {
- GdkSurfaceImplQuartz *parent_impl;
-
- parent_impl = GDK_SURFACE_IMPL_QUARTZ (impl->transient_for->impl);
- [parent_impl->toplevel addChildWindow:impl->toplevel ordered:NSWindowAbove];
- clear_toplevel_order ();
- }
-}
-
-void
-gdk_surface_quartz_hide (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- /* Make sure we're not stuck in fullscreen mode. */
-#ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
- if (get_fullscreen_geometry (window))
- SetSystemUIMode (kUIModeNormal, 0);
-#endif
-
- _gdk_surface_clear_update_area (window);
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (WINDOW_IS_TOPLEVEL (window))
- {
- /* Update main window. */
- main_window_stack = g_slist_remove (main_window_stack, window);
- if ([NSApp mainWindow] == impl->toplevel)
- _gdk_quartz_surface_did_resign_main (window);
-
- if (impl->transient_for)
- _gdk_quartz_surface_detach_from_parent (window);
-
- [(GdkQuartzNSWindow*)impl->toplevel hide];
- }
- else if (impl->view)
- {
- [impl->view setHidden:YES];
- }
-}
-
-void
-gdk_surface_quartz_withdraw (GdkSurface *window)
-{
- gdk_surface_hide (window);
-}
-
-static void
-move_resize_window_internal (GdkSurface *window,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- GdkSurfaceImplQuartz *impl;
- GdkRectangle old_visible;
- GdkRectangle new_visible;
- GdkRectangle scroll_rect;
- cairo_region_t *old_region;
- cairo_region_t *expose_region;
- NSSize delta;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if ((x == -1 || (x == window->x)) &&
- (y == -1 || (y == window->y)) &&
- (width == -1 || (width == window->width)) &&
- (height == -1 || (height == window->height)))
- {
- return;
- }
-
- if (!impl->toplevel)
- {
- /* The previously visible area of this window in a coordinate
- * system rooted at the origin of this window.
- */
- old_visible.x = -window->x;
- old_visible.y = -window->y;
-
- old_visible.width = window->width;
- old_visible.height = window->height;
- }
-
- if (x != -1)
- {
- delta.width = x - window->x;
- window->x = x;
- }
- else
- {
- delta.width = 0;
- }
-
- if (y != -1)
- {
- delta.height = y - window->y;
- window->y = y;
- }
- else
- {
- delta.height = 0;
- }
-
- if (width != -1)
- window->width = width;
-
- if (height != -1)
- window->height = height;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel)
- {
- NSRect content_rect;
- NSRect frame_rect;
- gint gx, gy;
-
- _gdk_quartz_surface_gdk_xy_to_xy (window->x, window->y + window->height,
- &gx, &gy);
-
- content_rect = NSMakeRect (gx, gy, window->width, window->height);
-
- frame_rect = [impl->toplevel frameRectForContentRect:content_rect];
- [impl->toplevel setFrame:frame_rect display:YES];
- }
- else
- {
- if (!window->input_only)
- {
- NSRect nsrect;
-
- nsrect = NSMakeRect (window->x, window->y, window->width, window->height);
-
- /* The newly visible area of this window in a coordinate
- * system rooted at the origin of this window.
- */
- new_visible.x = -window->x;
- new_visible.y = -window->y;
- new_visible.width = old_visible.width; /* parent has not changed size */
- new_visible.height = old_visible.height; /* parent has not changed size */
-
- expose_region = cairo_region_create_rectangle (&new_visible);
- old_region = cairo_region_create_rectangle (&old_visible);
- cairo_region_subtract (expose_region, old_region);
-
- /* Determine what (if any) part of the previously visible
- * part of the window can be copied without a redraw
- */
- scroll_rect = old_visible;
- scroll_rect.x -= delta.width;
- scroll_rect.y -= delta.height;
- gdk_rectangle_intersect (&scroll_rect, &old_visible, &scroll_rect);
-
- if (!cairo_region_is_empty (expose_region))
- {
- if (scroll_rect.width != 0 && scroll_rect.height != 0)
- {
- [impl->view scrollRect:NSMakeRect (scroll_rect.x,
- scroll_rect.y,
- scroll_rect.width,
- scroll_rect.height)
- by:delta];
- }
-
- [impl->view setFrame:nsrect];
-
- gdk_quartz_surface_set_needs_display_in_region (window, expose_region);
- }
- else
- {
- [impl->view setFrame:nsrect];
- [impl->view setNeedsDisplay:YES];
- }
-
- cairo_region_destroy (expose_region);
- cairo_region_destroy (old_region);
- }
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-static inline void
-window_quartz_move (GdkSurface *window,
- gint x,
- gint y)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
- return;
-
- move_resize_window_internal (window, x, y, -1, -1);
-}
-
-static inline void
-window_quartz_resize (GdkSurface *window,
- gint width,
- gint height)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
- return;
-
- if (width < 1)
- width = 1;
- if (height < 1)
- height = 1;
-
- move_resize_window_internal (window, -1, -1, width, height);
-}
-
-static inline void
-window_quartz_move_resize (GdkSurface *window,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- if (width < 1)
- width = 1;
- if (height < 1)
- height = 1;
-
- move_resize_window_internal (window, x, y, width, height);
-}
-
-static void
-gdk_surface_quartz_move_resize (GdkSurface *window,
- gboolean with_move,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- if (with_move && (width < 0 && height < 0))
- window_quartz_move (window, x, y);
- else
- {
- if (with_move)
- window_quartz_move_resize (window, x, y, width, height);
- else
- window_quartz_resize (window, width, height);
- }
-}
-
-/* Get the toplevel ordering from NSApp and update our own list. We do
- * this on demand since the NSApp’s list is not up to date directly
- * after we get windowDidBecomeMain.
- */
-static void
-update_toplevel_order (void)
-{
- GdkSurfaceImplQuartz *root_impl;
- NSEnumerator *enumerator;
- id nswindow;
- GList *toplevels = NULL;
-
- root_impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
-
- if (root_impl->sorted_children)
- return;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- enumerator = [[NSApp orderedWindows] objectEnumerator];
- while ((nswindow = [enumerator nextObject]))
- {
- GdkSurface *window;
-
- if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
- continue;
-
- window = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
- toplevels = g_list_prepend (toplevels, window);
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-
- root_impl->sorted_children = g_list_reverse (toplevels);
-}
-
-static void
-clear_toplevel_order (void)
-{
- GdkSurfaceImplQuartz *root_impl;
-
- root_impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
-
- g_list_free (root_impl->sorted_children);
- root_impl->sorted_children = NULL;
-}
-
-static void
-gdk_surface_quartz_raise (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (WINDOW_IS_TOPLEVEL (window))
- {
- GdkSurfaceImplQuartz *impl;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- [impl->toplevel orderFront:impl->toplevel];
-
- clear_toplevel_order ();
- }
- else
- {
- GdkSurface *parent = window->parent;
-
- if (parent)
- {
- GdkSurfaceImplQuartz *impl;
-
- impl = (GdkSurfaceImplQuartz *)parent->impl;
-
- impl->sorted_children = g_list_remove (impl->sorted_children, window);
- impl->sorted_children = g_list_prepend (impl->sorted_children, window);
- }
- }
-}
-
-static void
-gdk_surface_quartz_lower (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (WINDOW_IS_TOPLEVEL (window))
- {
- GdkSurfaceImplQuartz *impl;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- [impl->toplevel orderBack:impl->toplevel];
-
- clear_toplevel_order ();
- }
- else
- {
- GdkSurface *parent = window->parent;
-
- if (parent)
- {
- GdkSurfaceImplQuartz *impl;
-
- impl = (GdkSurfaceImplQuartz *)parent->impl;
-
- impl->sorted_children = g_list_remove (impl->sorted_children, window);
- impl->sorted_children = g_list_append (impl->sorted_children, window);
- }
- }
-}
-
-static void
-gdk_surface_quartz_restack_toplevel (GdkSurface *window,
- GdkSurface *sibling,
- gboolean above)
-{
- GdkSurfaceImplQuartz *impl;
- gint sibling_num;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (sibling->impl);
- sibling_num = [impl->toplevel windowNumber];
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (above)
- [impl->toplevel orderWindow:NSWindowAbove relativeTo:sibling_num];
- else
- [impl->toplevel orderWindow:NSWindowBelow relativeTo:sibling_num];
-}
-
-static void
-gdk_surface_quartz_get_geometry (GdkSurface *window,
- gint *x,
- gint *y,
- gint *width,
- gint *height)
-{
- GdkSurfaceImplQuartz *impl;
- NSRect ns_rect;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- if (window == _gdk_root)
- {
- if (x)
- *x = 0;
- if (y)
- *y = 0;
-
- if (width)
- *width = window->width;
- if (height)
- *height = window->height;
- }
- else if (WINDOW_IS_TOPLEVEL (window))
- {
- ns_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
-
- /* This doesn't work exactly as in X. There doesn't seem to be a
- * way to get the coords relative to the parent window (usually
- * the window frame), but that seems useless except for
- * borderless windows where it's relative to the root window. So
- * we return (0, 0) (should be something like (0, 22)) for
- * windows with borders and the root relative coordinates
- * otherwise.
- */
- if ([impl->toplevel styleMask] == NSBorderlessWindowMask)
- {
- _gdk_quartz_surface_xy_to_gdk_xy (ns_rect.origin.x,
- ns_rect.origin.y + ns_rect.size.height,
- x, y);
- }
- else
- {
- if (x)
- *x = 0;
- if (y)
- *y = 0;
- }
-
- if (width)
- *width = ns_rect.size.width;
- if (height)
- *height = ns_rect.size.height;
- }
- else
- {
- ns_rect = [impl->view frame];
-
- if (x)
- *x = ns_rect.origin.x;
- if (y)
- *y = ns_rect.origin.y;
- if (width)
- *width = ns_rect.size.width;
- if (height)
- *height = ns_rect.size.height;
- }
-}
-
-static void
-gdk_surface_quartz_get_root_coords (GdkSurface *window,
- gint x,
- gint y,
- gint *root_x,
- gint *root_y)
-{
- int tmp_x = 0, tmp_y = 0;
- GdkSurface *toplevel;
- NSRect content_rect;
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window))
- {
- if (root_x)
- *root_x = 0;
- if (root_y)
- *root_y = 0;
-
- return;
- }
-
- if (window == _gdk_root)
- {
- if (root_x)
- *root_x = x;
- if (root_y)
- *root_y = y;
-
- return;
- }
-
- toplevel = gdk_surface_get_toplevel (window);
- impl = GDK_SURFACE_IMPL_QUARTZ (toplevel->impl);
-
- content_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
-
- _gdk_quartz_surface_xy_to_gdk_xy (content_rect.origin.x,
- content_rect.origin.y + content_rect.size.height,
- &tmp_x, &tmp_y);
-
- tmp_x += x;
- tmp_y += y;
-
- while (window != toplevel)
- {
- if (_gdk_surface_has_impl ((GdkSurface *)window))
- {
- tmp_x += window->x;
- tmp_y += window->y;
- }
-
- window = window->parent;
- }
-
- if (root_x)
- *root_x = tmp_x;
- if (root_y)
- *root_y = tmp_y;
-}
-
-/* Returns coordinates relative to the passed in window. */
-static GdkSurface *
-gdk_surface_quartz_get_device_state_helper (GdkSurface *window,
- GdkDevice *device,
- gdouble *x,
- gdouble *y,
- GdkModifierType *mask)
-{
- NSPoint point;
- gint x_tmp, y_tmp;
- GdkSurface *toplevel;
- GdkSurface *found_window;
-
- g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), NULL);
-
- if (GDK_SURFACE_DESTROYED (window))
- {
- *x = 0;
- *y = 0;
- *mask = 0;
- return NULL;
- }
-
- toplevel = gdk_surface_get_toplevel (window);
-
- *mask = _gdk_quartz_events_get_current_keyboard_modifiers () |
- _gdk_quartz_events_get_current_mouse_modifiers ();
-
- /* Get the y coordinate, needs to be flipped. */
- if (window == _gdk_root)
- {
- point = [NSEvent mouseLocation];
- _gdk_quartz_surface_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
- }
- else
- {
- GdkSurfaceImplQuartz *impl;
- NSWindow *nswindow;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (toplevel->impl);
- nswindow = impl->toplevel;
-
- point = [nswindow mouseLocationOutsideOfEventStream];
-
- x_tmp = point.x;
- y_tmp = toplevel->height - point.y;
-
- window = (GdkSurface *)toplevel;
- }
-
- found_window = _gdk_quartz_surface_find_child (window, x_tmp, y_tmp,
- FALSE);
-
- /* We never return the root window. */
- if (found_window == _gdk_root)
- found_window = NULL;
-
- *x = x_tmp;
- *y = y_tmp;
-
- return found_window;
-}
-
-static gboolean
-gdk_surface_quartz_get_device_state (GdkSurface *window,
- GdkDevice *device,
- gdouble *x,
- gdouble *y,
- GdkModifierType *mask)
-{
- return gdk_surface_quartz_get_device_state_helper (window,
- device,
- x, y, mask) != NULL;
-}
-
-static GdkEventMask
-gdk_surface_quartz_get_events (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return 0;
- else
- return window->event_mask;
-}
-
-static void
-gdk_surface_quartz_set_events (GdkSurface *window,
- GdkEventMask event_mask)
-{
- /* The mask is set in the common code. */
-}
-
-static void
-gdk_quartz_surface_set_urgency_hint (GdkSurface *window,
- gboolean urgent)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_set_geometry_hints (GdkSurface *window,
- const GdkGeometry *geometry,
- GdkSurfaceHints geom_mask)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_return_if_fail (geometry != NULL);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- if (!impl->toplevel)
- return;
-
- if (geom_mask & GDK_HINT_POS)
- {
- /* FIXME: Implement */
- }
-
- if (geom_mask & GDK_HINT_USER_POS)
- {
- /* FIXME: Implement */
- }
-
- if (geom_mask & GDK_HINT_USER_SIZE)
- {
- /* FIXME: Implement */
- }
-
- if (geom_mask & GDK_HINT_MIN_SIZE)
- {
- NSSize size;
-
- size.width = geometry->min_width;
- size.height = geometry->min_height;
-
- [impl->toplevel setContentMinSize:size];
- }
-
- if (geom_mask & GDK_HINT_MAX_SIZE)
- {
- NSSize size;
-
- size.width = geometry->max_width;
- size.height = geometry->max_height;
-
- [impl->toplevel setContentMaxSize:size];
- }
-
- if (geom_mask & GDK_HINT_BASE_SIZE)
- {
- /* FIXME: Implement */
- }
-
- if (geom_mask & GDK_HINT_RESIZE_INC)
- {
- NSSize size;
-
- size.width = geometry->width_inc;
- size.height = geometry->height_inc;
-
- [impl->toplevel setContentResizeIncrements:size];
- }
-
- if (geom_mask & GDK_HINT_ASPECT)
- {
- NSSize size;
-
- if (geometry->min_aspect != geometry->max_aspect)
- {
- g_warning ("Only equal minimum and maximum aspect ratios are supported on Mac OS. Using minimum aspect ratio...");
- }
-
- size.width = geometry->min_aspect;
- size.height = 1.0;
-
- [impl->toplevel setContentAspectRatio:size];
- }
-
- if (geom_mask & GDK_HINT_WIN_GRAVITY)
- {
- /* FIXME: Implement */
- }
-}
-
-static void
-gdk_quartz_surface_set_title (GdkSurface *window,
- const gchar *title)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_return_if_fail (title != NULL);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (impl->toplevel)
- {
- GDK_QUARTZ_ALLOC_POOL;
- [impl->toplevel setTitle:[NSString stringWithUTF8String:title]];
- GDK_QUARTZ_RELEASE_POOL;
- }
-}
-
-static void
-gdk_quartz_surface_set_role (GdkSurface *window,
- const gchar *role)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- WINDOW_IS_TOPLEVEL (window))
- return;
-
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_set_startup_id (GdkSurface *window,
- const gchar *startup_id)
-{
- /* FIXME: Implement? */
-}
-
-static void
-gdk_quartz_surface_set_transient_for (GdkSurface *window,
- GdkSurface *parent)
-{
- GdkSurfaceImplQuartz *window_impl;
- GdkSurfaceImplQuartz *parent_impl;
-
- if (GDK_SURFACE_DESTROYED (window) || GDK_SURFACE_DESTROYED (parent) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- window_impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- if (!window_impl->toplevel)
- return;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- if (window_impl->transient_for)
- {
- _gdk_quartz_surface_detach_from_parent (window);
-
- g_object_unref (window_impl->transient_for);
- window_impl->transient_for = NULL;
- }
-
- parent_impl = GDK_SURFACE_IMPL_QUARTZ (parent->impl);
- if (parent_impl->toplevel)
- {
- /* We save the parent because it needs to be unset/reset when
- * hiding and showing the window.
- */
-
- /* We don't set transients for tooltips, they are already
- * handled by the window level being the top one. If we do, then
- * the parent window will be brought to the top just because the
- * tooltip is, which is not what we want.
- */
- if (gdk_surface_get_type_hint (window) != GDK_SURFACE_TYPE_HINT_TOOLTIP)
- {
- window_impl->transient_for = g_object_ref (parent);
-
- /* We only add the window if it is shown, otherwise it will
- * be shown unconditionally here. If it is not shown, the
- * window will be added in show() instead.
- */
- if (!(window->state & GDK_SURFACE_STATE_WITHDRAWN))
- _gdk_quartz_surface_attach_to_parent (window);
- }
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-static void
-gdk_surface_quartz_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape,
- gint x,
- gint y)
-{
- /* FIXME: Implement */
-}
-
-static void
-gdk_surface_quartz_input_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_set_accept_focus (GdkSurface *window,
- gboolean accept_focus)
-{
- window->accept_focus = accept_focus != FALSE;
-}
-
-static void
-gdk_quartz_surface_set_focus_on_map (GdkSurface *window,
- gboolean focus_on_map)
-{
- window->focus_on_map = focus_on_map != FALSE;
-}
-
-static void
-gdk_quartz_surface_set_icon_name (GdkSurface *window,
- const gchar *name)
-{
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_focus (GdkSurface *window,
- guint32 timestamp)
-{
- GdkSurfaceImplQuartz *impl;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- if (window->accept_focus && window->window_type != GDK_SURFACE_TEMP)
- {
- GDK_QUARTZ_ALLOC_POOL;
- [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
- clear_toplevel_order ();
- GDK_QUARTZ_RELEASE_POOL;
- }
-}
-
-static gint
-window_type_hint_to_level (GdkSurfaceTypeHint hint)
-{
- /* the order in this switch statement corresponds to the actual
- * stacking order: the first group is top, the last group is bottom
- */
- switch (hint)
- {
- case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
- case GDK_SURFACE_TYPE_HINT_COMBO:
- case GDK_SURFACE_TYPE_HINT_DND:
- case GDK_SURFACE_TYPE_HINT_TOOLTIP:
- return NSPopUpMenuWindowLevel;
-
- case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
- case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
- return NSStatusWindowLevel;
-
- case GDK_SURFACE_TYPE_HINT_MENU: /* Torn-off menu */
- case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
- return NSTornOffMenuWindowLevel;
-
- case GDK_SURFACE_TYPE_HINT_DOCK:
- return NSFloatingWindowLevel; /* NSDockWindowLevel is deprecated, and not replaced */
-
- case GDK_SURFACE_TYPE_HINT_UTILITY:
- case GDK_SURFACE_TYPE_HINT_DIALOG: /* Dialog window */
- case GDK_SURFACE_TYPE_HINT_NORMAL: /* Normal toplevel window */
- case GDK_SURFACE_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
- return NSNormalWindowLevel;
-
- case GDK_SURFACE_TYPE_HINT_DESKTOP:
- return kCGDesktopWindowLevelKey; /* doesn't map to any real Cocoa model */
-
- default:
- break;
- }
-
- return NSNormalWindowLevel;
-}
-
-static gboolean
-window_type_hint_to_shadow (GdkSurfaceTypeHint hint)
-{
- switch (hint)
- {
- case GDK_SURFACE_TYPE_HINT_NORMAL: /* Normal toplevel window */
- case GDK_SURFACE_TYPE_HINT_DIALOG: /* Dialog window */
- case GDK_SURFACE_TYPE_HINT_DOCK:
- case GDK_SURFACE_TYPE_HINT_UTILITY:
- case GDK_SURFACE_TYPE_HINT_MENU: /* Torn-off menu */
- case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
- case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
- case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
- case GDK_SURFACE_TYPE_HINT_COMBO:
- case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
- case GDK_SURFACE_TYPE_HINT_TOOLTIP:
- return TRUE;
-
- case GDK_SURFACE_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
- case GDK_SURFACE_TYPE_HINT_DESKTOP: /* N/A */
- case GDK_SURFACE_TYPE_HINT_DND:
- break;
-
- default:
- break;
- }
-
- return FALSE;
-}
-
-static gboolean
-window_type_hint_to_hides_on_deactivate (GdkSurfaceTypeHint hint)
-{
- switch (hint)
- {
- case GDK_SURFACE_TYPE_HINT_UTILITY:
- case GDK_SURFACE_TYPE_HINT_MENU: /* Torn-off menu */
- case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
- case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
- case GDK_SURFACE_TYPE_HINT_TOOLTIP:
- return TRUE;
-
- default:
- break;
- }
-
- return FALSE;
-}
-
-static void
-_gdk_quartz_surface_update_has_shadow (GdkSurfaceImplQuartz *impl)
-{
- gboolean has_shadow;
-
- /* In case there is any shadow set we have to turn off the
- * NSWindow setHasShadow as the system drawn ones wont match our
- * window boundary anymore */
- has_shadow = (window_type_hint_to_shadow (impl->type_hint) && !impl->shadow_max);
-
- [impl->toplevel setHasShadow: has_shadow];
-}
-
-static void
-gdk_quartz_surface_set_type_hint (GdkSurface *window,
- GdkSurfaceTypeHint hint)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- impl->type_hint = hint;
-
- /* Match the documentation, only do something if we're not mapped yet. */
- if (GDK_SURFACE_IS_MAPPED (window))
- return;
-
- _gdk_quartz_surface_update_has_shadow (impl);
- [impl->toplevel setLevel: window_type_hint_to_level (hint)];
- [impl->toplevel setHidesOnDeactivate: window_type_hint_to_hides_on_deactivate (hint)];
-}
-
-static GdkSurfaceTypeHint
-gdk_quartz_surface_get_type_hint (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return GDK_SURFACE_TYPE_HINT_NORMAL;
-
- return GDK_SURFACE_IMPL_QUARTZ (window->impl)->type_hint;
-}
-
-static void
-gdk_quartz_surface_set_modal_hint (GdkSurface *window,
- gboolean modal)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_set_skip_taskbar_hint (GdkSurface *window,
- gboolean skips_taskbar)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_set_skip_pager_hint (GdkSurface *window,
- gboolean skips_pager)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_begin_resize_drag (GdkSurface *window,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (!impl->toplevel)
- {
- g_warning ("Can't call gdk_surface_begin_resize_drag on non-toplevel window");
- return;
- }
-
- [(GdkQuartzNSWindow *)impl->toplevel beginManualResize:edge];
-}
-
-static void
-gdk_quartz_surface_begin_move_drag (GdkSurface *window,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (!impl->toplevel)
- {
- g_warning ("Can't call gdk_surface_begin_move_drag on non-toplevel window");
- return;
- }
-
- [(GdkQuartzNSWindow *)impl->toplevel beginManualMove];
-}
-
-static void
-gdk_quartz_surface_set_icon_list (GdkSurface *window,
- GList *surfaces)
-{
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_get_frame_extents (GdkSurface *window,
- GdkRectangle *rect)
-{
- GdkSurface *toplevel;
- GdkSurfaceImplQuartz *impl;
- NSRect ns_rect;
-
- g_return_if_fail (rect != NULL);
-
-
- rect->x = 0;
- rect->y = 0;
- rect->width = 1;
- rect->height = 1;
-
- toplevel = gdk_surface_get_toplevel (window);
- impl = GDK_SURFACE_IMPL_QUARTZ (toplevel->impl);
-
- ns_rect = [impl->toplevel frame];
-
- _gdk_quartz_surface_xy_to_gdk_xy (ns_rect.origin.x,
- ns_rect.origin.y + ns_rect.size.height,
- &rect->x, &rect->y);
-
- rect->width = ns_rect.size.width;
- rect->height = ns_rect.size.height;
-}
-
-/* Fake protocol to make gcc think that it's OK to call setStyleMask
- even if it isn't. We check to make sure before actually calling
- it. */
-
-@protocol CanSetStyleMask
-- (void)setStyleMask:(int)mask;
-@end
-
-static void
-gdk_quartz_surface_set_decorations (GdkSurface *window,
- GdkWMDecoration decorations)
-{
- GdkSurfaceImplQuartz *impl;
- NSUInteger old_mask, new_mask;
- NSView *old_view;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (decorations == 0 || GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP ||
- impl->type_hint == GDK_SURFACE_TYPE_HINT_SPLASHSCREEN )
- {
- new_mask = NSBorderlessWindowMask;
- }
- else
- {
- /* FIXME: Honor other GDK_DECOR_* flags. */
- new_mask = (NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask | NSResizableWindowMask);
- }
-
- GDK_QUARTZ_ALLOC_POOL;
-
- old_mask = [impl->toplevel styleMask];
-
- if (old_mask != new_mask)
- {
- NSRect rect;
-
- old_view = [[impl->toplevel contentView] retain];
-
- rect = [impl->toplevel frame];
-
- /* Properly update the size of the window when the titlebar is
- * added or removed.
- */
- if (old_mask == NSBorderlessWindowMask &&
- new_mask != NSBorderlessWindowMask)
- {
- rect = [NSWindow frameRectForContentRect:rect styleMask:new_mask];
-
- }
- else if (old_mask != NSBorderlessWindowMask &&
- new_mask == NSBorderlessWindowMask)
- {
- rect = [NSWindow contentRectForFrameRect:rect styleMask:old_mask];
- }
-
- /* Note, before OS 10.6 there doesn't seem to be a way to change this
- * without recreating the toplevel. From 10.6 onward, a simple call to
- * setStyleMask takes care of most of this, except for ensuring that the
- * title is set.
- */
- if ([impl->toplevel respondsToSelector:@selector(setStyleMask:)])
- {
- NSString *title = [impl->toplevel title];
-
- [(id<CanSetStyleMask>)impl->toplevel setStyleMask:new_mask];
-
- /* It appears that unsetting and then resetting NSTitledWindowMask
- * does not reset the title in the title bar as might be expected.
- *
- * In theory we only need to set this if new_mask includes
- * NSTitledWindowMask. This behaved extremely oddly when
- * conditionalized upon that and since it has no side effects (i.e.
- * if NSTitledWindowMask is not requested, the title will not be
- * displayed) just do it unconditionally. We also must null check
- * 'title' before setting it to avoid crashing.
- */
- if (title)
- [impl->toplevel setTitle:title];
- }
- else
- {
- NSString *title = [impl->toplevel title];
- NSColor *bg = [impl->toplevel backgroundColor];
- NSScreen *screen = [impl->toplevel screen];
-
- /* Make sure the old window is closed, recall that releasedWhenClosed
- * is set on GdkQuartzSurfaces.
- */
- [impl->toplevel close];
-
- impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:rect
- styleMask:new_mask
- backing:NSBackingStoreBuffered
- defer:NO
- screen:screen];
- _gdk_quartz_surface_update_has_shadow (impl);
-
- [impl->toplevel setLevel: window_type_hint_to_level (impl->type_hint)];
- if (title)
- [impl->toplevel setTitle:title];
- [impl->toplevel setBackgroundColor:bg];
- [impl->toplevel setHidesOnDeactivate: window_type_hint_to_hides_on_deactivate (impl->type_hint)];
- [impl->toplevel setContentView:old_view];
- }
-
- if (new_mask == NSBorderlessWindowMask)
- {
- [impl->toplevel setContentSize:rect.size];
- [impl->toplevel setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
- }
- else
- [impl->toplevel setFrame:rect display:YES];
-
- /* Invalidate the window shadow for non-opaque views that have shadow
- * enabled, to get the shadow shape updated.
- */
- if (![old_view isOpaque] && [impl->toplevel hasShadow])
- [(GdkQuartzView*)old_view setNeedsInvalidateShadow:YES];
-
- [old_view release];
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-static gboolean
-gdk_quartz_surface_get_decorations (GdkSurface *window,
- GdkWMDecoration *decorations)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return FALSE;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (decorations)
- {
- /* Borderless is 0, so we can't check it as a bit being set. */
- if ([impl->toplevel styleMask] == NSBorderlessWindowMask)
- {
- *decorations = 0;
- }
- else
- {
- /* FIXME: Honor the other GDK_DECOR_* flags. */
- *decorations = GDK_DECOR_ALL;
- }
- }
-
- return TRUE;
-}
-
-static void
-gdk_quartz_surface_set_functions (GdkSurface *window,
- GdkWMFunction functions)
-{
- GdkSurfaceImplQuartz *impl;
- gboolean min, max, close;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (functions & GDK_FUNC_ALL)
- {
- min = !(functions & GDK_FUNC_MINIMIZE);
- max = !(functions & GDK_FUNC_MAXIMIZE);
- close = !(functions & GDK_FUNC_CLOSE);
- }
- else
- {
- min = (functions & GDK_FUNC_MINIMIZE);
- max = (functions & GDK_FUNC_MAXIMIZE);
- close = (functions & GDK_FUNC_CLOSE);
- }
-
- if (impl->toplevel)
- {
- NSUInteger mask = [impl->toplevel styleMask];
-
- if (min)
- mask = mask | NSMiniaturizableWindowMask;
- else
- mask = mask & ~NSMiniaturizableWindowMask;
-
- if (max)
- mask = mask | NSResizableWindowMask;
- else
- mask = mask & ~NSResizableWindowMask;
-
- if (close)
- mask = mask | NSClosableWindowMask;
- else
- mask = mask & ~NSClosableWindowMask;
-
- [impl->toplevel setStyleMask:mask];
- }
-}
-
-static void
-gdk_quartz_surface_stick (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-}
-
-static void
-gdk_quartz_surface_unstick (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-}
-
-static void
-gdk_quartz_surface_maximize (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
- gboolean maximized;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel && !maximized)
- [impl->toplevel zoom:nil];
-
- GDK_QUARTZ_RELEASE_POOL;
- }
-}
-
-static void
-gdk_quartz_surface_unmaximize (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
- gboolean maximized;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel && maximized)
- [impl->toplevel zoom:nil];
-
- GDK_QUARTZ_RELEASE_POOL;
- }
-}
-
-static void
-gdk_quartz_surface_iconify (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel)
- [impl->toplevel miniaturize:nil];
-
- GDK_QUARTZ_RELEASE_POOL;
- }
- else
- {
- gdk_synthesize_window_state (window,
- 0,
- GDK_SURFACE_STATE_ICONIFIED);
- }
-}
-
-static void
-gdk_quartz_surface_deiconify (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel)
- [impl->toplevel deminiaturize:nil];
-
- GDK_QUARTZ_RELEASE_POOL;
- }
- else
- {
- gdk_synthesize_window_state (window,
- GDK_SURFACE_STATE_ICONIFIED,
- 0);
- }
-}
-
-#ifdef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
-
-static gboolean
-window_is_fullscreen (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- return ([impl->toplevel styleMask] & NSFullScreenWindowMask) != 0;
-}
-
-static void
-gdk_quartz_surface_fullscreen (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (!window_is_fullscreen (window))
- [impl->toplevel toggleFullScreen:nil];
-}
-
-static void
-gdk_quartz_surface_unfullscreen (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (window_is_fullscreen (window))
- [impl->toplevel toggleFullScreen:nil];
-}
-
-void
-_gdk_quartz_surface_update_fullscreen_state (GdkSurface *window)
-{
- gboolean is_fullscreen;
- gboolean was_fullscreen;
-
- is_fullscreen = window_is_fullscreen (window);
- was_fullscreen = (gdk_surface_get_state (window) & GDK_SURFACE_STATE_FULLSCREEN) != 0;
-
- if (is_fullscreen != was_fullscreen)
- {
- if (is_fullscreen)
- gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
- else
- gdk_synthesize_window_state (window, GDK_SURFACE_STATE_FULLSCREEN, 0);
- }
-}
-
-#else
-
-static FullscreenSavedGeometry *
-get_fullscreen_geometry (GdkSurface *window)
-{
- return g_object_get_data (G_OBJECT (window), FULLSCREEN_DATA);
-}
-
-static void
-gdk_quartz_surface_fullscreen (GdkSurface *window)
-{
- FullscreenSavedGeometry *geometry;
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- NSRect frame;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- geometry = get_fullscreen_geometry (window);
- if (!geometry)
- {
- geometry = g_new (FullscreenSavedGeometry, 1);
-
- geometry->x = window->x;
- geometry->y = window->y;
- geometry->width = window->width;
- geometry->height = window->height;
-
- if (!gdk_surface_get_decorations (window, &geometry->decor))
- geometry->decor = GDK_DECOR_ALL;
-
- g_object_set_data_full (G_OBJECT (window),
- FULLSCREEN_DATA, geometry,
- g_free);
-
- gdk_surface_set_decorations (window, 0);
-
- frame = [[impl->toplevel screen] frame];
- move_resize_window_internal (window,
- 0, 0,
- frame.size.width, frame.size.height);
- [impl->toplevel setContentSize:frame.size];
- [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
-
- clear_toplevel_order ();
- }
-
- SetSystemUIMode (kUIModeAllHidden, kUIOptionAutoShowMenuBar);
-
- gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
-}
-
-static void
-gdk_quartz_surface_unfullscreen (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- FullscreenSavedGeometry *geometry;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- geometry = get_fullscreen_geometry (window);
- if (geometry)
- {
- SetSystemUIMode (kUIModeNormal, 0);
-
- move_resize_window_internal (window,
- geometry->x,
- geometry->y,
- geometry->width,
- geometry->height);
-
- gdk_surface_set_decorations (window, geometry->decor);
-
- g_object_set_data (G_OBJECT (window), FULLSCREEN_DATA, NULL);
-
- [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
- clear_toplevel_order ();
-
- gdk_synthesize_window_state (window, GDK_SURFACE_STATE_FULLSCREEN, 0);
- }
-}
-
-#endif
-
-static void
-gdk_quartz_surface_set_keep_above (GdkSurface *window,
- gboolean setting)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- gint level;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- level = window_type_hint_to_level (gdk_surface_get_type_hint (window));
-
- /* Adjust normal window level by one if necessary. */
- [impl->toplevel setLevel: level + (setting ? 1 : 0)];
-}
-
-static void
-gdk_quartz_surface_set_keep_below (GdkSurface *window,
- gboolean setting)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- gint level;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- level = window_type_hint_to_level (gdk_surface_get_type_hint (window));
-
- /* Adjust normal window level by one if necessary. */
- [impl->toplevel setLevel: level - (setting ? 1 : 0)];
-}
-
-static GdkSurface *
-gdk_quartz_surface_get_group (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD, NULL);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return NULL;
-
- /* FIXME: Implement */
-
- return NULL;
-}
-
-static void
-gdk_quartz_surface_set_group (GdkSurface *window,
- GdkSurface *leader)
-{
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_destroy_notify (GdkSurface *window)
-{
- check_grab_destroy (window);
-}
-
-static void
-gdk_quartz_surface_set_opacity (GdkSurface *window,
- gdouble opacity)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- if (opacity < 0)
- opacity = 0;
- else if (opacity > 1)
- opacity = 1;
-
- [impl->toplevel setAlphaValue: opacity];
-}
-
-static void
-gdk_quartz_surface_set_shadow_width (GdkSurface *window,
- gint left,
- gint right,
- gint top,
- gint bottom)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (WINDOW_IS_TOPLEVEL (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl->shadow_top = top;
- impl->shadow_max = MAX (MAX (left, right), MAX (top, bottom));
- _gdk_quartz_surface_update_has_shadow (impl);
-}
-
-/* Protocol to build cleanly for OSX < 10.7 */
-@protocol ScaleFactor
-- (CGFloat) backingScaleFactor;
-@end
-
-static gint
-gdk_quartz_surface_get_scale_factor (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window))
- return 1;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (impl->toplevel != NULL && gdk_quartz_osx_version() >= GDK_OSX_LION)
- return [(id <ScaleFactor>) impl->toplevel backingScaleFactor];
-
- return 1;
-}
-
-static void
-gdk_surface_impl_quartz_class_init (GdkSurfaceImplQuartzClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_CLASS (klass);
- GdkSurfaceImplQuartzClass *impl_quartz_class = GDK_SURFACE_IMPL_QUARTZ_CLASS (klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- object_class->finalize = gdk_surface_impl_quartz_finalize;
-
- impl_class->ref_cairo_surface = gdk_quartz_ref_cairo_surface;
- impl_class->show = gdk_surface_quartz_show;
- impl_class->hide = gdk_surface_quartz_hide;
- impl_class->withdraw = gdk_surface_quartz_withdraw;
- impl_class->set_events = gdk_surface_quartz_set_events;
- impl_class->get_events = gdk_surface_quartz_get_events;
- impl_class->raise = gdk_surface_quartz_raise;
- impl_class->lower = gdk_surface_quartz_lower;
- impl_class->restack_toplevel = gdk_surface_quartz_restack_toplevel;
- impl_class->move_resize = gdk_surface_quartz_move_resize;
- impl_class->get_geometry = gdk_surface_quartz_get_geometry;
- impl_class->get_root_coords = gdk_surface_quartz_get_root_coords;
- impl_class->get_device_state = gdk_surface_quartz_get_device_state;
- impl_class->shape_combine_region = gdk_surface_quartz_shape_combine_region;
- impl_class->input_shape_combine_region = gdk_surface_quartz_input_shape_combine_region;
- impl_class->destroy = gdk_quartz_surface_destroy;
- impl_class->begin_paint = gdk_surface_impl_quartz_begin_paint;
- impl_class->get_scale_factor = gdk_quartz_surface_get_scale_factor;
-
- impl_class->focus = gdk_quartz_surface_focus;
- impl_class->set_type_hint = gdk_quartz_surface_set_type_hint;
- impl_class->get_type_hint = gdk_quartz_surface_get_type_hint;
- impl_class->set_modal_hint = gdk_quartz_surface_set_modal_hint;
- impl_class->set_skip_taskbar_hint = gdk_quartz_surface_set_skip_taskbar_hint;
- impl_class->set_skip_pager_hint = gdk_quartz_surface_set_skip_pager_hint;
- impl_class->set_urgency_hint = gdk_quartz_surface_set_urgency_hint;
- impl_class->set_geometry_hints = gdk_quartz_surface_set_geometry_hints;
- impl_class->set_title = gdk_quartz_surface_set_title;
- impl_class->set_role = gdk_quartz_surface_set_role;
- impl_class->set_startup_id = gdk_quartz_surface_set_startup_id;
- impl_class->set_transient_for = gdk_quartz_surface_set_transient_for;
- impl_class->get_frame_extents = gdk_quartz_surface_get_frame_extents;
- impl_class->set_accept_focus = gdk_quartz_surface_set_accept_focus;
- impl_class->set_focus_on_map = gdk_quartz_surface_set_focus_on_map;
- impl_class->set_icon_list = gdk_quartz_surface_set_icon_list;
- impl_class->set_icon_name = gdk_quartz_surface_set_icon_name;
- impl_class->iconify = gdk_quartz_surface_iconify;
- impl_class->deiconify = gdk_quartz_surface_deiconify;
- impl_class->stick = gdk_quartz_surface_stick;
- impl_class->unstick = gdk_quartz_surface_unstick;
- impl_class->maximize = gdk_quartz_surface_maximize;
- impl_class->unmaximize = gdk_quartz_surface_unmaximize;
- impl_class->fullscreen = gdk_quartz_surface_fullscreen;
- impl_class->unfullscreen = gdk_quartz_surface_unfullscreen;
- impl_class->set_keep_above = gdk_quartz_surface_set_keep_above;
- impl_class->set_keep_below = gdk_quartz_surface_set_keep_below;
- impl_class->get_group = gdk_quartz_surface_get_group;
- impl_class->set_group = gdk_quartz_surface_set_group;
- impl_class->set_decorations = gdk_quartz_surface_set_decorations;
- impl_class->get_decorations = gdk_quartz_surface_get_decorations;
- impl_class->set_functions = gdk_quartz_surface_set_functions;
- impl_class->set_functions = gdk_quartz_surface_set_functions;
- impl_class->begin_resize_drag = gdk_quartz_surface_begin_resize_drag;
- impl_class->begin_move_drag = gdk_quartz_surface_begin_move_drag;
- impl_class->set_opacity = gdk_quartz_surface_set_opacity;
- impl_class->set_shadow_width = gdk_quartz_surface_set_shadow_width;
- impl_class->destroy_notify = gdk_quartz_surface_destroy_notify;
- impl_class->register_dnd = _gdk_quartz_surface_register_dnd;
- impl_class->drag_begin = _gdk_quartz_surface_drag_begin;
- impl_class->process_updates_recurse = _gdk_quartz_surface_process_updates_recurse;
-
- impl_class->create_gl_context = gdk_quartz_surface_create_gl_context;
-
- impl_quartz_class->get_context = gdk_surface_impl_quartz_get_context;
- impl_quartz_class->release_context = gdk_surface_impl_quartz_release_context;
-}
-
-GType
-_gdk_surface_impl_quartz_get_type (void)
-{
- static GType object_type = 0;
-
- if (!object_type)
- {
- const GTypeInfo object_info =
- {
- sizeof (GdkSurfaceImplQuartzClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gdk_surface_impl_quartz_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GdkSurfaceImplQuartz),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gdk_surface_impl_quartz_init,
- };
-
- object_type = g_type_register_static (GDK_TYPE_SURFACE_IMPL,
- "GdkSurfaceImplQuartz",
- &object_info, 0);
- }
-
- return object_type;
-}
-
-CGContextRef
-gdk_quartz_surface_get_context (GdkSurfaceImplQuartz *window,
- gboolean antialias)
-{
- if (!GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->get_context)
- {
- g_warning ("%s doesn't implement GdkSurfaceImplQuartzClass::get_context()",
- G_OBJECT_TYPE_NAME (window));
- return NULL;
- }
-
- return GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->get_context (window, antialias);
-}
-
-void
-gdk_quartz_surface_release_context (GdkSurfaceImplQuartz *window,
- CGContextRef cg_context)
-{
- if (!GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->release_context)
- {
- g_warning ("%s doesn't implement GdkSurfaceImplQuartzClass::release_context()",
- G_OBJECT_TYPE_NAME (window));
- return;
- }
-
- GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->release_context (window, cg_context);
-}
-
-
-
-static CGContextRef
-gdk_root_window_impl_quartz_get_context (GdkSurfaceImplQuartz *window,
- gboolean antialias)
-{
- CGColorSpaceRef colorspace;
- CGContextRef cg_context;
- GdkSurfaceImplQuartz *window_impl = GDK_SURFACE_IMPL_QUARTZ (window);
-
- if (GDK_SURFACE_DESTROYED (window_impl->wrapper))
- return NULL;
-
- /* We do not have the notion of a root window on OS X. We fake this
- * by creating a 1x1 bitmap and return a context to that.
- */
- colorspace = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
- cg_context = CGBitmapContextCreate (NULL,
- 1, 1, 8, 4, colorspace,
- kCGImageAlphaPremultipliedLast);
- CGColorSpaceRelease (colorspace);
-
- return cg_context;
-}
-
-static void
-gdk_root_window_impl_quartz_release_context (GdkSurfaceImplQuartz *window,
- CGContextRef cg_context)
-{
- CGContextRelease (cg_context);
-}
-
-static void
-gdk_root_window_impl_quartz_class_init (GdkRootWindowImplQuartzClass *klass)
-{
- GdkSurfaceImplQuartzClass *window_quartz_class = GDK_SURFACE_IMPL_QUARTZ_CLASS (klass);
-
- root_window_parent_class = g_type_class_peek_parent (klass);
-
- window_quartz_class->get_context = gdk_root_window_impl_quartz_get_context;
- window_quartz_class->release_context = gdk_root_window_impl_quartz_release_context;
-}
-
-static void
-gdk_root_window_impl_quartz_init (GdkRootWindowImplQuartz *impl)
-{
-}
-
-GType
-_gdk_root_window_impl_quartz_get_type (void)
-{
- static GType object_type = 0;
-
- if (!object_type)
- {
- const GTypeInfo object_info =
- {
- sizeof (GdkRootWindowImplQuartzClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gdk_root_window_impl_quartz_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GdkRootWindowImplQuartz),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gdk_root_window_impl_quartz_init,
- };
-
- object_type = g_type_register_static (GDK_TYPE_SURFACE_IMPL_QUARTZ,
- "GdkRootWindowQuartz",
- &object_info, 0);
- }
-
- return object_type;
-}
-
-GList *
-get_toplevels (void)
-{
- update_toplevel_order ();
- return GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl)->sorted_children;
-}
+++ /dev/null
-/* gdkdrawable-quartz.h
- *
- * Copyright (C) 2005 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_SURFACE_QUARTZ_H__
-#define __GDK_SURFACE_QUARTZ_H__
-
-#import <gdk/quartz/GdkQuartzView.h>
-#import <gdk/quartz/GdkQuartzNSWindow.h>
-#include "gdk/gdkwindowimpl.h"
-
-G_BEGIN_DECLS
-
-/* Window implementation for Quartz
- */
-
-typedef struct _GdkSurfaceImplQuartz GdkSurfaceImplQuartz;
-typedef struct _GdkSurfaceImplQuartzClass GdkSurfaceImplQuartzClass;
-
-#define GDK_TYPE_SURFACE_IMPL_QUARTZ (_gdk_surface_impl_quartz_get_type ())
-#define GDK_SURFACE_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL_QUARTZ, GdkSurfaceImplQuartz))
-#define GDK_SURFACE_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL_QUARTZ, GdkSurfaceImplQuartzClass))
-#define GDK_IS_SURFACE_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL_QUARTZ))
-#define GDK_IS_SURFACE_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL_QUARTZ))
-#define GDK_SURFACE_IMPL_QUARTZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL_QUARTZ, GdkSurfaceImplQuartzClass))
-
-struct _GdkSurfaceImplQuartz
-{
- GdkSurfaceImpl parent_instance;
-
- GdkSurface *wrapper;
-
- NSWindow *toplevel;
- NSTrackingRectTag tracking_rect;
- GdkQuartzView *view;
-
- GdkSurfaceTypeHint type_hint;
-
- gint in_paint_rect_count;
-
- GdkSurface *transient_for;
-
- /* Sorted by z-order */
- GList *sorted_children;
-
- cairo_region_t *needs_display_region;
-
- cairo_surface_t *cairo_surface;
-
- gint shadow_top;
-
- gint shadow_max;
-};
-
-struct _GdkSurfaceImplQuartzClass
-{
- GdkSurfaceImplClass parent_class;
-
- CGContextRef (* get_context) (GdkSurfaceImplQuartz *window,
- gboolean antialias);
- void (* release_context) (GdkSurfaceImplQuartz *window,
- CGContextRef cg_context);
-};
-
-GType _gdk_surface_impl_quartz_get_type (void);
-
-CGContextRef gdk_quartz_surface_get_context (GdkSurfaceImplQuartz *window,
- gboolean antialias);
-void gdk_quartz_surface_release_context (GdkSurfaceImplQuartz *window,
- CGContextRef context);
-
-/* Root window implementation for Quartz
- */
-
-typedef struct _GdkRootWindowImplQuartz GdkRootWindowImplQuartz;
-typedef struct _GdkRootWindowImplQuartzClass GdkRootWindowImplQuartzClass;
-
-#define GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ (_gdk_root_window_impl_quartz_get_type ())
-#define GDK_ROOT_WINDOW_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ, GdkRootWindowImplQuartz))
-#define GDK_ROOT_WINDOW_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ, GdkRootWindowImplQuartzClass))
-#define GDK_IS_ROOT_WINDOW_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ))
-#define GDK_IS_ROOT_WINDOW_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ))
-#define GDK_ROOT_WINDOW_IMPL_QUARTZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_ROOT_WINDOW_IMPL_QUARTZ, GdkRootWindowImplQuartzClass))
-
-struct _GdkRootWindowImplQuartz
-{
- GdkSurfaceImplQuartz parent_instance;
-};
-
-struct _GdkRootWindowImplQuartzClass
-{
- GdkSurfaceImplQuartzClass parent_class;
-};
-
-GType _gdk_root_window_impl_quartz_get_type (void);
-
-GList *get_toplevels (void);
-
-G_END_DECLS
-
-#endif /* __GDK_SURFACE_QUARTZ_H__ */
'gdkscreen-quartz.c',
'gdkselection-quartz.c',
'gdkutils-quartz.c',
- 'gdkwindow-quartz.c',
+ 'gdksurface-quartz.c',
])
gdk_quartz_public_headers = files([
'gdkquartzkeys.h',
'gdkquartzscreen.h',
'gdkquartzutils.h',
- 'gdkquartzwindow.h',
+ 'gdkquartzsurface.h',
])
install_headers(gdk_quartz_public_headers, subdir: 'gtk-4.0/gdk/quartz/')
#include <errno.h>
#include <string.h>
-#include <gdk/gdkwindow.h>
+#include <gdk/gdksurface.h>
#include <gdk/gdktypes.h>
#include "gdkclipboard-wayland.h"
#include "gdkclipboardprivate.h"
#include <glib.h>
#include <gdk/gdkkeys.h>
-#include <gdk/gdkwindow.h>
+#include <gdk/gdksurface.h>
#include <gdk/gdkinternals.h>
#include <gdk/gdk.h> /* For gdk_get_program_class() */
#include "gdkwaylanddisplay.h"
#include "gdkwaylandglcontext.h"
-#include "gdkwaylandwindow.h"
+#include "gdkwaylandsurface.h"
#include "gdkprivate-wayland.h"
#include "gdkinternals.h"
#include "gdkglcontextprivate.h"
#include "gdkdisplayprivate.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkinternals.h"
#include <epoxy/egl.h>
--- /dev/null
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <netinet/in.h>
+#include <unistd.h>
+
+#include "gdk.h"
+#include "gdkwayland.h"
+
+#include "gdksurface.h"
+#include "gdksurfaceimpl.h"
+#include "gdkdisplay-wayland.h"
+#include "gdkglcontext-wayland.h"
+#include "gdkframeclockprivate.h"
+#include "gdkprivate-wayland.h"
+#include "gdkinternals.h"
+#include "gdkdeviceprivate.h"
+#include "gdkprivate-wayland.h"
+#include "gdkmonitor-wayland.h"
+#include <wayland/xdg-shell-unstable-v6-client-protocol.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+enum {
+ COMMITTED,
+
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+#define WINDOW_IS_TOPLEVEL(window) \
+ (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD)
+
+#define MAX_WL_BUFFER_SIZE (4083) /* 4096 minus header, string argument length and NUL byte */
+
+typedef struct _GdkWaylandSurface GdkWaylandSurface;
+typedef struct _GdkWaylandSurfaceClass GdkWaylandSurfaceClass;
+
+struct _GdkWaylandSurface
+{
+ GdkSurface parent;
+};
+
+struct _GdkWaylandSurfaceClass
+{
+ GdkSurfaceClass parent_class;
+};
+
+G_DEFINE_TYPE (GdkWaylandSurface, gdk_wayland_surface, GDK_TYPE_SURFACE)
+
+static void
+gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *wayland_surface_class)
+{
+}
+
+static void
+gdk_wayland_surface_init (GdkWaylandSurface *wayland_surface)
+{
+}
+
+#define GDK_TYPE_SURFACE_IMPL_WAYLAND (_gdk_surface_impl_wayland_get_type ())
+#define GDK_SURFACE_IMPL_WAYLAND(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL_WAYLAND, GdkSurfaceImplWayland))
+#define GDK_SURFACE_IMPL_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL_WAYLAND, GdkSurfaceImplWaylandClass))
+#define GDK_IS_SURFACE_IMPL_WAYLAND(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL_WAYLAND))
+#define GDK_IS_SURFACE_IMPL_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL_WAYLAND))
+#define GDK_SURFACE_IMPL_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL_WAYLAND, GdkSurfaceImplWaylandClass))
+
+typedef struct _GdkSurfaceImplWayland GdkSurfaceImplWayland;
+typedef struct _GdkSurfaceImplWaylandClass GdkSurfaceImplWaylandClass;
+
+typedef enum _PositionMethod
+{
+ POSITION_METHOD_NONE,
+ POSITION_METHOD_MOVE_RESIZE,
+ POSITION_METHOD_MOVE_TO_RECT
+} PositionMethod;
+
+struct _GdkSurfaceImplWayland
+{
+ GdkSurfaceImpl parent_instance;
+
+ GdkSurface *wrapper;
+
+ struct {
+ /* The wl_outputs that this window currently touches */
+ GSList *outputs;
+
+ struct wl_surface *wl_surface;
+ struct zxdg_surface_v6 *xdg_surface;
+ struct zxdg_toplevel_v6 *xdg_toplevel;
+ struct zxdg_popup_v6 *xdg_popup;
+ struct gtk_surface1 *gtk_surface;
+ struct wl_subsurface *wl_subsurface;
+ struct wl_egl_window *egl_window;
+ struct wl_egl_window *dummy_egl_window;
+ struct zxdg_exported_v1 *xdg_exported;
+ struct org_kde_kwin_server_decoration *server_decoration;
+ } display_server;
+
+ EGLSurface egl_surface;
+ EGLSurface dummy_egl_surface;
+
+ unsigned int initial_configure_received : 1;
+ unsigned int mapped : 1;
+ unsigned int use_custom_surface : 1;
+ unsigned int pending_buffer_attached : 1;
+ unsigned int pending_commit : 1;
+ unsigned int awaiting_frame : 1;
+ GdkSurfaceTypeHint hint;
+ GdkSurface *transient_for;
+ GdkSurface *popup_parent;
+ PositionMethod position_method;
+
+ cairo_surface_t *staging_cairo_surface;
+ cairo_surface_t *committed_cairo_surface;
+ cairo_surface_t *backfill_cairo_surface;
+
+ int pending_buffer_offset_x;
+ int pending_buffer_offset_y;
+
+ gchar *title;
+
+ struct {
+ gboolean was_set;
+
+ gchar *application_id;
+ gchar *app_menu_path;
+ gchar *menubar_path;
+ gchar *window_object_path;
+ gchar *application_object_path;
+ gchar *unique_bus_name;
+ } application;
+
+ GdkGeometry geometry_hints;
+ GdkSurfaceHints geometry_mask;
+
+ GdkSeat *grab_input_seat;
+
+ gint64 pending_frame_counter;
+ guint32 scale;
+
+ int margin_left;
+ int margin_right;
+ int margin_top;
+ int margin_bottom;
+ gboolean margin_dirty;
+
+ struct wl_output *initial_fullscreen_output;
+
+ cairo_region_t *opaque_region;
+ gboolean opaque_region_dirty;
+
+ cairo_region_t *input_region;
+ gboolean input_region_dirty;
+
+ cairo_region_t *staged_updates_region;
+
+ int saved_width;
+ int saved_height;
+
+ gulong parent_surface_committed_handler;
+
+ struct {
+ GdkRectangle rect;
+ GdkGravity rect_anchor;
+ GdkGravity window_anchor;
+ GdkAnchorHints anchor_hints;
+ gint rect_anchor_dx;
+ gint rect_anchor_dy;
+ } pending_move_to_rect;
+
+ struct {
+ int width;
+ int height;
+ GdkSurfaceState state;
+ } pending;
+
+ struct {
+ GdkWaylandSurfaceExported callback;
+ gpointer user_data;
+ GDestroyNotify destroy_func;
+ } exported;
+
+ struct zxdg_imported_v1 *imported_transient_for;
+ GHashTable *shortcuts_inhibitors;
+};
+
+struct _GdkSurfaceImplWaylandClass
+{
+ GdkSurfaceImplClass parent_class;
+};
+
+static void gdk_wayland_surface_maybe_configure (GdkSurface *window,
+ int width,
+ int height,
+ int scale);
+
+static void maybe_set_gtk_surface_dbus_properties (GdkSurface *window);
+static void maybe_set_gtk_surface_modal (GdkSurface *window);
+
+static void gdk_surface_request_transient_parent_commit (GdkSurface *window);
+
+static void gdk_wayland_surface_sync_margin (GdkSurface *window);
+static void gdk_wayland_surface_sync_input_region (GdkSurface *window);
+static void gdk_wayland_surface_sync_opaque_region (GdkSurface *window);
+
+static void unset_transient_for_exported (GdkSurface *window);
+
+static void calculate_moved_to_rect_result (GdkSurface *window,
+ int x,
+ int y,
+ int width,
+ int height,
+ GdkRectangle *flipped_rect,
+ GdkRectangle *final_rect,
+ gboolean *flipped_x,
+ gboolean *flipped_y);
+
+static gboolean gdk_wayland_surface_is_exported (GdkSurface *window);
+
+GType _gdk_surface_impl_wayland_get_type (void);
+
+G_DEFINE_TYPE (GdkSurfaceImplWayland, _gdk_surface_impl_wayland, GDK_TYPE_SURFACE_IMPL)
+
+static void
+_gdk_surface_impl_wayland_init (GdkSurfaceImplWayland *impl)
+{
+ impl->scale = 1;
+ impl->initial_fullscreen_output = NULL;
+ impl->saved_width = -1;
+ impl->saved_height = -1;
+}
+
+static void
+_gdk_wayland_screen_add_orphan_dialog (GdkSurface *window)
+{
+ GdkWaylandDisplay *display_wayland =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+
+ if (!g_list_find (display_wayland->orphan_dialogs, window))
+ display_wayland->orphan_dialogs =
+ g_list_prepend (display_wayland->orphan_dialogs, window);
+}
+
+static void
+drop_cairo_surfaces (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
+ g_clear_pointer (&impl->backfill_cairo_surface, cairo_surface_destroy);
+
+ /* We nullify this so if a buffer release comes in later, we won't
+ * try to reuse that buffer since it's no longer suitable
+ */
+ impl->committed_cairo_surface = NULL;
+}
+
+static void
+_gdk_wayland_surface_save_size (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (window->state & (GDK_SURFACE_STATE_FULLSCREEN | GDK_SURFACE_STATE_MAXIMIZED))
+ return;
+
+ impl->saved_width = window->width - impl->margin_left - impl->margin_right;
+ impl->saved_height = window->height - impl->margin_top - impl->margin_bottom;
+}
+
+static void
+_gdk_wayland_surface_clear_saved_size (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (window->state & (GDK_SURFACE_STATE_FULLSCREEN | GDK_SURFACE_STATE_MAXIMIZED))
+ return;
+
+ impl->saved_width = -1;
+ impl->saved_height = -1;
+}
+
+/*
+ * gdk_wayland_surface_update_size:
+ * @drawable: a #GdkDrawableImplWayland.
+ *
+ * Updates the state of the drawable (in particular the drawable's
+ * cairo surface) when its size has changed.
+ */
+static void
+gdk_wayland_surface_update_size (GdkSurface *window,
+ int32_t width,
+ int32_t height,
+ int scale)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkRectangle area;
+ cairo_region_t *region;
+
+ if ((window->width == width) &&
+ (window->height == height) &&
+ (impl->scale == scale))
+ return;
+
+ drop_cairo_surfaces (window);
+
+ window->width = width;
+ window->height = height;
+ impl->scale = scale;
+
+ if (impl->display_server.egl_window)
+ wl_egl_window_resize (impl->display_server.egl_window, width * scale, height * scale, 0, 0);
+ if (impl->display_server.wl_surface)
+ wl_surface_set_buffer_scale (impl->display_server.wl_surface, scale);
+
+ area.x = 0;
+ area.y = 0;
+ area.width = window->width;
+ area.height = window->height;
+
+ region = cairo_region_create_rectangle (&area);
+ _gdk_surface_invalidate_for_expose (window, region);
+ cairo_region_destroy (region);
+}
+
+static const gchar *
+get_default_title (void)
+{
+ const char *title;
+
+ title = g_get_application_name ();
+ if (!title)
+ title = g_get_prgname ();
+ if (!title)
+ title = "";
+
+ return title;
+}
+
+static void
+fill_presentation_time_from_frame_time (GdkFrameTimings *timings,
+ guint32 frame_time)
+{
+ /* The timestamp in a wayland frame is a msec time value that in some
+ * way reflects the time at which the server started drawing the frame.
+ * This is not useful from our perspective.
+ *
+ * However, for the DRM backend of Weston, on reasonably recent
+ * Linux, we know that the time is the
+ * clock_gettime (CLOCK_MONOTONIC) value at the vblank, and that
+ * backend starts drawing immediately after receiving the vblank
+ * notification. If we detect this, and make the assumption that the
+ * compositor will finish drawing before the next vblank, we can
+ * then determine the presentation time as the frame time we
+ * received plus one refresh interval.
+ *
+ * If a backend is using clock_gettime(CLOCK_MONOTONIC), but not
+ * picking values right at the vblank, then the presentation times
+ * we compute won't be accurate, but not really worse than then
+ * the alternative of not providing presentation times at all.
+ *
+ * The complexity here is dealing with the fact that we receive
+ * only the low 32 bits of the CLOCK_MONOTONIC value in milliseconds.
+ */
+ gint64 now_monotonic = g_get_monotonic_time ();
+ gint64 now_monotonic_msec = now_monotonic / 1000;
+ uint32_t now_monotonic_low = (uint32_t)now_monotonic_msec;
+
+ if (frame_time - now_monotonic_low < 1000 ||
+ frame_time - now_monotonic_low > (uint32_t)-1000)
+ {
+ /* Timestamp we received is within one second of the current time.
+ */
+ gint64 last_frame_time = now_monotonic + (gint64)1000 * (gint32)(frame_time - now_monotonic_low);
+ if ((gint32)now_monotonic_low < 0 && (gint32)frame_time > 0)
+ last_frame_time += (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
+ else if ((gint32)now_monotonic_low > 0 && (gint32)frame_time < 0)
+ last_frame_time -= (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
+
+ timings->presentation_time = last_frame_time + timings->refresh_interval;
+ }
+}
+
+static void
+read_back_cairo_surface (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ cairo_t *cr;
+ cairo_region_t *paint_region = NULL;
+
+ if (!impl->backfill_cairo_surface)
+ goto out;
+
+ paint_region = cairo_region_copy (window->clip_region);
+ cairo_region_subtract (paint_region, impl->staged_updates_region);
+
+ if (cairo_region_is_empty (paint_region))
+ goto out;
+
+ cr = cairo_create (impl->staging_cairo_surface);
+ cairo_set_source_surface (cr, impl->backfill_cairo_surface, 0, 0);
+ gdk_cairo_region (cr, paint_region);
+ cairo_clip (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+ cairo_surface_flush (impl->staging_cairo_surface);
+
+out:
+ g_clear_pointer (&paint_region, cairo_region_destroy);
+ g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
+ g_clear_pointer (&impl->backfill_cairo_surface, cairo_surface_destroy);
+}
+
+static void
+frame_callback (void *data,
+ struct wl_callback *callback,
+ uint32_t time)
+{
+ GdkSurface *window = data;
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkWaylandDisplay *display_wayland =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ GdkFrameClock *clock = gdk_surface_get_frame_clock (window);
+ GdkFrameTimings *timings;
+
+ GDK_DISPLAY_NOTE (GDK_DISPLAY (display_wayland), EVENTS, g_message ("frame %p", window));
+
+ wl_callback_destroy (callback);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (!impl->awaiting_frame)
+ return;
+
+ impl->awaiting_frame = FALSE;
+ _gdk_frame_clock_thaw (clock);
+
+ timings = gdk_frame_clock_get_timings (clock, impl->pending_frame_counter);
+ impl->pending_frame_counter = 0;
+
+ if (timings == NULL)
+ return;
+
+ timings->refresh_interval = 16667; /* default to 1/60th of a second */
+ if (impl->display_server.outputs)
+ {
+ /* We pick a random output out of the outputs that the window touches
+ * The rate here is in milli-hertz */
+ int refresh_rate =
+ gdk_wayland_display_get_output_refresh_rate (display_wayland,
+ impl->display_server.outputs->data);
+ if (refresh_rate != 0)
+ timings->refresh_interval = G_GINT64_CONSTANT(1000000000) / refresh_rate;
+ }
+
+ fill_presentation_time_from_frame_time (timings, time);
+
+ timings->complete = TRUE;
+
+#ifdef G_ENABLE_DEBUG
+ if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
+ _gdk_frame_clock_debug_print_timings (clock, timings);
+#endif
+}
+
+static const struct wl_callback_listener frame_listener = {
+ frame_callback
+};
+
+static void
+on_frame_clock_before_paint (GdkFrameClock *clock,
+ GdkSurface *window)
+{
+ GdkFrameTimings *timings = gdk_frame_clock_get_current_timings (clock);
+ gint64 presentation_time;
+ gint64 refresh_interval;
+
+ if (window->update_freeze_count > 0)
+ return;
+
+ gdk_frame_clock_get_refresh_info (clock,
+ timings->frame_time,
+ &refresh_interval, &presentation_time);
+
+ if (presentation_time != 0)
+ {
+ /* Assume the algorithm used by the DRM backend of Weston - it
+ * starts drawing at the next vblank after receiving the commit
+ * for this frame, and presentation occurs at the vblank
+ * after that.
+ */
+ timings->predicted_presentation_time = presentation_time + refresh_interval;
+ }
+ else
+ {
+ /* As above, but we don't actually know the phase of the vblank,
+ * so just assume that we're half way through a refresh cycle.
+ */
+ timings->predicted_presentation_time = timings->frame_time + refresh_interval / 2 + refresh_interval;
+ }
+}
+
+static void
+on_frame_clock_after_paint (GdkFrameClock *clock,
+ GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ struct wl_callback *callback;
+
+ if (!impl->pending_commit)
+ return;
+
+ if (window->update_freeze_count > 0)
+ return;
+
+ callback = wl_surface_frame (impl->display_server.wl_surface);
+ wl_callback_add_listener (callback, &frame_listener, window);
+ _gdk_frame_clock_freeze (clock);
+
+ /* Before we commit a new buffer, make sure we've backfilled
+ * undrawn parts from any old committed buffer
+ */
+ if (impl->pending_buffer_attached)
+ read_back_cairo_surface (window);
+
+ /* From this commit forward, we can't write to the buffer,
+ * it's "live". In the future, if we need to stage more changes
+ * we have to allocate a new staging buffer and draw to it instead.
+ *
+ * Our one saving grace is if the compositor releases the buffer
+ * before we need to stage any changes, then we can take it back and
+ * use it again.
+ */
+ wl_surface_commit (impl->display_server.wl_surface);
+
+ if (impl->pending_buffer_attached)
+ impl->committed_cairo_surface = g_steal_pointer (&impl->staging_cairo_surface);
+
+ impl->pending_buffer_attached = FALSE;
+ impl->pending_commit = FALSE;
+ impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock);
+ impl->awaiting_frame = TRUE;
+
+ g_signal_emit (impl, signals[COMMITTED], 0);
+}
+
+void
+gdk_wayland_surface_update_scale (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ guint32 scale;
+ GSList *l;
+ GList *children, *c;
+
+ if (display_wayland->compositor_version < WL_SURFACE_HAS_BUFFER_SCALE)
+ {
+ /* We can't set the scale on this surface */
+ return;
+ }
+
+ scale = 1;
+ for (l = impl->display_server.outputs; l != NULL; l = l->next)
+ {
+ guint32 output_scale = gdk_wayland_display_get_output_scale (display_wayland, l->data);
+ scale = MAX (scale, output_scale);
+ }
+
+ /* Notify app that scale changed */
+ gdk_wayland_surface_maybe_configure (window, window->width, window->height, scale);
+
+ children = gdk_surface_get_children (window);
+ for (c = children; c; c = c->next)
+ {
+ GdkSurface *child = c->data;
+ gdk_wayland_surface_update_scale (child);
+ }
+ g_list_free (children);
+}
+
+static void gdk_wayland_surface_create_surface (GdkSurface *window);
+
+void
+_gdk_wayland_display_create_window_impl (GdkDisplay *display,
+ GdkSurface *window,
+ GdkSurface *real_parent,
+ GdkEventMask event_mask,
+ GdkSurfaceAttr *attributes)
+{
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+ GdkSurfaceImplWayland *impl;
+ GdkFrameClock *frame_clock;
+
+ impl = g_object_new (GDK_TYPE_SURFACE_IMPL_WAYLAND, NULL);
+ window->impl = GDK_SURFACE_IMPL (impl);
+ impl->wrapper = GDK_SURFACE (window);
+ impl->shortcuts_inhibitors = g_hash_table_new (NULL, NULL);
+
+ if (window->width > 65535)
+ {
+ g_warning ("Native Windows wider than 65535 pixels are not supported");
+ window->width = 65535;
+ }
+ if (window->height > 65535)
+ {
+ g_warning ("Native Windows taller than 65535 pixels are not supported");
+ window->height = 65535;
+ }
+
+ g_object_ref (window);
+
+ /* More likely to be right than just assuming 1 */
+ if (display_wayland->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE &&
+ gdk_display_get_n_monitors (display) > 0)
+ impl->scale = gdk_monitor_get_scale_factor (gdk_display_get_monitor (display, 0));
+
+ impl->title = NULL;
+
+ switch (GDK_SURFACE_TYPE (window))
+ {
+ case GDK_SURFACE_TOPLEVEL:
+ case GDK_SURFACE_TEMP:
+ gdk_surface_set_title (window, get_default_title ());
+ break;
+
+ case GDK_SURFACE_CHILD:
+ default:
+ break;
+ }
+
+ if (real_parent == NULL)
+ display_wayland->toplevels = g_list_prepend (display_wayland->toplevels, window);
+
+ gdk_wayland_surface_create_surface (window);
+
+ frame_clock = gdk_surface_get_frame_clock (window);
+ g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), window);
+ g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), window);
+}
+
+static void
+gdk_wayland_surface_attach_image (GdkSurface *window)
+{
+ GdkWaylandDisplay *display;
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ g_assert (_gdk_wayland_is_shm_surface (impl->staging_cairo_surface));
+
+ /* Attach this new buffer to the surface */
+ wl_surface_attach (impl->display_server.wl_surface,
+ _gdk_wayland_shm_surface_get_wl_buffer (impl->staging_cairo_surface),
+ impl->pending_buffer_offset_x,
+ impl->pending_buffer_offset_y);
+ impl->pending_buffer_offset_x = 0;
+ impl->pending_buffer_offset_y = 0;
+
+ /* Only set the buffer scale if supported by the compositor */
+ display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ if (display->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE)
+ wl_surface_set_buffer_scale (impl->display_server.wl_surface, impl->scale);
+
+ impl->pending_buffer_attached = TRUE;
+ impl->pending_commit = TRUE;
+}
+
+static const cairo_user_data_key_t gdk_wayland_surface_cairo_key;
+
+static void
+buffer_release_callback (void *_data,
+ struct wl_buffer *wl_buffer)
+{
+ cairo_surface_t *cairo_surface = _data;
+ GdkSurfaceImplWayland *impl = cairo_surface_get_user_data (cairo_surface, &gdk_wayland_surface_cairo_key);
+
+ g_return_if_fail (GDK_IS_SURFACE_IMPL_WAYLAND (impl));
+
+ /* The released buffer isn't the latest committed one, we have no further
+ * use for it, so clean it up.
+ */
+ if (impl->committed_cairo_surface != cairo_surface)
+ {
+ /* If this fails, then the surface buffer got reused before it was
+ * released from the compositor
+ */
+ g_warn_if_fail (impl->staging_cairo_surface != cairo_surface);
+
+ cairo_surface_destroy (cairo_surface);
+ return;
+ }
+
+ if (impl->staged_updates_region != NULL)
+ {
+ /* If this fails, then we're tracking staged updates on a staging surface
+ * that doesn't exist.
+ */
+ g_warn_if_fail (impl->staging_cairo_surface != NULL);
+
+ /* If we've staged updates into a new buffer before the release for this
+ * buffer came in, then we can't reuse this buffer, so unref it. It may still
+ * be alive as a readback buffer though (via impl->backfill_cairo_surface).
+ *
+ * It's possible a staging surface was allocated but no updates were staged.
+ * If that happened, clean up that staging surface now, since the old commit
+ * buffer is available again, and reusing the old commit buffer for future
+ * updates will save having to do a read back later.
+ */
+ if (!cairo_region_is_empty (impl->staged_updates_region))
+ {
+ g_clear_pointer (&impl->committed_cairo_surface, cairo_surface_destroy);
+ return;
+ }
+ else
+ {
+ g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
+ g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
+ }
+ }
+
+ /* Release came in, we haven't done any interim updates, so we can just use
+ * the old committed buffer again.
+ */
+ impl->staging_cairo_surface = g_steal_pointer (&impl->committed_cairo_surface);
+}
+
+static const struct wl_buffer_listener buffer_listener = {
+ buffer_release_callback
+};
+
+static void
+gdk_wayland_surface_ensure_cairo_surface (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ /* If we are drawing using OpenGL then we only need a logical 1x1 surface. */
+ if (impl->display_server.egl_window)
+ {
+ if (impl->staging_cairo_surface &&
+ _gdk_wayland_is_shm_surface (impl->staging_cairo_surface))
+ g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
+
+ if (!impl->staging_cairo_surface)
+ {
+ impl->staging_cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ impl->scale,
+ impl->scale);
+ cairo_surface_set_device_scale (impl->staging_cairo_surface,
+ impl->scale, impl->scale);
+ }
+ }
+ else if (!impl->staging_cairo_surface)
+ {
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (impl->wrapper));
+ struct wl_buffer *buffer;
+
+ impl->staging_cairo_surface = _gdk_wayland_display_create_shm_surface (display_wayland,
+ impl->wrapper->width,
+ impl->wrapper->height,
+ impl->scale);
+ cairo_surface_set_user_data (impl->staging_cairo_surface,
+ &gdk_wayland_surface_cairo_key,
+ g_object_ref (impl),
+ (cairo_destroy_func_t)
+ g_object_unref);
+ buffer = _gdk_wayland_shm_surface_get_wl_buffer (impl->staging_cairo_surface);
+ wl_buffer_add_listener (buffer, &buffer_listener, impl->staging_cairo_surface);
+ }
+}
+
+/* The cairo surface returned here uses a memory segment that's shared
+ * with the display server. This is not a temporary buffer that gets
+ * copied to the display server, but the actual buffer the display server
+ * will ultimately end up sending to the GPU. At the time this happens
+ * impl->committed_cairo_surface gets set to impl->staging_cairo_surface, and
+ * impl->staging_cairo_surface gets nullified.
+ */
+static cairo_surface_t *
+gdk_wayland_surface_ref_cairo_surface (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (impl->wrapper))
+ return NULL;
+
+ gdk_wayland_surface_ensure_cairo_surface (window);
+
+ cairo_surface_reference (impl->staging_cairo_surface);
+
+ return impl->staging_cairo_surface;
+}
+
+static cairo_surface_t *
+gdk_wayland_surface_create_similar_image_surface (GdkSurface * window,
+ cairo_format_t format,
+ int width,
+ int height)
+{
+ return cairo_image_surface_create (format, width, height);
+}
+
+static gboolean
+gdk_surface_impl_wayland_begin_paint (GdkSurface *window)
+{
+ gdk_wayland_surface_ensure_cairo_surface (window);
+
+ return FALSE;
+}
+
+static void
+gdk_surface_impl_wayland_end_paint (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ cairo_rectangle_int_t rect;
+ int i, n;
+
+ if (impl->staging_cairo_surface &&
+ _gdk_wayland_is_shm_surface (impl->staging_cairo_surface) &&
+ !cairo_region_is_empty (window->current_paint.region))
+ {
+ gdk_wayland_surface_attach_image (window);
+
+ /* If there's a committed buffer pending, then track which
+ * updates are staged until the next frame, so we can back
+ * fill the unstaged parts of the staging buffer with the
+ * last frame.
+ */
+ if (impl->committed_cairo_surface != NULL)
+ {
+ if (impl->staged_updates_region == NULL)
+ {
+ impl->staged_updates_region = cairo_region_copy (window->current_paint.region);
+ impl->backfill_cairo_surface = cairo_surface_reference (impl->committed_cairo_surface);
+ }
+ else
+ {
+ cairo_region_union (impl->staged_updates_region, window->current_paint.region);
+ }
+ }
+
+ n = cairo_region_num_rectangles (window->current_paint.region);
+ for (i = 0; i < n; i++)
+ {
+ cairo_region_get_rectangle (window->current_paint.region, i, &rect);
+ wl_surface_damage (impl->display_server.wl_surface, rect.x, rect.y, rect.width, rect.height);
+ }
+
+ impl->pending_commit = TRUE;
+ }
+
+ gdk_wayland_surface_sync (window);
+}
+
+void
+gdk_wayland_surface_sync (GdkSurface *window)
+{
+ gdk_wayland_surface_sync_margin (window);
+ gdk_wayland_surface_sync_opaque_region (window);
+ gdk_wayland_surface_sync_input_region (window);
+}
+
+static gboolean
+gdk_surface_impl_wayland_beep (GdkSurface *window)
+{
+ gdk_wayland_display_system_bell (gdk_surface_get_display (window),
+ window);
+
+ return TRUE;
+}
+
+static void
+gdk_surface_impl_wayland_finalize (GObject *object)
+{
+ GdkSurface *window = GDK_SURFACE (object);
+ GdkSurfaceImplWayland *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE_IMPL_WAYLAND (object));
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (object);
+
+ if (gdk_wayland_surface_is_exported (window))
+ gdk_wayland_surface_unexport_handle (window);
+
+ g_free (impl->title);
+
+ g_free (impl->application.application_id);
+ g_free (impl->application.app_menu_path);
+ g_free (impl->application.menubar_path);
+ g_free (impl->application.window_object_path);
+ g_free (impl->application.application_object_path);
+ g_free (impl->application.unique_bus_name);
+
+ g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
+ g_clear_pointer (&impl->input_region, cairo_region_destroy);
+ g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
+
+ g_hash_table_destroy (impl->shortcuts_inhibitors);
+
+ G_OBJECT_CLASS (_gdk_surface_impl_wayland_parent_class)->finalize (object);
+}
+
+static void
+gdk_wayland_surface_configure (GdkSurface *window,
+ int width,
+ int height,
+ int scale)
+{
+ GdkDisplay *display;
+ GdkEvent *event;
+
+ event = gdk_event_new (GDK_CONFIGURE);
+ event->any.window = g_object_ref (window);
+ event->any.send_event = FALSE;
+ event->configure.width = width;
+ event->configure.height = height;
+
+ gdk_wayland_surface_update_size (window, width, height, scale);
+ _gdk_surface_update_size (window);
+
+ display = gdk_surface_get_display (window);
+ _gdk_wayland_display_deliver_event (display, event);
+}
+
+static void
+gdk_wayland_surface_maybe_configure (GdkSurface *window,
+ int width,
+ int height,
+ int scale)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ gboolean is_xdg_popup;
+ gboolean is_visible;
+
+ if (window->width == width &&
+ window->height == height &&
+ impl->scale == scale)
+ return;
+
+ /* For xdg_popup using an xdg_positioner, there is a race condition if
+ * the application tries to change the size after it's mapped, but before
+ * the initial configure is received, so hide and show the surface again
+ * force the new size onto the compositor. See bug #772505.
+ */
+
+ is_xdg_popup = (impl->display_server.xdg_popup != NULL);
+ is_visible = gdk_surface_is_visible (window);
+
+ if (is_xdg_popup && is_visible && !impl->initial_configure_received)
+ gdk_surface_hide (window);
+
+ gdk_wayland_surface_configure (window, width, height, scale);
+
+ if (is_xdg_popup && is_visible && !impl->initial_configure_received)
+ gdk_surface_show (window);
+}
+
+static void
+gdk_wayland_surface_sync_parent (GdkSurface *window,
+ GdkSurface *parent)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkSurfaceImplWayland *impl_parent = NULL;
+ struct zxdg_toplevel_v6 *parent_toplevel;
+
+ g_assert (parent == NULL ||
+ gdk_surface_get_display (window) == gdk_surface_get_display (parent));
+
+ if (!impl->display_server.xdg_toplevel)
+ return;
+
+ if (impl->transient_for)
+ impl_parent = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
+ else if (parent)
+ impl_parent = GDK_SURFACE_IMPL_WAYLAND (parent->impl);
+
+ if (impl_parent)
+ {
+ /* XXX: Is this correct? */
+ if (!impl_parent->display_server.wl_surface)
+ return;
+
+ parent_toplevel = impl_parent->display_server.xdg_toplevel;
+ }
+ else
+ parent_toplevel = NULL;
+
+ zxdg_toplevel_v6_set_parent (impl->display_server.xdg_toplevel,
+ parent_toplevel);
+}
+
+static void
+gdk_wayland_surface_sync_parent_of_imported (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (!impl->display_server.wl_surface)
+ return;
+
+ if (!impl->imported_transient_for)
+ return;
+
+ if (!impl->display_server.xdg_toplevel)
+ return;
+
+ zxdg_imported_v1_set_parent_of (impl->imported_transient_for,
+ impl->display_server.wl_surface);
+}
+
+static void
+gdk_wayland_surface_update_dialogs (GdkSurface *window)
+{
+ GdkWaylandDisplay *display_wayland =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ GList *l;
+
+ if (!display_wayland->orphan_dialogs)
+ return;
+
+ for (l = display_wayland->orphan_dialogs; l; l = l->next)
+ {
+ GdkSurface *w = l->data;
+ GdkSurfaceImplWayland *impl;
+
+ if (!GDK_IS_SURFACE_IMPL_WAYLAND(w->impl))
+ continue;
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (w->impl);
+ if (w == window)
+ continue;
+ if (impl->hint != GDK_SURFACE_TYPE_HINT_DIALOG)
+ continue;
+ if (impl->transient_for)
+ continue;
+
+ /* Update the parent relationship only for dialogs without transients */
+ gdk_wayland_surface_sync_parent (w, window);
+ }
+}
+
+static void
+gdk_wayland_surface_sync_title (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (!impl->display_server.xdg_toplevel)
+ return;
+
+ if (!impl->title)
+ return;
+
+ zxdg_toplevel_v6_set_title (impl->display_server.xdg_toplevel, impl->title);
+}
+
+static void
+gdk_wayland_surface_get_window_geometry (GdkSurface *window,
+ GdkRectangle *geometry)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ *geometry = (GdkRectangle) {
+ .x = impl->margin_left,
+ .y = impl->margin_top,
+ .width = window->width - (impl->margin_left + impl->margin_right),
+ .height = window->height - (impl->margin_top + impl->margin_bottom)
+ };
+}
+
+static void
+gdk_wayland_surface_sync_margin (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkRectangle geometry;
+
+ if (!impl->display_server.xdg_surface)
+ return;
+
+ gdk_wayland_surface_get_window_geometry (window, &geometry);
+ gdk_surface_set_geometry_hints (window,
+ &impl->geometry_hints,
+ impl->geometry_mask);
+ zxdg_surface_v6_set_window_geometry (impl->display_server.xdg_surface,
+ geometry.x,
+ geometry.y,
+ geometry.width,
+ geometry.height);
+}
+
+static struct wl_region *
+wl_region_from_cairo_region (GdkWaylandDisplay *display,
+ cairo_region_t *region)
+{
+ struct wl_region *wl_region;
+ int i, n_rects;
+
+ wl_region = wl_compositor_create_region (display->compositor);
+ if (wl_region == NULL)
+ return NULL;
+
+ n_rects = cairo_region_num_rectangles (region);
+ for (i = 0; i < n_rects; i++)
+ {
+ cairo_rectangle_int_t rect;
+ cairo_region_get_rectangle (region, i, &rect);
+ wl_region_add (wl_region, rect.x, rect.y, rect.width, rect.height);
+ }
+
+ return wl_region;
+}
+
+static void
+gdk_wayland_surface_sync_opaque_region (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ struct wl_region *wl_region = NULL;
+
+ if (!impl->display_server.wl_surface)
+ return;
+
+ if (!impl->opaque_region_dirty)
+ return;
+
+ if (impl->opaque_region != NULL)
+ wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window)),
+ impl->opaque_region);
+
+ wl_surface_set_opaque_region (impl->display_server.wl_surface, wl_region);
+
+ if (wl_region != NULL)
+ wl_region_destroy (wl_region);
+
+ impl->opaque_region_dirty = FALSE;
+}
+
+static void
+gdk_wayland_surface_sync_input_region (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ struct wl_region *wl_region = NULL;
+
+ if (!impl->display_server.wl_surface)
+ return;
+
+ if (!impl->input_region_dirty)
+ return;
+
+ if (impl->input_region != NULL)
+ wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window)),
+ impl->input_region);
+
+ wl_surface_set_input_region (impl->display_server.wl_surface, wl_region);
+
+ if (wl_region != NULL)
+ wl_region_destroy (wl_region);
+
+ impl->input_region_dirty = FALSE;
+}
+
+static void
+gdk_wayland_set_input_region_if_empty (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkWaylandDisplay *display;
+ struct wl_region *empty;
+
+ if (!impl->input_region_dirty)
+ return;
+
+ if (impl->input_region == NULL)
+ return;
+
+ if (!cairo_region_is_empty (impl->input_region))
+ return;
+
+ display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ empty = wl_compositor_create_region (display->compositor);
+
+ wl_surface_set_input_region (impl->display_server.wl_surface, empty);
+ wl_region_destroy (empty);
+
+ impl->input_region_dirty = FALSE;
+}
+
+static void
+surface_enter (void *data,
+ struct wl_surface *wl_surface,
+ struct wl_output *output)
+{
+ GdkSurface *window = GDK_SURFACE (data);
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ GDK_DISPLAY_NOTE (gdk_surface_get_display (window), EVENTS,
+ g_message ("surface enter, window %p output %p", window, output));
+
+ impl->display_server.outputs = g_slist_prepend (impl->display_server.outputs, output);
+
+ gdk_wayland_surface_update_scale (window);
+}
+
+static void
+surface_leave (void *data,
+ struct wl_surface *wl_surface,
+ struct wl_output *output)
+{
+ GdkSurface *window = GDK_SURFACE (data);
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ GDK_DISPLAY_NOTE (gdk_surface_get_display (window), EVENTS,
+ g_message ("surface leave, window %p output %p", window, output));
+
+ impl->display_server.outputs = g_slist_remove (impl->display_server.outputs, output);
+
+ if (impl->display_server.outputs)
+ gdk_wayland_surface_update_scale (window);
+}
+
+static const struct wl_surface_listener surface_listener = {
+ surface_enter,
+ surface_leave
+};
+
+static void
+on_parent_surface_committed (GdkSurfaceImplWayland *parent_impl,
+ GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ g_signal_handler_disconnect (parent_impl,
+ impl->parent_surface_committed_handler);
+ impl->parent_surface_committed_handler = 0;
+
+ wl_subsurface_set_desync (impl->display_server.wl_subsurface);
+
+ /* Special case if the input region is empty, it won't change on resize */
+ gdk_wayland_set_input_region_if_empty (window);
+}
+
+static void
+gdk_wayland_surface_create_subsurface (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl, *parent_impl = NULL;
+ GdkWaylandDisplay *display_wayland;
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (!impl->display_server.wl_surface)
+ return; /* Bail out, surface and subsurface will be created later when shown */
+
+ if (impl->display_server.wl_subsurface)
+ return;
+
+ if (impl->transient_for)
+ parent_impl = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
+
+ if (parent_impl && parent_impl->display_server.wl_surface)
+ {
+ display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ impl->display_server.wl_subsurface =
+ wl_subcompositor_get_subsurface (display_wayland->subcompositor,
+ impl->display_server.wl_surface, parent_impl->display_server.wl_surface);
+ wl_subsurface_set_position (impl->display_server.wl_subsurface,
+ window->x + window->abs_x,
+ window->y + window->abs_y);
+
+ /* In order to synchronize the initial position with the initial frame
+ * content, wait with making the subsurface desynchronized until after
+ * the parent was committed.
+ */
+ impl->parent_surface_committed_handler =
+ g_signal_connect_object (parent_impl, "committed",
+ G_CALLBACK (on_parent_surface_committed),
+ window, 0);
+ gdk_surface_request_transient_parent_commit (window);
+ }
+}
+
+static void
+gdk_wayland_surface_create_surface (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+
+ impl->display_server.wl_surface = wl_compositor_create_surface (display_wayland->compositor);
+ wl_surface_add_listener (impl->display_server.wl_surface, &surface_listener, window);
+}
+
+static void
+xdg_surface_configure (void *data,
+ struct zxdg_surface_v6 *xdg_surface,
+ uint32_t serial)
+{
+ GdkSurface *window = GDK_SURFACE (data);
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkSurfaceState new_state;
+ int width = impl->pending.width;
+ int height = impl->pending.height;
+ gboolean fixed_size;
+ gboolean saved_size;
+
+ if (!impl->initial_configure_received)
+ {
+ gdk_surface_thaw_updates (window);
+ impl->initial_configure_received = TRUE;
+ }
+
+ if (impl->display_server.xdg_popup)
+ {
+ zxdg_surface_v6_ack_configure (xdg_surface, serial);
+ return;
+ }
+
+ new_state = impl->pending.state;
+ impl->pending.state = 0;
+
+ fixed_size =
+ new_state & (GDK_SURFACE_STATE_MAXIMIZED | GDK_SURFACE_STATE_FULLSCREEN | GDK_SURFACE_STATE_TILED);
+
+ saved_size = (width == 0 && height == 0);
+ /* According to xdg_shell, an xdg_surface.configure with size 0x0
+ * should be interpreted as that it is up to the client to set a
+ * size.
+ *
+ * When transitioning from maximize or fullscreen state, this means
+ * the client should configure its size back to what it was before
+ * being maximize or fullscreen.
+ */
+ if (saved_size && !fixed_size)
+ {
+ width = impl->saved_width;
+ height = impl->saved_height;
+ }
+
+ if (width > 0 && height > 0)
+ {
+ GdkSurfaceHints geometry_mask = impl->geometry_mask;
+
+ /* Ignore size increments for maximized/fullscreen windows */
+ if (fixed_size)
+ geometry_mask &= ~GDK_HINT_RESIZE_INC;
+ if (!saved_size)
+ {
+ /* Do not reapply contrains if we are restoring original size */
+ gdk_surface_constrain_size (&impl->geometry_hints,
+ geometry_mask,
+ width + impl->margin_left + impl->margin_right,
+ height + impl->margin_top + impl->margin_bottom,
+ &width,
+ &height);
+
+ /* Save size for next time we get 0x0 */
+ _gdk_wayland_surface_save_size (window);
+ }
+
+ gdk_wayland_surface_configure (window, width, height, impl->scale);
+ }
+
+ GDK_DISPLAY_NOTE (gdk_surface_get_display (window), EVENTS,
+ g_message ("configure, window %p %dx%d,%s%s%s%s",
+ window, width, height,
+ (new_state & GDK_SURFACE_STATE_FULLSCREEN) ? " fullscreen" : "",
+ (new_state & GDK_SURFACE_STATE_MAXIMIZED) ? " maximized" : "",
+ (new_state & GDK_SURFACE_STATE_FOCUSED) ? " focused" : "",
+ (new_state & GDK_SURFACE_STATE_TILED) ? " tiled" : ""));
+
+ gdk_surface_set_state (window, new_state);
+ zxdg_surface_v6_ack_configure (xdg_surface, serial);
+ if (impl->hint != GDK_SURFACE_TYPE_HINT_DIALOG &&
+ new_state & GDK_SURFACE_STATE_FOCUSED)
+ gdk_wayland_surface_update_dialogs (window);
+}
+
+static const struct zxdg_surface_v6_listener xdg_surface_listener = {
+ xdg_surface_configure,
+};
+
+static void
+xdg_toplevel_configure (void *data,
+ struct zxdg_toplevel_v6 *xdg_toplevel,
+ int32_t width,
+ int32_t height,
+ struct wl_array *states)
+{
+ GdkSurface *window = GDK_SURFACE (data);
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ uint32_t *p;
+
+ wl_array_for_each (p, states)
+ {
+ uint32_t state = *p;
+ switch (state)
+ {
+ case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
+ impl->pending.state |= GDK_SURFACE_STATE_FULLSCREEN;
+ break;
+ case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED:
+ impl->pending.state |= GDK_SURFACE_STATE_MAXIMIZED;
+ break;
+ case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED:
+ impl->pending.state |= GDK_SURFACE_STATE_FOCUSED;
+ break;
+ case ZXDG_TOPLEVEL_V6_STATE_RESIZING:
+ break;
+ default:
+ /* Unknown state */
+ break;
+ }
+ }
+
+ impl->pending.width = width;
+ impl->pending.height = height;
+}
+
+static void
+xdg_toplevel_close (void *data,
+ struct zxdg_toplevel_v6 *xdg_toplevel)
+{
+ GdkSurface *window = GDK_SURFACE (data);
+ GdkDisplay *display;
+ GdkEvent *event;
+
+ display = gdk_surface_get_display (window);
+
+ GDK_DISPLAY_NOTE (display, EVENTS, g_message ("close %p", window));
+
+ event = gdk_event_new (GDK_DELETE);
+ event->any.window = g_object_ref (window);
+ event->any.send_event = TRUE;
+
+ _gdk_wayland_display_deliver_event (display, event);
+}
+
+static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
+ xdg_toplevel_configure,
+ xdg_toplevel_close,
+};
+
+static void
+gdk_wayland_surface_create_xdg_toplevel (GdkSurface *window)
+{
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ const gchar *app_id;
+
+ impl->display_server.xdg_surface =
+ zxdg_shell_v6_get_xdg_surface (display_wayland->xdg_shell,
+ impl->display_server.wl_surface);
+ zxdg_surface_v6_add_listener (impl->display_server.xdg_surface,
+ &xdg_surface_listener,
+ window);
+ gdk_surface_freeze_updates (window);
+
+ impl->display_server.xdg_toplevel =
+ zxdg_surface_v6_get_toplevel (impl->display_server.xdg_surface);
+ zxdg_toplevel_v6_add_listener (impl->display_server.xdg_toplevel,
+ &xdg_toplevel_listener,
+ window);
+
+ gdk_wayland_surface_sync_parent (window, NULL);
+ gdk_wayland_surface_sync_parent_of_imported (window);
+ gdk_wayland_surface_sync_title (window);
+
+ if (window->state & GDK_SURFACE_STATE_MAXIMIZED)
+ zxdg_toplevel_v6_set_maximized (impl->display_server.xdg_toplevel);
+ if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
+ zxdg_toplevel_v6_set_fullscreen (impl->display_server.xdg_toplevel,
+ impl->initial_fullscreen_output);
+
+ impl->initial_fullscreen_output = NULL;
+
+ app_id = g_get_prgname ();
+
+ if (app_id == NULL)
+ app_id = "GTK+ Application";
+
+ zxdg_toplevel_v6_set_app_id (impl->display_server.xdg_toplevel, app_id);
+
+ maybe_set_gtk_surface_dbus_properties (window);
+ maybe_set_gtk_surface_modal (window);
+
+ if (impl->hint == GDK_SURFACE_TYPE_HINT_DIALOG)
+ _gdk_wayland_screen_add_orphan_dialog (window);
+
+ wl_surface_commit (impl->display_server.wl_surface);
+}
+
+static void
+xdg_popup_configure (void *data,
+ struct zxdg_popup_v6 *xdg_popup,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height)
+{
+ GdkSurface *window = GDK_SURFACE (data);
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkRectangle flipped_rect;
+ GdkRectangle final_rect;
+ gboolean flipped_x;
+ gboolean flipped_y;
+
+ g_return_if_fail (impl->transient_for);
+
+ if (impl->position_method != POSITION_METHOD_MOVE_TO_RECT)
+ return;
+
+ calculate_moved_to_rect_result (window, x, y, width, height,
+ &flipped_rect,
+ &final_rect,
+ &flipped_x,
+ &flipped_y);
+
+ g_signal_emit_by_name (window,
+ "moved-to-rect",
+ &flipped_rect,
+ &final_rect,
+ flipped_x,
+ flipped_y);
+}
+
+static void
+xdg_popup_done (void *data,
+ struct zxdg_popup_v6 *xdg_popup)
+{
+ GdkSurface *window = GDK_SURFACE (data);
+
+ GDK_DISPLAY_NOTE (gdk_surface_get_display (window), EVENTS, g_message ("done %p", window));
+
+ gdk_surface_hide (window);
+}
+
+static const struct zxdg_popup_v6_listener xdg_popup_listener = {
+ xdg_popup_configure,
+ xdg_popup_done,
+};
+
+static enum zxdg_positioner_v6_anchor
+rect_anchor_to_anchor (GdkGravity rect_anchor)
+{
+ switch (rect_anchor)
+ {
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_STATIC:
+ return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
+ ZXDG_POSITIONER_V6_ANCHOR_LEFT);
+ case GDK_GRAVITY_NORTH:
+ return ZXDG_POSITIONER_V6_ANCHOR_TOP;
+ case GDK_GRAVITY_NORTH_EAST:
+ return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
+ ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
+ case GDK_GRAVITY_WEST:
+ return ZXDG_POSITIONER_V6_ANCHOR_LEFT;
+ case GDK_GRAVITY_CENTER:
+ return ZXDG_POSITIONER_V6_ANCHOR_NONE;
+ case GDK_GRAVITY_EAST:
+ return ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
+ case GDK_GRAVITY_SOUTH_WEST:
+ return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
+ ZXDG_POSITIONER_V6_ANCHOR_LEFT);
+ case GDK_GRAVITY_SOUTH:
+ return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
+ case GDK_GRAVITY_SOUTH_EAST:
+ return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
+ ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
+ default:
+ g_assert_not_reached ();
+ }
+
+ return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
+ ZXDG_POSITIONER_V6_ANCHOR_LEFT);
+}
+
+static enum zxdg_positioner_v6_gravity
+window_anchor_to_gravity (GdkGravity rect_anchor)
+{
+ switch (rect_anchor)
+ {
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_STATIC:
+ return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
+ ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
+ case GDK_GRAVITY_NORTH:
+ return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
+ case GDK_GRAVITY_NORTH_EAST:
+ return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
+ ZXDG_POSITIONER_V6_GRAVITY_LEFT);
+ case GDK_GRAVITY_WEST:
+ return ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
+ case GDK_GRAVITY_CENTER:
+ return ZXDG_POSITIONER_V6_GRAVITY_NONE;
+ case GDK_GRAVITY_EAST:
+ return ZXDG_POSITIONER_V6_GRAVITY_LEFT;
+ case GDK_GRAVITY_SOUTH_WEST:
+ return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
+ ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
+ case GDK_GRAVITY_SOUTH:
+ return ZXDG_POSITIONER_V6_GRAVITY_TOP;
+ case GDK_GRAVITY_SOUTH_EAST:
+ return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
+ ZXDG_POSITIONER_V6_GRAVITY_LEFT);
+ default:
+ g_assert_not_reached ();
+ }
+
+ return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
+ ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
+}
+
+void
+gdk_wayland_surface_announce_csd (GdkSurface *window)
+{
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ if (!display_wayland->server_decoration_manager)
+ return;
+ impl->display_server.server_decoration =
+ org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
+ impl->display_server.wl_surface);
+ if (impl->display_server.server_decoration)
+ org_kde_kwin_server_decoration_request_mode (impl->display_server.server_decoration,
+ ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT);
+}
+
+static GdkSurface *
+get_real_parent_and_translate (GdkSurface *window,
+ gint *x,
+ gint *y)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkSurface *parent = impl->transient_for;
+
+ while (parent)
+ {
+ GdkSurfaceImplWayland *parent_impl =
+ GDK_SURFACE_IMPL_WAYLAND (parent->impl);
+ GdkSurface *effective_parent = gdk_surface_get_parent (parent);
+
+ if ((gdk_surface_has_native (parent) &&
+ !parent_impl->display_server.wl_subsurface) ||
+ !effective_parent)
+ break;
+
+ *x += parent->x;
+ *y += parent->y;
+
+ if (gdk_surface_has_native (parent) &&
+ parent_impl->display_server.wl_subsurface)
+ parent = parent->transient_for;
+ else
+ parent = effective_parent;
+ }
+
+ return parent;
+}
+
+static void
+translate_to_real_parent_window_geometry (GdkSurface *window,
+ gint *x,
+ gint *y)
+{
+ GdkSurface *parent;
+
+ parent = get_real_parent_and_translate (window, x, y);
+
+ *x -= parent->shadow_left;
+ *y -= parent->shadow_top;
+}
+
+static GdkSurface *
+translate_from_real_parent_window_geometry (GdkSurface *window,
+ gint *x,
+ gint *y)
+{
+ GdkSurface *parent;
+ gint dx = 0;
+ gint dy = 0;
+
+ parent = get_real_parent_and_translate (window, &dx, &dy);
+
+ *x -= dx - parent->shadow_left;
+ *y -= dy - parent->shadow_top;
+
+ return parent;
+}
+
+static void
+calculate_popup_rect (GdkSurface *window,
+ GdkGravity rect_anchor,
+ GdkGravity window_anchor,
+ GdkRectangle *out_rect)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkRectangle geometry;
+ GdkRectangle anchor_rect;
+ int x = 0, y = 0;
+
+ gdk_wayland_surface_get_window_geometry (window, &geometry);
+
+ anchor_rect = (GdkRectangle) {
+ .x = (impl->pending_move_to_rect.rect.x +
+ impl->pending_move_to_rect.rect_anchor_dx),
+ .y = (impl->pending_move_to_rect.rect.y +
+ impl->pending_move_to_rect.rect_anchor_dy),
+ .width = impl->pending_move_to_rect.rect.width,
+ .height = impl->pending_move_to_rect.rect.height
+ };
+
+ switch (rect_anchor)
+ {
+ default:
+ case GDK_GRAVITY_STATIC:
+ case GDK_GRAVITY_NORTH_WEST:
+ x = anchor_rect.x;
+ y = anchor_rect.y;
+ break;
+ case GDK_GRAVITY_NORTH:
+ x = anchor_rect.x + (anchor_rect.width / 2);
+ y = anchor_rect.y;
+ break;
+ case GDK_GRAVITY_NORTH_EAST:
+ x = anchor_rect.x + anchor_rect.width;
+ y = anchor_rect.y;
+ break;
+ case GDK_GRAVITY_WEST:
+ x = anchor_rect.x;
+ y = anchor_rect.y + (anchor_rect.height / 2);
+ break;
+ case GDK_GRAVITY_CENTER:
+ x = anchor_rect.x + (anchor_rect.width / 2);
+ y = anchor_rect.y + (anchor_rect.height / 2);
+ break;
+ case GDK_GRAVITY_EAST:
+ x = anchor_rect.x + anchor_rect.width;
+ y = anchor_rect.y + (anchor_rect.height / 2);
+ break;
+ case GDK_GRAVITY_SOUTH_WEST:
+ x = anchor_rect.x;
+ y = anchor_rect.y + anchor_rect.height;
+ break;
+ case GDK_GRAVITY_SOUTH:
+ x = anchor_rect.x + (anchor_rect.width / 2);
+ y = anchor_rect.y + anchor_rect.height;
+ break;
+ case GDK_GRAVITY_SOUTH_EAST:
+ x = anchor_rect.x + anchor_rect.width;
+ y = anchor_rect.y + anchor_rect.height;
+ break;
+ }
+
+ switch (window_anchor)
+ {
+ default:
+ case GDK_GRAVITY_STATIC:
+ case GDK_GRAVITY_NORTH_WEST:
+ break;
+ case GDK_GRAVITY_NORTH:
+ x -= geometry.width / 2;
+ break;
+ case GDK_GRAVITY_NORTH_EAST:
+ x -= geometry.width;
+ break;
+ case GDK_GRAVITY_WEST:
+ y -= geometry.height / 2;
+ break;
+ case GDK_GRAVITY_CENTER:
+ x -= geometry.width / 2;
+ y -= geometry.height / 2;
+ break;
+ case GDK_GRAVITY_EAST:
+ x -= geometry.width;
+ y -= geometry.height / 2;
+ break;
+ case GDK_GRAVITY_SOUTH_WEST:
+ y -= geometry.height;
+ break;
+ case GDK_GRAVITY_SOUTH:
+ x -= geometry.width / 2;
+ y -= geometry.height;
+ break;
+ case GDK_GRAVITY_SOUTH_EAST:
+ x -= geometry.width;
+ y -= geometry.height;
+ break;
+ }
+
+ *out_rect = (GdkRectangle) {
+ .x = x,
+ .y = y,
+ .width = geometry.width,
+ .height = geometry.height
+ };
+}
+
+static GdkGravity
+flip_anchor_horizontally (GdkGravity anchor)
+{
+ switch (anchor)
+ {
+ default:
+ case GDK_GRAVITY_STATIC:
+ case GDK_GRAVITY_NORTH_WEST:
+ return GDK_GRAVITY_NORTH_EAST;
+ case GDK_GRAVITY_NORTH:
+ return GDK_GRAVITY_NORTH;
+ case GDK_GRAVITY_NORTH_EAST:
+ return GDK_GRAVITY_NORTH_WEST;
+ case GDK_GRAVITY_WEST:
+ return GDK_GRAVITY_EAST;
+ case GDK_GRAVITY_CENTER:
+ return GDK_GRAVITY_CENTER;
+ case GDK_GRAVITY_EAST:
+ return GDK_GRAVITY_WEST;
+ case GDK_GRAVITY_SOUTH_WEST:
+ return GDK_GRAVITY_SOUTH_EAST;
+ case GDK_GRAVITY_SOUTH:
+ return GDK_GRAVITY_SOUTH;
+ case GDK_GRAVITY_SOUTH_EAST:
+ return GDK_GRAVITY_SOUTH_WEST;
+ }
+
+ g_assert_not_reached ();
+}
+
+static GdkGravity
+flip_anchor_vertically (GdkGravity anchor)
+{
+ switch (anchor)
+ {
+ default:
+ case GDK_GRAVITY_STATIC:
+ case GDK_GRAVITY_NORTH_WEST:
+ return GDK_GRAVITY_SOUTH_WEST;
+ case GDK_GRAVITY_NORTH:
+ return GDK_GRAVITY_SOUTH;
+ case GDK_GRAVITY_NORTH_EAST:
+ return GDK_GRAVITY_SOUTH_EAST;
+ case GDK_GRAVITY_WEST:
+ return GDK_GRAVITY_WEST;
+ case GDK_GRAVITY_CENTER:
+ return GDK_GRAVITY_CENTER;
+ case GDK_GRAVITY_EAST:
+ return GDK_GRAVITY_EAST;
+ case GDK_GRAVITY_SOUTH_WEST:
+ return GDK_GRAVITY_NORTH_WEST;
+ case GDK_GRAVITY_SOUTH:
+ return GDK_GRAVITY_NORTH;
+ case GDK_GRAVITY_SOUTH_EAST:
+ return GDK_GRAVITY_NORTH_EAST;
+ }
+
+ g_assert_not_reached ();
+}
+
+static void
+calculate_moved_to_rect_result (GdkSurface *window,
+ int x,
+ int y,
+ int width,
+ int height,
+ GdkRectangle *flipped_rect,
+ GdkRectangle *final_rect,
+ gboolean *flipped_x,
+ gboolean *flipped_y)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkSurface *parent;
+ gint window_x, window_y;
+ gint window_width, window_height;
+ GdkRectangle best_rect;
+
+ parent = translate_from_real_parent_window_geometry (window, &x, &y);
+ *final_rect = (GdkRectangle) {
+ .x = x,
+ .y = y,
+ .width = width,
+ .height = height,
+ };
+
+ window_x = parent->x + x;
+ window_y = parent->y + y;
+ window_width = width + window->shadow_left + window->shadow_right;
+ window_height = height + window->shadow_top + window->shadow_bottom;
+
+ gdk_surface_move_resize (window,
+ window_x, window_y,
+ window_width, window_height);
+
+ calculate_popup_rect (window,
+ impl->pending_move_to_rect.rect_anchor,
+ impl->pending_move_to_rect.window_anchor,
+ &best_rect);
+
+ *flipped_rect = best_rect;
+
+ if (x != best_rect.x &&
+ impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_X)
+ {
+ GdkRectangle flipped_x_rect;
+ GdkGravity flipped_rect_anchor;
+ GdkGravity flipped_window_anchor;
+
+ flipped_rect_anchor =
+ flip_anchor_horizontally (impl->pending_move_to_rect.rect_anchor);
+ flipped_window_anchor =
+ flip_anchor_horizontally (impl->pending_move_to_rect.window_anchor),
+ calculate_popup_rect (window,
+ flipped_rect_anchor,
+ flipped_window_anchor,
+ &flipped_x_rect);
+
+ if (flipped_x_rect.x == x)
+ flipped_rect->x = x;
+ }
+ if (y != best_rect.y &&
+ impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_Y)
+ {
+ GdkRectangle flipped_y_rect;
+ GdkGravity flipped_rect_anchor;
+ GdkGravity flipped_window_anchor;
+
+ flipped_rect_anchor =
+ flip_anchor_vertically (impl->pending_move_to_rect.rect_anchor);
+ flipped_window_anchor =
+ flip_anchor_vertically (impl->pending_move_to_rect.window_anchor),
+ calculate_popup_rect (window,
+ flipped_rect_anchor,
+ flipped_window_anchor,
+ &flipped_y_rect);
+
+ if (flipped_y_rect.y == y)
+ flipped_rect->y = y;
+ }
+
+ *flipped_x = flipped_rect->x != best_rect.x;
+ *flipped_y = flipped_rect->y != best_rect.y;
+}
+
+static struct zxdg_positioner_v6 *
+create_dynamic_positioner (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkWaylandDisplay *display =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ struct zxdg_positioner_v6 *positioner;
+ GdkRectangle geometry;
+ enum zxdg_positioner_v6_anchor anchor;
+ enum zxdg_positioner_v6_gravity gravity;
+ uint32_t constraint_adjustment = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE;
+ gint real_anchor_rect_x, real_anchor_rect_y;
+ gint anchor_rect_width, anchor_rect_height;
+
+ positioner = zxdg_shell_v6_create_positioner (display->xdg_shell);
+
+ gdk_wayland_surface_get_window_geometry (window, &geometry);
+ zxdg_positioner_v6_set_size (positioner, geometry.width, geometry.height);
+
+ real_anchor_rect_x = impl->pending_move_to_rect.rect.x;
+ real_anchor_rect_y = impl->pending_move_to_rect.rect.y;
+ translate_to_real_parent_window_geometry (window,
+ &real_anchor_rect_x,
+ &real_anchor_rect_y);
+
+ anchor_rect_width = impl->pending_move_to_rect.rect.width;
+ anchor_rect_height = impl->pending_move_to_rect.rect.height;
+ zxdg_positioner_v6_set_anchor_rect (positioner,
+ real_anchor_rect_x,
+ real_anchor_rect_y,
+ anchor_rect_width,
+ anchor_rect_height);
+
+ zxdg_positioner_v6_set_offset (positioner,
+ impl->pending_move_to_rect.rect_anchor_dx,
+ impl->pending_move_to_rect.rect_anchor_dy);
+
+ anchor = rect_anchor_to_anchor (impl->pending_move_to_rect.rect_anchor);
+ zxdg_positioner_v6_set_anchor (positioner, anchor);
+
+ gravity = window_anchor_to_gravity (impl->pending_move_to_rect.window_anchor);
+ zxdg_positioner_v6_set_gravity (positioner, gravity);
+
+ if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_X)
+ constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X;
+ if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_Y)
+ constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y;
+ if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_X)
+ constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X;
+ if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_Y)
+ constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
+ if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_X)
+ constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X;
+ if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_Y)
+ constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
+
+ zxdg_positioner_v6_set_constraint_adjustment (positioner,
+ constraint_adjustment);
+
+ return positioner;
+}
+
+static struct zxdg_positioner_v6 *
+create_simple_positioner (GdkSurface *window,
+ GdkSurface *parent)
+{
+ GdkWaylandDisplay *display =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ struct zxdg_positioner_v6 *positioner;
+ GdkRectangle geometry;
+ GdkRectangle parent_geometry;
+ int parent_x, parent_y;
+
+ positioner = zxdg_shell_v6_create_positioner (display->xdg_shell);
+
+ gdk_wayland_surface_get_window_geometry (window, &geometry);
+ zxdg_positioner_v6_set_size (positioner, geometry.width, geometry.height);
+
+ parent_x = parent->x;
+ parent_y = parent->y;
+
+ gdk_wayland_surface_get_window_geometry (parent, &parent_geometry);
+ parent_x += parent_geometry.x;
+ parent_y += parent_geometry.y;
+
+ zxdg_positioner_v6_set_anchor_rect (positioner,
+ (window->x + geometry.x) - parent_x,
+ (window->y + geometry.y) - parent_y,
+ 1, 1);
+ zxdg_positioner_v6_set_anchor (positioner,
+ (ZXDG_POSITIONER_V6_ANCHOR_TOP |
+ ZXDG_POSITIONER_V6_ANCHOR_LEFT));
+ zxdg_positioner_v6_set_gravity (positioner,
+ (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
+ ZXDG_POSITIONER_V6_GRAVITY_RIGHT));
+
+ return positioner;
+}
+
+static void
+gdk_wayland_surface_create_xdg_popup (GdkSurface *window,
+ GdkSurface *parent,
+ struct wl_seat *seat)
+{
+ GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkSurfaceImplWayland *parent_impl = GDK_SURFACE_IMPL_WAYLAND (parent->impl);
+ struct zxdg_positioner_v6 *positioner;
+ GdkSeat *gdk_seat;
+ guint32 serial;
+
+ if (!impl->display_server.wl_surface)
+ return;
+
+ if (!parent_impl->display_server.xdg_surface)
+ return;
+
+ if (impl->display_server.xdg_toplevel)
+ {
+ g_warning ("Can't map popup, already mapped as toplevel");
+ return;
+ }
+ if (impl->display_server.xdg_popup)
+ {
+ g_warning ("Can't map popup, already mapped");
+ return;
+ }
+ if ((display->current_popups &&
+ g_list_last (display->current_popups)->data != parent) ||
+ (!display->current_popups &&
+ !parent_impl->display_server.xdg_toplevel))
+ {
+ g_warning ("Tried to map a popup with a non-top most parent");
+ return;
+ }
+
+ impl->display_server.xdg_surface =
+ zxdg_shell_v6_get_xdg_surface (display->xdg_shell,
+ impl->display_server.wl_surface);
+ zxdg_surface_v6_add_listener (impl->display_server.xdg_surface,
+ &xdg_surface_listener,
+ window);
+ gdk_surface_freeze_updates (window);
+
+ if (impl->position_method == POSITION_METHOD_MOVE_TO_RECT)
+ positioner = create_dynamic_positioner (window);
+ else
+ positioner = create_simple_positioner (window, parent);
+
+ impl->display_server.xdg_popup =
+ zxdg_surface_v6_get_popup (impl->display_server.xdg_surface,
+ parent_impl->display_server.xdg_surface,
+ positioner);
+ zxdg_popup_v6_add_listener (impl->display_server.xdg_popup,
+ &xdg_popup_listener,
+ window);
+
+ zxdg_positioner_v6_destroy (positioner);
+
+ if (seat)
+ {
+ gdk_seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
+ serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_seat, NULL);
+ zxdg_popup_v6_grab (impl->display_server.xdg_popup, seat, serial);
+ }
+
+ wl_surface_commit (impl->display_server.wl_surface);
+
+ impl->popup_parent = parent;
+ display->current_popups = g_list_append (display->current_popups, window);
+}
+
+static struct wl_seat *
+find_grab_input_seat (GdkSurface *window, GdkSurface *transient_for)
+{
+ GdkSurface *attached_grab_window;
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkSurfaceImplWayland *tmp_impl;
+
+ /* Use the device that was used for the grab as the device for
+ * the popup window setup - so this relies on GTK+ taking the
+ * grab before showing the popup window.
+ */
+ if (impl->grab_input_seat)
+ return gdk_wayland_seat_get_wl_seat (impl->grab_input_seat);
+
+ /* HACK: GtkMenu grabs a special window known as the "grab transfer window"
+ * and then transfers the grab over to the correct window later. Look for
+ * this window when taking the grab to know it's correct.
+ *
+ * See: associate_menu_grab_transfer_window in gtkmenu.c
+ */
+ attached_grab_window = g_object_get_data (G_OBJECT (window), "gdk-attached-grab-window");
+ if (attached_grab_window)
+ {
+ tmp_impl = GDK_SURFACE_IMPL_WAYLAND (attached_grab_window->impl);
+ if (tmp_impl->grab_input_seat)
+ return gdk_wayland_seat_get_wl_seat (tmp_impl->grab_input_seat);
+ }
+
+ while (transient_for)
+ {
+ tmp_impl = GDK_SURFACE_IMPL_WAYLAND (transient_for->impl);
+
+ if (tmp_impl->grab_input_seat)
+ return gdk_wayland_seat_get_wl_seat (tmp_impl->grab_input_seat);
+
+ transient_for = tmp_impl->transient_for;
+ }
+
+ return NULL;
+}
+
+static gboolean
+should_be_mapped (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ /* Don't map crazy temp that GTK+ uses for internal X11 shenanigans. */
+ if (window->window_type == GDK_SURFACE_TEMP && window->x < 0 && window->y < 0)
+ return FALSE;
+
+ if (impl->hint == GDK_SURFACE_TYPE_HINT_DND)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+should_map_as_popup (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ /* Ideally, popup would be temp windows with a parent and grab */
+ if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP)
+ {
+ /* If a temp window has a parent and a grab, we can use a popup */
+ if (impl->transient_for)
+ {
+ if (impl->grab_input_seat)
+ return TRUE;
+ }
+ else
+ g_message ("Window %p is a temporary window without parent, "
+ "application will not be able to position it on screen.",
+ window);
+ }
+
+ /* Yet we need to keep the window type hint tests for compatibility */
+ switch ((guint) impl->hint)
+ {
+ case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
+ case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU:
+ case GDK_SURFACE_TYPE_HINT_COMBO:
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+should_map_as_subsurface (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_SUBSURFACE)
+ return TRUE;
+
+ if (GDK_SURFACE_TYPE (window) != GDK_SURFACE_TEMP)
+ return FALSE;
+
+ /* if we want a popup, we do not want a subsurface */
+ if (should_map_as_popup (window))
+ return FALSE;
+
+ if (impl->transient_for)
+ {
+ GdkSurfaceImplWayland *impl_parent;
+
+ impl_parent = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
+ /* subsurface require that the parent is mapped */
+ if (impl_parent->mapped)
+ return TRUE;
+ else
+ g_warning ("Couldn't map window %p as subsurface because its parent is not mapped.",
+ window);
+
+ }
+
+ return FALSE;
+}
+
+/* Get the window that can be used as a parent for a popup, i.e. a xdg_toplevel
+ * or xdg_popup. If the window is not, traverse up the transiency parents until
+ * we find one.
+ */
+static GdkSurface *
+get_popup_parent (GdkSurface *window)
+{
+ while (window)
+ {
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (impl->display_server.xdg_popup || impl->display_server.xdg_toplevel)
+ return window;
+
+ window = impl->transient_for;
+ }
+
+ return NULL;
+}
+
+static void
+gdk_wayland_surface_map (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkSurface *transient_for = NULL;
+
+ if (!should_be_mapped (window))
+ return;
+
+ if (impl->mapped || impl->use_custom_surface)
+ return;
+
+ if (should_map_as_subsurface (window))
+ {
+ if (impl->transient_for)
+ gdk_wayland_surface_create_subsurface (window);
+ else
+ g_warning ("Couldn't map window %p as susburface yet because it doesn't have a parent",
+ window);
+ }
+ else if (should_map_as_popup (window))
+ {
+ gboolean create_fallback = FALSE;
+ struct wl_seat *grab_input_seat;
+
+ /* Popup menus can appear without a transient parent, which means they
+ * cannot be positioned properly on Wayland. This attempts to guess the
+ * surface they should be positioned with by finding the surface beneath
+ * the device that created the grab for the popup window.
+ */
+ if (!impl->transient_for && impl->hint == GDK_SURFACE_TYPE_HINT_POPUP_MENU)
+ {
+ GdkDevice *grab_device = NULL;
+
+ /* The popup menu window is not the grabbed window. This may mean
+ * that a "transfer window" (see gtkmenu.c) is used, and we need
+ * to find that window to get the grab device. If so is the case
+ * the "transfer window" can be retrieved via the
+ * "gdk-attached-grab-window" associated data field.
+ */
+ if (!impl->grab_input_seat)
+ {
+ GdkSurface *attached_grab_window =
+ g_object_get_data (G_OBJECT (window),
+ "gdk-attached-grab-window");
+ if (attached_grab_window)
+ {
+ GdkSurfaceImplWayland *attached_impl =
+ GDK_SURFACE_IMPL_WAYLAND (attached_grab_window->impl);
+ grab_device = gdk_seat_get_pointer (attached_impl->grab_input_seat);
+ transient_for =
+ gdk_device_get_window_at_position (grab_device,
+ NULL, NULL);
+ }
+ }
+ else
+ {
+ grab_device = gdk_seat_get_pointer (impl->grab_input_seat);
+ transient_for =
+ gdk_device_get_window_at_position (grab_device, NULL, NULL);
+ }
+
+ if (transient_for)
+ transient_for = get_popup_parent (gdk_surface_get_toplevel (transient_for));
+
+ /* If the position was not explicitly set, start the popup at the
+ * position of the device that holds the grab.
+ */
+ if (impl->position_method == POSITION_METHOD_NONE && grab_device)
+ gdk_surface_get_device_position (transient_for, grab_device,
+ &window->x, &window->y, NULL);
+ }
+ else
+ {
+ transient_for = gdk_surface_get_toplevel (impl->transient_for);
+ transient_for = get_popup_parent (transient_for);
+ }
+
+ if (!transient_for)
+ {
+ g_warning ("Couldn't map as window %p as popup because it doesn't have a parent",
+ window);
+
+ create_fallback = TRUE;
+ }
+ else
+ {
+ grab_input_seat = find_grab_input_seat (window, transient_for);
+ }
+
+ if (!create_fallback)
+ {
+ gdk_wayland_surface_create_xdg_popup (window,
+ transient_for,
+ grab_input_seat);
+ }
+ else
+ {
+ gdk_wayland_surface_create_xdg_toplevel (window);
+ }
+ }
+ else
+ {
+ gdk_wayland_surface_create_xdg_toplevel (window);
+ }
+
+ impl->mapped = TRUE;
+}
+
+static void
+gdk_wayland_surface_show (GdkSurface *window,
+ gboolean already_mapped)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (!impl->display_server.wl_surface)
+ gdk_wayland_surface_create_surface (window);
+
+ gdk_wayland_surface_map (window);
+
+ _gdk_make_event (window, GDK_MAP, NULL, FALSE);
+
+ if (impl->staging_cairo_surface &&
+ _gdk_wayland_is_shm_surface (impl->staging_cairo_surface))
+ gdk_wayland_surface_attach_image (window);
+}
+
+static void
+unmap_subsurface (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkSurfaceImplWayland *parent_impl;
+
+ g_return_if_fail (impl->display_server.wl_subsurface);
+ g_return_if_fail (impl->transient_for);
+
+ parent_impl = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
+ wl_subsurface_destroy (impl->display_server.wl_subsurface);
+ if (impl->parent_surface_committed_handler)
+ {
+ g_signal_handler_disconnect (parent_impl,
+ impl->parent_surface_committed_handler);
+ impl->parent_surface_committed_handler = 0;
+ }
+ impl->display_server.wl_subsurface = NULL;
+}
+
+static void
+unmap_popups_for_window (GdkSurface *window)
+{
+ GdkWaylandDisplay *display_wayland;
+ GList *l;
+
+ display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ for (l = display_wayland->current_popups; l; l = l->next)
+ {
+ GdkSurface *popup = l->data;
+ GdkSurfaceImplWayland *popup_impl = GDK_SURFACE_IMPL_WAYLAND (popup->impl);
+
+ if (popup_impl->popup_parent == window)
+ {
+ g_warning ("Tried to unmap the parent of a popup");
+ gdk_surface_hide (popup);
+
+ return;
+ }
+ }
+}
+
+static void
+gdk_wayland_surface_hide_surface (GdkSurface *window)
+{
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ unmap_popups_for_window (window);
+
+ if (impl->display_server.wl_surface)
+ {
+ if (impl->dummy_egl_surface)
+ {
+ eglDestroySurface (display_wayland->egl_display, impl->dummy_egl_surface);
+ impl->dummy_egl_surface = NULL;
+ }
+
+ if (impl->display_server.dummy_egl_window)
+ {
+ wl_egl_window_destroy (impl->display_server.dummy_egl_window);
+ impl->display_server.dummy_egl_window = NULL;
+ }
+
+ if (impl->egl_surface)
+ {
+ eglDestroySurface (display_wayland->egl_display, impl->egl_surface);
+ impl->egl_surface = NULL;
+ }
+
+ if (impl->display_server.egl_window)
+ {
+ wl_egl_window_destroy (impl->display_server.egl_window);
+ impl->display_server.egl_window = NULL;
+ }
+
+ if (impl->display_server.xdg_toplevel)
+ {
+ zxdg_toplevel_v6_destroy (impl->display_server.xdg_toplevel);
+ impl->display_server.xdg_toplevel = NULL;
+ }
+ else if (impl->display_server.xdg_popup)
+ {
+ zxdg_popup_v6_destroy (impl->display_server.xdg_popup);
+ impl->display_server.xdg_popup = NULL;
+ display_wayland->current_popups =
+ g_list_remove (display_wayland->current_popups, window);
+ }
+ if (impl->display_server.xdg_surface)
+ {
+ zxdg_surface_v6_destroy (impl->display_server.xdg_surface);
+ impl->display_server.xdg_surface = NULL;
+ if (!impl->initial_configure_received)
+ gdk_surface_thaw_updates (window);
+ else
+ impl->initial_configure_received = FALSE;
+ }
+
+ if (impl->display_server.wl_subsurface)
+ unmap_subsurface (window);
+
+ if (impl->awaiting_frame)
+ {
+ GdkFrameClock *frame_clock;
+
+ impl->awaiting_frame = FALSE;
+ frame_clock = gdk_surface_get_frame_clock (window);
+ if (frame_clock)
+ _gdk_frame_clock_thaw (frame_clock);
+ }
+
+ if (impl->display_server.gtk_surface)
+ {
+ gtk_surface1_destroy (impl->display_server.gtk_surface);
+ impl->display_server.gtk_surface = NULL;
+ impl->application.was_set = FALSE;
+ }
+
+ wl_surface_destroy (impl->display_server.wl_surface);
+ impl->display_server.wl_surface = NULL;
+
+ g_slist_free (impl->display_server.outputs);
+ impl->display_server.outputs = NULL;
+
+ if (impl->hint == GDK_SURFACE_TYPE_HINT_DIALOG && !impl->transient_for)
+ display_wayland->orphan_dialogs =
+ g_list_remove (display_wayland->orphan_dialogs, window);
+ }
+
+ unset_transient_for_exported (window);
+
+ _gdk_wayland_surface_clear_saved_size (window);
+ impl->pending_commit = FALSE;
+ impl->mapped = FALSE;
+}
+
+static void
+gdk_wayland_surface_hide (GdkSurface *window)
+{
+ gdk_wayland_surface_hide_surface (window);
+ _gdk_surface_clear_update_area (window);
+}
+
+static void
+gdk_surface_wayland_withdraw (GdkSurface *window)
+{
+ if (!window->destroyed)
+ {
+ if (GDK_SURFACE_IS_MAPPED (window))
+ gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_WITHDRAWN);
+
+ g_assert (!GDK_SURFACE_IS_MAPPED (window));
+
+ gdk_wayland_surface_hide_surface (window);
+ }
+}
+
+static void
+gdk_surface_wayland_set_events (GdkSurface *window,
+ GdkEventMask event_mask)
+{
+ GDK_SURFACE (window)->event_mask = event_mask;
+}
+
+static GdkEventMask
+gdk_surface_wayland_get_events (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window))
+ return 0;
+ else
+ return GDK_SURFACE (window)->event_mask;
+}
+
+static void
+gdk_surface_wayland_raise (GdkSurface *window)
+{
+}
+
+static void
+gdk_surface_wayland_lower (GdkSurface *window)
+{
+}
+
+static void
+gdk_surface_wayland_restack_toplevel (GdkSurface *window,
+ GdkSurface *sibling,
+ gboolean above)
+{
+}
+
+static void
+gdk_surface_request_transient_parent_commit (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *window_impl, *impl;
+ GdkFrameClock *frame_clock;
+
+ window_impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (!window_impl->transient_for)
+ return;
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window_impl->transient_for->impl);
+
+ if (!impl->display_server.wl_surface || impl->pending_commit)
+ return;
+
+ frame_clock = gdk_surface_get_frame_clock (window_impl->transient_for);
+
+ if (!frame_clock)
+ return;
+
+ impl->pending_commit = TRUE;
+ gdk_frame_clock_request_phase (frame_clock,
+ GDK_FRAME_CLOCK_PHASE_AFTER_PAINT);
+}
+
+static void
+gdk_surface_wayland_move_resize (GdkSurface *window,
+ gboolean with_move,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (with_move)
+ {
+ /* Each toplevel has in its own "root" coordinate system */
+ if (GDK_SURFACE_TYPE (window) != GDK_SURFACE_TOPLEVEL)
+ {
+ window->x = x;
+ window->y = y;
+ impl->position_method = POSITION_METHOD_MOVE_RESIZE;
+
+ if (impl->display_server.wl_subsurface)
+ {
+ wl_subsurface_set_position (impl->display_server.wl_subsurface,
+ window->x + window->abs_x,
+ window->y + window->abs_y);
+ gdk_surface_request_transient_parent_commit (window);
+ }
+ }
+ }
+
+ /* If this function is called with width and height = -1 then that means
+ * just move the window - don't update its size
+ */
+ if (width > 0 && height > 0)
+ gdk_wayland_surface_maybe_configure (window, width, height, impl->scale);
+}
+
+/* Avoid zero width/height as this is a protocol error */
+static void
+sanitize_anchor_rect (GdkSurface *window,
+ GdkRectangle *rect)
+{
+ gint original_width = rect->width;
+ gint original_height = rect->height;
+
+ rect->width = MAX (1, rect->width);
+ rect->height = MAX (1, rect->height);
+ rect->x = MAX (rect->x + original_width - rect->width, 0);
+ rect->y = MAX (rect->y + original_height - rect->height, 0);
+}
+
+static void
+gdk_surface_wayland_move_to_rect (GdkSurface *window,
+ const GdkRectangle *rect,
+ GdkGravity rect_anchor,
+ GdkGravity window_anchor,
+ GdkAnchorHints anchor_hints,
+ gint rect_anchor_dx,
+ gint rect_anchor_dy)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ impl->pending_move_to_rect.rect = *rect;
+ sanitize_anchor_rect (window, &impl->pending_move_to_rect.rect);
+
+ impl->pending_move_to_rect.rect_anchor = rect_anchor;
+ impl->pending_move_to_rect.window_anchor = window_anchor;
+ impl->pending_move_to_rect.anchor_hints = anchor_hints;
+ impl->pending_move_to_rect.rect_anchor_dx = rect_anchor_dx;
+ impl->pending_move_to_rect.rect_anchor_dy = rect_anchor_dy;
+
+ impl->position_method = POSITION_METHOD_MOVE_TO_RECT;
+}
+
+static void
+gdk_surface_wayland_get_geometry (GdkSurface *window,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height)
+{
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ if (x)
+ *x = window->x;
+ if (y)
+ *y = window->y;
+ if (width)
+ *width = window->width;
+ if (height)
+ *height = window->height;
+ }
+}
+
+static void
+gdk_surface_wayland_get_root_coords (GdkSurface *window,
+ gint x,
+ gint y,
+ gint *root_x,
+ gint *root_y)
+{
+ /*
+ * Wayland does not have a global coordinate space shared between surfaces. In
+ * fact, for regular toplevels, we have no idea where our surfaces are
+ * positioned, relatively.
+ *
+ * However, there are some cases like popups and subsurfaces where we do have
+ * some amount of control over the placement of our window, and we can
+ * semi-accurately control the x/y position of these windows, if they are
+ * relative to another surface.
+ *
+ * To pretend we have something called a root coordinate space, assume all
+ * parent-less windows are positioned in (0, 0), and all relative positioned
+ * popups and subsurfaces are placed within this fake root coordinate space.
+ *
+ * For example a 200x200 large toplevel window will have the position (0, 0).
+ * If a popup positioned in the middle of the toplevel will have the fake
+ * position (100,100). Furthermore, if a positioned is placed in the middle
+ * that popup, will have the fake position (150,150), even though it has the
+ * relative position (50,50). These three windows would make up one single
+ * fake root coordinate space.
+ */
+
+ if (root_x)
+ *root_x = window->x + x;
+
+ if (root_y)
+ *root_y = window->y + y;
+}
+
+static gboolean
+gdk_surface_wayland_get_device_state (GdkSurface *window,
+ GdkDevice *device,
+ gdouble *x,
+ gdouble *y,
+ GdkModifierType *mask)
+{
+ gboolean return_val;
+
+ g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), FALSE);
+
+ return_val = TRUE;
+
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ GdkSurface *child;
+
+ GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
+ &child,
+ NULL, NULL,
+ x, y, mask);
+ return_val = (child != NULL);
+ }
+
+ return return_val;
+}
+
+static void
+gdk_surface_wayland_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+}
+
+static void
+gdk_surface_wayland_input_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ g_clear_pointer (&impl->input_region, cairo_region_destroy);
+
+ if (shape_region)
+ {
+ impl->input_region = cairo_region_copy (shape_region);
+ cairo_region_translate (impl->input_region, offset_x, offset_y);
+ }
+
+ impl->input_region_dirty = TRUE;
+}
+
+static void
+gdk_wayland_surface_destroy (GdkSurface *window,
+ gboolean recursing,
+ gboolean foreign_destroy)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ /* Wayland windows can't be externally destroyed; we may possibly
+ * eventually want to use this path at display close-down
+ */
+ g_return_if_fail (!foreign_destroy);
+
+ gdk_wayland_surface_hide_surface (window);
+ drop_cairo_surfaces (window);
+
+ if (window->parent == NULL)
+ {
+ GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ display->toplevels = g_list_remove (display->toplevels, window);
+ }
+}
+
+static void
+gdk_wayland_surface_focus (GdkSurface *window,
+ guint32 timestamp)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (!impl->display_server.gtk_surface)
+ return;
+
+ /* We didn't have an event to fetch a time from, meaning we have nothing valid
+ * to send. This should rather be translated to a 'needs-attention' request or
+ * something.
+ */
+ if (timestamp == GDK_CURRENT_TIME)
+ return;
+
+ gtk_surface1_present (impl->display_server.gtk_surface, timestamp);
+}
+
+static void
+gdk_wayland_surface_set_type_hint (GdkSurface *window,
+ GdkSurfaceTypeHint hint)
+{
+ GdkSurfaceImplWayland *impl;
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ impl->hint = hint;
+}
+
+static GdkSurfaceTypeHint
+gdk_wayland_surface_get_type_hint (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return GDK_SURFACE_TYPE_HINT_NORMAL;
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ return impl->hint;
+}
+
+static void
+gtk_surface_configure (void *data,
+ struct gtk_surface1 *gtk_surface,
+ struct wl_array *states)
+{
+ GdkSurface *window = GDK_SURFACE (data);
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkSurfaceState new_state = 0;
+ uint32_t *p;
+
+ wl_array_for_each (p, states)
+ {
+ uint32_t state = *p;
+
+ switch (state)
+ {
+ case GTK_SURFACE1_STATE_TILED:
+ new_state |= GDK_SURFACE_STATE_TILED;
+ break;
+
+ /* Since v2 */
+ case GTK_SURFACE1_STATE_TILED_TOP:
+ new_state |= (GDK_SURFACE_STATE_TILED | GDK_SURFACE_STATE_TOP_TILED);
+ break;
+ case GTK_SURFACE1_STATE_TILED_RIGHT:
+ new_state |= (GDK_SURFACE_STATE_TILED | GDK_SURFACE_STATE_RIGHT_TILED);
+ break;
+ case GTK_SURFACE1_STATE_TILED_BOTTOM:
+ new_state |= (GDK_SURFACE_STATE_TILED | GDK_SURFACE_STATE_BOTTOM_TILED);
+ break;
+ case GTK_SURFACE1_STATE_TILED_LEFT:
+ new_state |= (GDK_SURFACE_STATE_TILED | GDK_SURFACE_STATE_LEFT_TILED);
+ break;
+ default:
+ /* Unknown state */
+ break;
+ }
+ }
+
+ impl->pending.state |= new_state;
+}
+
+static void
+gtk_surface_configure_edges (void *data,
+ struct gtk_surface1 *gtk_surface,
+ struct wl_array *edge_constraints)
+{
+ GdkSurface *window = GDK_SURFACE (data);
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkSurfaceState new_state = 0;
+ uint32_t *p;
+
+ wl_array_for_each (p, edge_constraints)
+ {
+ uint32_t constraint = *p;
+
+ switch (constraint)
+ {
+ case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_TOP:
+ new_state |= GDK_SURFACE_STATE_TOP_RESIZABLE;
+ break;
+ case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_RIGHT:
+ new_state |= GDK_SURFACE_STATE_RIGHT_RESIZABLE;
+ break;
+ case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_BOTTOM:
+ new_state |= GDK_SURFACE_STATE_BOTTOM_RESIZABLE;
+ break;
+ case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_LEFT:
+ new_state |= GDK_SURFACE_STATE_LEFT_RESIZABLE;
+ break;
+ default:
+ /* Unknown state */
+ break;
+ }
+ }
+
+ impl->pending.state |= new_state;
+}
+
+static const struct gtk_surface1_listener gtk_surface_listener = {
+ gtk_surface_configure,
+ gtk_surface_configure_edges
+};
+
+static void
+gdk_wayland_surface_init_gtk_surface (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkWaylandDisplay *display =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+
+ if (impl->display_server.gtk_surface != NULL)
+ return;
+ if (impl->display_server.xdg_surface == NULL)
+ return;
+ if (display->gtk_shell == NULL)
+ return;
+
+ impl->display_server.gtk_surface =
+ gtk_shell1_get_gtk_surface (display->gtk_shell,
+ impl->display_server.wl_surface);
+ gdk_surface_set_geometry_hints (window,
+ &impl->geometry_hints,
+ impl->geometry_mask);
+ gtk_surface1_add_listener (impl->display_server.gtk_surface,
+ >k_surface_listener,
+ window);
+}
+
+static void
+maybe_set_gtk_surface_modal (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ gdk_wayland_surface_init_gtk_surface (window);
+ if (impl->display_server.gtk_surface == NULL)
+ return;
+
+ if (window->modal_hint)
+ gtk_surface1_set_modal (impl->display_server.gtk_surface);
+ else
+ gtk_surface1_unset_modal (impl->display_server.gtk_surface);
+
+}
+
+static void
+gdk_wayland_surface_set_modal_hint (GdkSurface *window,
+ gboolean modal)
+{
+ window->modal_hint = modal;
+ maybe_set_gtk_surface_modal (window);
+}
+
+static void
+gdk_wayland_surface_set_skip_taskbar_hint (GdkSurface *window,
+ gboolean skips_taskbar)
+{
+}
+
+static void
+gdk_wayland_surface_set_skip_pager_hint (GdkSurface *window,
+ gboolean skips_pager)
+{
+}
+
+static void
+gdk_wayland_surface_set_urgency_hint (GdkSurface *window,
+ gboolean urgent)
+{
+}
+
+static void
+gdk_wayland_surface_set_geometry_hints (GdkSurface *window,
+ const GdkGeometry *geometry,
+ GdkSurfaceHints geom_mask)
+{
+ GdkSurfaceImplWayland *impl;
+ int width, height;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ impl->geometry_hints = *geometry;
+ impl->geometry_mask = geom_mask;
+
+ if (!impl->display_server.xdg_toplevel)
+ return;
+
+ if (geom_mask & GDK_HINT_MIN_SIZE)
+ {
+ width = MAX (0, geometry->min_width - (impl->margin_left + impl->margin_right));
+ height = MAX (0, geometry->min_height - (impl->margin_top + impl->margin_bottom));
+ }
+ else
+ {
+ width = 0;
+ height = 0;
+ }
+
+ zxdg_toplevel_v6_set_min_size (impl->display_server.xdg_toplevel, width, height);
+
+ if (geom_mask & GDK_HINT_MAX_SIZE)
+ {
+ width = MAX (0, geometry->max_width - (impl->margin_left + impl->margin_right));
+ height = MAX (0, geometry->max_height - (impl->margin_top + impl->margin_bottom));
+ }
+ else
+ {
+ width = 0;
+ height = 0;
+ }
+
+ zxdg_toplevel_v6_set_max_size (impl->display_server.xdg_toplevel, width, height);
+}
+
+static void
+gdk_wayland_surface_set_title (GdkSurface *window,
+ const gchar *title)
+{
+ GdkSurfaceImplWayland *impl;
+ const char *end;
+ gsize title_length;
+
+ g_return_if_fail (title != NULL);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (g_strcmp0 (impl->title, title) == 0)
+ return;
+
+ g_free (impl->title);
+
+ title_length = MIN (strlen (title), MAX_WL_BUFFER_SIZE);
+ if (g_utf8_validate (title, title_length, &end))
+ {
+ impl->title = g_malloc (end - title + 1);
+ memcpy (impl->title, title, end - title);
+ impl->title[end - title] = '\0';
+ }
+ else
+ {
+ impl->title = g_utf8_make_valid (title, title_length);
+ g_warning ("Invalid utf8 passed to gdk_surface_set_title: '%s'", title);
+ }
+
+ gdk_wayland_surface_sync_title (window);
+}
+
+static void
+gdk_wayland_surface_set_role (GdkSurface *window,
+ const gchar *role)
+{
+}
+
+static void
+gdk_wayland_surface_set_startup_id (GdkSurface *window,
+ const gchar *startup_id)
+{
+}
+
+static gboolean
+check_transient_for_loop (GdkSurface *window,
+ GdkSurface *parent)
+{
+ while (parent)
+ {
+ GdkSurfaceImplWayland *impl;
+
+ if (!GDK_IS_SURFACE_IMPL_WAYLAND(parent->impl))
+ return FALSE;
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (parent->impl);
+ if (impl->transient_for == window)
+ return TRUE;
+ parent = impl->transient_for;
+ }
+ return FALSE;
+}
+
+static void
+gdk_wayland_surface_set_transient_for (GdkSurface *window,
+ GdkSurface *parent)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkWaylandDisplay *display_wayland =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ GdkSurface *previous_parent;
+
+ g_assert (parent == NULL ||
+ gdk_surface_get_display (window) == gdk_surface_get_display (parent));
+
+ if (check_transient_for_loop (window, parent))
+ {
+ g_warning ("Setting %p transient for %p would create a loop", window, parent);
+ return;
+ }
+
+ unset_transient_for_exported (window);
+
+ if (impl->display_server.wl_subsurface)
+ unmap_subsurface (window);
+
+ previous_parent = impl->transient_for;
+ impl->transient_for = parent;
+
+ if (impl->hint == GDK_SURFACE_TYPE_HINT_DIALOG)
+ {
+ if (!parent)
+ _gdk_wayland_screen_add_orphan_dialog (window);
+ else if (!previous_parent)
+ display_wayland->orphan_dialogs =
+ g_list_remove (display_wayland->orphan_dialogs, window);
+ }
+ gdk_wayland_surface_sync_parent (window, NULL);
+ if (should_map_as_subsurface (window) &&
+ parent && gdk_surface_is_visible (window))
+ gdk_wayland_surface_create_subsurface (window);
+}
+
+static void
+gdk_wayland_surface_get_frame_extents (GdkSurface *window,
+ GdkRectangle *rect)
+{
+ *rect = (GdkRectangle) {
+ .x = window->x,
+ .y = window->y,
+ .width = window->width,
+ .height = window->height
+ };
+}
+
+static void
+gdk_wayland_surface_set_accept_focus (GdkSurface *window,
+ gboolean accept_focus)
+{
+}
+
+static void
+gdk_wayland_surface_set_focus_on_map (GdkSurface *window,
+ gboolean focus_on_map)
+{
+}
+
+static void
+gdk_wayland_surface_set_icon_list (GdkSurface *window,
+ GList *surfaces)
+{
+}
+
+static void
+gdk_wayland_surface_set_icon_name (GdkSurface *window,
+ const gchar *name)
+{
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+}
+
+static void
+gdk_wayland_surface_iconify (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ if (!impl->display_server.xdg_toplevel)
+ return;
+
+ zxdg_toplevel_v6_set_minimized (impl->display_server.xdg_toplevel);
+}
+
+static void
+gdk_wayland_surface_deiconify (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ gdk_surface_show (window);
+ else
+ /* Flip our client side flag, the real work happens on map. */
+ gdk_synthesize_window_state (window, GDK_SURFACE_STATE_ICONIFIED, 0);
+}
+
+static void
+gdk_wayland_surface_stick (GdkSurface *window)
+{
+}
+
+static void
+gdk_wayland_surface_unstick (GdkSurface *window)
+{
+}
+
+static void
+gdk_wayland_surface_maximize (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ _gdk_wayland_surface_save_size (window);
+ if (impl->display_server.xdg_toplevel)
+ zxdg_toplevel_v6_set_maximized (impl->display_server.xdg_toplevel);
+ else
+ gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_MAXIMIZED);
+}
+
+static void
+gdk_wayland_surface_unmaximize (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (impl->display_server.xdg_toplevel)
+ zxdg_toplevel_v6_unset_maximized (impl->display_server.xdg_toplevel);
+ else
+ gdk_synthesize_window_state (window, GDK_SURFACE_STATE_MAXIMIZED, 0);
+}
+
+static void
+gdk_wayland_surface_fullscreen_on_monitor (GdkSurface *window,
+ GdkMonitor *monitor)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ struct wl_output *output = ((GdkWaylandMonitor *)monitor)->output;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ _gdk_wayland_surface_save_size (window);
+ if (impl->display_server.xdg_toplevel)
+ {
+ zxdg_toplevel_v6_set_fullscreen (impl->display_server.xdg_toplevel, output);
+ }
+ else
+ {
+ gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
+ impl->initial_fullscreen_output = output;
+ }
+}
+
+static void
+gdk_wayland_surface_fullscreen (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ impl->initial_fullscreen_output = NULL;
+
+ _gdk_wayland_surface_save_size (window);
+ if (impl->display_server.xdg_toplevel)
+ zxdg_toplevel_v6_set_fullscreen (impl->display_server.xdg_toplevel, NULL);
+ else
+ gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
+}
+
+static void
+gdk_wayland_surface_unfullscreen (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ impl->initial_fullscreen_output = NULL;
+
+ if (impl->display_server.xdg_toplevel)
+ zxdg_toplevel_v6_unset_fullscreen (impl->display_server.xdg_toplevel);
+ else
+ gdk_synthesize_window_state (window, GDK_SURFACE_STATE_FULLSCREEN, 0);
+}
+
+static void
+gdk_wayland_surface_set_keep_above (GdkSurface *window, gboolean setting)
+{
+}
+
+static void
+gdk_wayland_surface_set_keep_below (GdkSurface *window, gboolean setting)
+{
+}
+
+static GdkSurface *
+gdk_wayland_surface_get_group (GdkSurface *window)
+{
+ return NULL;
+}
+
+static void
+gdk_wayland_surface_set_group (GdkSurface *window,
+ GdkSurface *leader)
+{
+}
+
+static void
+gdk_wayland_surface_set_decorations (GdkSurface *window,
+ GdkWMDecoration decorations)
+{
+}
+
+static gboolean
+gdk_wayland_surface_get_decorations (GdkSurface *window,
+ GdkWMDecoration *decorations)
+{
+ return FALSE;
+}
+
+static void
+gdk_wayland_surface_set_functions (GdkSurface *window,
+ GdkWMFunction functions)
+{
+}
+
+static void
+gdk_wayland_surface_begin_resize_drag (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GdkSurfaceImplWayland *impl;
+ GdkEventSequence *sequence;
+ uint32_t resize_edges, serial;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ switch (edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT;
+ break;
+
+ case GDK_SURFACE_EDGE_NORTH:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP;
+ break;
+
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT;
+ break;
+
+ case GDK_SURFACE_EDGE_WEST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT;
+ break;
+
+ case GDK_SURFACE_EDGE_EAST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT;
+ break;
+
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT;
+ break;
+
+ case GDK_SURFACE_EDGE_SOUTH:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM;
+ break;
+
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT;
+ break;
+
+ default:
+ g_warning ("gdk_surface_begin_resize_drag: bad resize edge %d!", edge);
+ return;
+ }
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (!impl->display_server.xdg_toplevel)
+ return;
+
+ serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_device_get_seat (device),
+ &sequence);
+
+ zxdg_toplevel_v6_resize (impl->display_server.xdg_toplevel,
+ gdk_wayland_device_get_wl_seat (device),
+ serial, resize_edges);
+
+ if (sequence)
+ gdk_wayland_device_unset_touch_grab (device, sequence);
+
+ /* This is needed since Wayland will absorb all the pointer events after the
+ * above function - FIXME: Is this always safe..?
+ */
+ gdk_seat_ungrab (gdk_device_get_seat (device));
+}
+
+static void
+gdk_wayland_surface_begin_move_drag (GdkSurface *window,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GdkSurfaceImplWayland *impl;
+ GdkEventSequence *sequence;
+ uint32_t serial;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (!impl->display_server.xdg_toplevel)
+ return;
+
+ serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_device_get_seat (device),
+ &sequence);
+ zxdg_toplevel_v6_move (impl->display_server.xdg_toplevel,
+ gdk_wayland_device_get_wl_seat (device),
+ serial);
+ if (sequence)
+ gdk_wayland_device_unset_touch_grab (device, sequence);
+
+ /* This is needed since Wayland will absorb all the pointer events after the
+ * above function - FIXME: Is this always safe..?
+ */
+ gdk_seat_ungrab (gdk_device_get_seat (device));
+}
+
+static void
+gdk_wayland_surface_set_opacity (GdkSurface *window,
+ gdouble opacity)
+{
+}
+
+static void
+gdk_wayland_surface_destroy_notify (GdkSurface *window)
+{
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ g_warning ("GdkSurface %p unexpectedly destroyed", window);
+ _gdk_surface_destroy (window, TRUE);
+ }
+
+ g_object_unref (window);
+}
+
+static gint
+gdk_wayland_surface_get_scale_factor (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return 1;
+
+ return impl->scale;
+}
+
+static void
+gdk_wayland_surface_set_opaque_region (GdkSurface *window,
+ cairo_region_t *region)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
+ impl->opaque_region = cairo_region_reference (region);
+ impl->opaque_region_dirty = TRUE;
+}
+
+static void
+gdk_wayland_surface_set_shadow_width (GdkSurface *window,
+ int left,
+ int right,
+ int top,
+ int bottom)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ gint new_width, new_height;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ /* Reconfigure window to keep the same window geometry */
+ new_width = window->width -
+ (impl->margin_left + impl->margin_right) + (left + right);
+ new_height = window->height -
+ (impl->margin_top + impl->margin_bottom) + (top + bottom);
+ gdk_wayland_surface_maybe_configure (window, new_width, new_height, impl->scale);
+
+ impl->margin_left = left;
+ impl->margin_right = right;
+ impl->margin_top = top;
+ impl->margin_bottom = bottom;
+}
+
+static gboolean
+gdk_wayland_surface_show_window_menu (GdkSurface *window,
+ GdkEvent *event)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ struct wl_seat *seat;
+ GdkWaylandDevice *device;
+ double x, y;
+ uint32_t serial;
+
+ switch ((guint) event->any.type)
+ {
+ case GDK_BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_TOUCH_BEGIN:
+ case GDK_TOUCH_END:
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (!impl->display_server.xdg_surface)
+ return FALSE;
+
+ device = GDK_WAYLAND_DEVICE (gdk_event_get_device (event));
+ seat = gdk_wayland_device_get_wl_seat (GDK_DEVICE (device));
+ gdk_event_get_coords (event, &x, &y);
+
+ serial = _gdk_wayland_device_get_implicit_grab_serial (device, event);
+ zxdg_toplevel_v6_show_window_menu (impl->display_server.xdg_toplevel,
+ seat, serial, x, y);
+ return TRUE;
+}
+
+static gboolean
+gdk_wayland_surface_supports_edge_constraints (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ struct gtk_surface1 *gtk_surface = impl->display_server.gtk_surface;
+
+ if (!gtk_surface)
+ return FALSE;
+
+ return gtk_surface1_get_version (gtk_surface) >= GTK_SURFACE1_CONFIGURE_EDGES_SINCE_VERSION;
+}
+
+static void
+_gdk_surface_impl_wayland_class_init (GdkSurfaceImplWaylandClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_CLASS (klass);
+
+ object_class->finalize = gdk_surface_impl_wayland_finalize;
+
+ impl_class->ref_cairo_surface = gdk_wayland_surface_ref_cairo_surface;
+ impl_class->create_similar_image_surface = gdk_wayland_surface_create_similar_image_surface;
+ impl_class->show = gdk_wayland_surface_show;
+ impl_class->hide = gdk_wayland_surface_hide;
+ impl_class->withdraw = gdk_surface_wayland_withdraw;
+ impl_class->set_events = gdk_surface_wayland_set_events;
+ impl_class->get_events = gdk_surface_wayland_get_events;
+ impl_class->raise = gdk_surface_wayland_raise;
+ impl_class->lower = gdk_surface_wayland_lower;
+ impl_class->restack_toplevel = gdk_surface_wayland_restack_toplevel;
+ impl_class->move_resize = gdk_surface_wayland_move_resize;
+ impl_class->move_to_rect = gdk_surface_wayland_move_to_rect;
+ impl_class->get_geometry = gdk_surface_wayland_get_geometry;
+ impl_class->get_root_coords = gdk_surface_wayland_get_root_coords;
+ impl_class->get_device_state = gdk_surface_wayland_get_device_state;
+ impl_class->shape_combine_region = gdk_surface_wayland_shape_combine_region;
+ impl_class->input_shape_combine_region = gdk_surface_wayland_input_shape_combine_region;
+ impl_class->destroy = gdk_wayland_surface_destroy;
+ impl_class->begin_paint = gdk_surface_impl_wayland_begin_paint;
+ impl_class->end_paint = gdk_surface_impl_wayland_end_paint;
+ impl_class->beep = gdk_surface_impl_wayland_beep;
+
+ impl_class->focus = gdk_wayland_surface_focus;
+ impl_class->set_type_hint = gdk_wayland_surface_set_type_hint;
+ impl_class->get_type_hint = gdk_wayland_surface_get_type_hint;
+ impl_class->set_modal_hint = gdk_wayland_surface_set_modal_hint;
+ impl_class->set_skip_taskbar_hint = gdk_wayland_surface_set_skip_taskbar_hint;
+ impl_class->set_skip_pager_hint = gdk_wayland_surface_set_skip_pager_hint;
+ impl_class->set_urgency_hint = gdk_wayland_surface_set_urgency_hint;
+ impl_class->set_geometry_hints = gdk_wayland_surface_set_geometry_hints;
+ impl_class->set_title = gdk_wayland_surface_set_title;
+ impl_class->set_role = gdk_wayland_surface_set_role;
+ impl_class->set_startup_id = gdk_wayland_surface_set_startup_id;
+ impl_class->set_transient_for = gdk_wayland_surface_set_transient_for;
+ impl_class->get_frame_extents = gdk_wayland_surface_get_frame_extents;
+ impl_class->set_accept_focus = gdk_wayland_surface_set_accept_focus;
+ impl_class->set_focus_on_map = gdk_wayland_surface_set_focus_on_map;
+ impl_class->set_icon_list = gdk_wayland_surface_set_icon_list;
+ impl_class->set_icon_name = gdk_wayland_surface_set_icon_name;
+ impl_class->iconify = gdk_wayland_surface_iconify;
+ impl_class->deiconify = gdk_wayland_surface_deiconify;
+ impl_class->stick = gdk_wayland_surface_stick;
+ impl_class->unstick = gdk_wayland_surface_unstick;
+ impl_class->maximize = gdk_wayland_surface_maximize;
+ impl_class->unmaximize = gdk_wayland_surface_unmaximize;
+ impl_class->fullscreen = gdk_wayland_surface_fullscreen;
+ impl_class->fullscreen_on_monitor = gdk_wayland_surface_fullscreen_on_monitor;
+ impl_class->unfullscreen = gdk_wayland_surface_unfullscreen;
+ impl_class->set_keep_above = gdk_wayland_surface_set_keep_above;
+ impl_class->set_keep_below = gdk_wayland_surface_set_keep_below;
+ impl_class->get_group = gdk_wayland_surface_get_group;
+ impl_class->set_group = gdk_wayland_surface_set_group;
+ impl_class->set_decorations = gdk_wayland_surface_set_decorations;
+ impl_class->get_decorations = gdk_wayland_surface_get_decorations;
+ impl_class->set_functions = gdk_wayland_surface_set_functions;
+ impl_class->begin_resize_drag = gdk_wayland_surface_begin_resize_drag;
+ impl_class->begin_move_drag = gdk_wayland_surface_begin_move_drag;
+ impl_class->set_opacity = gdk_wayland_surface_set_opacity;
+ impl_class->destroy_notify = gdk_wayland_surface_destroy_notify;
+ impl_class->register_dnd = _gdk_wayland_surface_register_dnd;
+ impl_class->drag_begin = _gdk_wayland_surface_drag_begin;
+ impl_class->get_scale_factor = gdk_wayland_surface_get_scale_factor;
+ impl_class->set_opaque_region = gdk_wayland_surface_set_opaque_region;
+ impl_class->set_shadow_width = gdk_wayland_surface_set_shadow_width;
+ impl_class->show_window_menu = gdk_wayland_surface_show_window_menu;
+ impl_class->create_gl_context = gdk_wayland_surface_create_gl_context;
+ impl_class->supports_edge_constraints = gdk_wayland_surface_supports_edge_constraints;
+
+ signals[COMMITTED] = g_signal_new (g_intern_static_string ("committed"),
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+}
+
+void
+_gdk_wayland_surface_set_grab_seat (GdkSurface *window,
+ GdkSeat *seat)
+{
+ GdkSurfaceImplWayland *impl;
+
+ g_return_if_fail (window != NULL);
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ impl->grab_input_seat = seat;
+}
+
+/**
+ * gdk_wayland_surface_new_subsurface: (constructor)
+ * @display: the display to create the window on
+ * @position: position relative to the transient window
+ *
+ * Creates a new subsurface window.
+ *
+ * Returns: (transfer full): the new #GdkSurface
+ **/
+GdkSurface *
+gdk_wayland_surface_new_subsurface (GdkDisplay *display,
+ const GdkRectangle *position)
+{
+ GdkSurfaceAttr attr;
+
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+ g_return_val_if_fail (position != NULL, NULL);
+
+ attr.wclass = GDK_INPUT_OUTPUT;
+ attr.x = position->x;
+ attr.y = position->y;
+ attr.width = position->width;
+ attr.height = position->height;
+ attr.window_type = GDK_SURFACE_SUBSURFACE;
+
+ return gdk_surface_new (display, NULL, &attr);
+}
+
+/**
+ * gdk_wayland_surface_get_wl_surface:
+ * @window: (type GdkWaylandSurface): a #GdkSurface
+ *
+ * Returns the Wayland surface of a #GdkSurface.
+ *
+ * Returns: (transfer none): a Wayland wl_surface
+ */
+struct wl_surface *
+gdk_wayland_surface_get_wl_surface (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), NULL);
+
+ return GDK_SURFACE_IMPL_WAYLAND (window->impl)->display_server.wl_surface;
+}
+
+struct wl_output *
+gdk_wayland_surface_get_wl_output (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl;
+
+ g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), NULL);
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ /* We pick the head of the list as this is the last entered output */
+ if (impl->display_server.outputs)
+ return (struct wl_output *) impl->display_server.outputs->data;
+
+ return NULL;
+}
+
+static struct wl_egl_window *
+gdk_wayland_surface_get_wl_egl_window (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (impl->display_server.egl_window == NULL)
+ {
+ impl->display_server.egl_window =
+ wl_egl_window_create (impl->display_server.wl_surface,
+ impl->wrapper->width * impl->scale,
+ impl->wrapper->height * impl->scale);
+ wl_surface_set_buffer_scale (impl->display_server.wl_surface, impl->scale);
+ }
+
+ return impl->display_server.egl_window;
+}
+
+EGLSurface
+gdk_wayland_surface_get_egl_surface (GdkSurface *window,
+ EGLConfig config)
+{
+ GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ GdkSurfaceImplWayland *impl;
+ struct wl_egl_window *egl_window;
+
+ g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), NULL);
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (impl->egl_surface == NULL)
+ {
+ egl_window = gdk_wayland_surface_get_wl_egl_window (window);
+
+ impl->egl_surface =
+ eglCreateWindowSurface (display->egl_display, config, egl_window, NULL);
+ }
+
+ return impl->egl_surface;
+}
+
+EGLSurface
+gdk_wayland_surface_get_dummy_egl_surface (GdkSurface *window,
+ EGLConfig config)
+{
+ GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ GdkSurfaceImplWayland *impl;
+
+ g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), NULL);
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (impl->dummy_egl_surface == NULL)
+ {
+ impl->display_server.dummy_egl_window =
+ wl_egl_window_create (impl->display_server.wl_surface, 1, 1);
+
+ impl->dummy_egl_surface =
+ eglCreateWindowSurface (display->egl_display, config, impl->display_server.dummy_egl_window, NULL);
+ }
+
+ return impl->dummy_egl_surface;
+}
+
+struct gtk_surface1 *
+gdk_wayland_surface_get_gtk_surface (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), NULL);
+
+ return GDK_SURFACE_IMPL_WAYLAND (window->impl)->display_server.gtk_surface;
+}
+
+/**
+ * gdk_wayland_surface_set_use_custom_surface:
+ * @window: (type GdkWaylandSurface): a #GdkSurface
+ *
+ * Marks a #GdkSurface as a custom Wayland surface. The application is
+ * expected to register the surface as some type of surface using
+ * some Wayland interface.
+ *
+ * A good example would be writing a panel or on-screen-keyboard as an
+ * out-of-process helper - as opposed to having those in the compositor
+ * process. In this case the underlying surface isn’t an xdg_shell
+ * surface and the panel or OSK client need to identify the wl_surface
+ * as a panel or OSK to the compositor. The assumption is that the
+ * compositor will expose a private interface to the special client
+ * that lets the client identify the wl_surface as a panel or such.
+ *
+ * This function should be called before a #GdkSurface is shown. This is
+ * best done by connecting to the #GtkWidget::realize signal:
+ *
+ * |[<!-- language="C" -->
+ * static void
+ * widget_realize_cb (GtkWidget *widget)
+ * {
+ * GdkSurface *window;
+ * struct wl_surface *surface;
+ * struct input_panel_surface *ip_surface;
+ *
+ * window = gtk_widget_get_window (widget);
+ * gdk_wayland_surface_set_custom_surface (window);
+ *
+ * surface = gdk_wayland_surface_get_wl_surface (window);
+ * ip_surface = input_panel_get_input_panel_surface (input_panel, surface);
+ * input_panel_surface_set_panel (ip_surface);
+ * }
+ *
+ * static void
+ * setup_window (GtkWindow *window)
+ * {
+ * g_signal_connect (window, "realize", G_CALLBACK (widget_realize_cb), NULL);
+ * }
+ * ]|
+ */
+void
+gdk_wayland_surface_set_use_custom_surface (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl;
+
+ g_return_if_fail (GDK_IS_WAYLAND_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (!impl->display_server.wl_surface)
+ gdk_wayland_surface_create_surface (window);
+
+ impl->use_custom_surface = TRUE;
+}
+
+static void
+maybe_set_gtk_surface_dbus_properties (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ if (impl->application.was_set)
+ return;
+
+ if (impl->application.application_id == NULL &&
+ impl->application.app_menu_path == NULL &&
+ impl->application.menubar_path == NULL &&
+ impl->application.window_object_path == NULL &&
+ impl->application.application_object_path == NULL &&
+ impl->application.unique_bus_name == NULL)
+ return;
+
+ gdk_wayland_surface_init_gtk_surface (window);
+ if (impl->display_server.gtk_surface == NULL)
+ return;
+
+ gtk_surface1_set_dbus_properties (impl->display_server.gtk_surface,
+ impl->application.application_id,
+ impl->application.app_menu_path,
+ impl->application.menubar_path,
+ impl->application.window_object_path,
+ impl->application.application_object_path,
+ impl->application.unique_bus_name);
+ impl->application.was_set = TRUE;
+}
+
+void
+gdk_wayland_surface_set_dbus_properties_libgtk_only (GdkSurface *window,
+ const char *application_id,
+ const char *app_menu_path,
+ const char *menubar_path,
+ const char *window_object_path,
+ const char *application_object_path,
+ const char *unique_bus_name)
+{
+ GdkSurfaceImplWayland *impl;
+
+ g_return_if_fail (GDK_IS_WAYLAND_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ impl->application.application_id = g_strdup (application_id);
+ impl->application.app_menu_path = g_strdup (app_menu_path);
+ impl->application.menubar_path = g_strdup (menubar_path);
+ impl->application.window_object_path = g_strdup (window_object_path);
+ impl->application.application_object_path =
+ g_strdup (application_object_path);
+ impl->application.unique_bus_name = g_strdup (unique_bus_name);
+
+ maybe_set_gtk_surface_dbus_properties (window);
+}
+
+void
+_gdk_wayland_surface_offset_next_wl_buffer (GdkSurface *window,
+ int x,
+ int y)
+{
+ GdkSurfaceImplWayland *impl;
+
+ g_return_if_fail (GDK_IS_WAYLAND_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ impl->pending_buffer_offset_x = x;
+ impl->pending_buffer_offset_y = y;
+}
+
+static void
+xdg_exported_handle (void *data,
+ struct zxdg_exported_v1 *zxdg_exported_v1,
+ const char *handle)
+{
+ GdkSurface *window = data;
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ impl->exported.callback (window, handle, impl->exported.user_data);
+ g_clear_pointer (&impl->exported.user_data,
+ impl->exported.destroy_func);
+}
+
+static const struct zxdg_exported_v1_listener xdg_exported_listener = {
+ xdg_exported_handle
+};
+
+/**
+ * GdkWaylandSurfaceExported:
+ * @window: the #GdkSurface that is exported
+ * @handle: the handle
+ * @user_data: user data that was passed to gdk_wayland_surface_export_handle()
+ *
+ * Callback that gets called when the handle for a window has been
+ * obtained from the Wayland compositor. The handle can be passed
+ * to other processes, for the purpose of marking windows as transient
+ * for out-of-process surfaces.
+ */
+
+static gboolean
+gdk_wayland_surface_is_exported (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ return !!impl->display_server.xdg_exported;
+}
+
+/**
+ * gdk_wayland_surface_export_handle:
+ * @window: the #GdkSurface to obtain a handle for
+ * @callback: callback to call with the handle
+ * @user_data: user data for @callback
+ * @destroy_func: destroy notify for @user_data
+ *
+ * Asynchronously obtains a handle for a surface that can be passed
+ * to other processes. When the handle has been obtained, @callback
+ * will be called.
+ *
+ * It is an error to call this function on a window that is already
+ * exported.
+ *
+ * When the handle is no longer needed, gdk_wayland_surface_unexport_handle()
+ * should be called to clean up resources.
+ *
+ * The main purpose for obtaining a handle is to mark a surface
+ * from another window as transient for this one, see
+ * gdk_wayland_surface_set_transient_for_exported().
+ *
+ * Note that this API depends on an unstable Wayland protocol,
+ * and thus may require changes in the future.
+ *
+ * Return value: %TRUE if the handle has been requested, %FALSE if
+ * an error occurred.
+ */
+gboolean
+gdk_wayland_surface_export_handle (GdkSurface *window,
+ GdkWaylandSurfaceExported callback,
+ gpointer user_data,
+ GDestroyNotify destroy_func)
+{
+ GdkSurfaceImplWayland *impl;
+ GdkWaylandDisplay *display_wayland;
+ GdkDisplay *display = gdk_surface_get_display (window);
+ struct zxdg_exported_v1 *xdg_exported;
+
+ g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), FALSE);
+ g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ display_wayland = GDK_WAYLAND_DISPLAY (display);
+
+ g_return_val_if_fail (!impl->display_server.xdg_exported, FALSE);
+
+ if (!display_wayland->xdg_exporter)
+ {
+ g_warning ("Server is missing xdg_foreign support");
+ return FALSE;
+ }
+
+ xdg_exported = zxdg_exporter_v1_export (display_wayland->xdg_exporter,
+ impl->display_server.wl_surface);
+ zxdg_exported_v1_add_listener (xdg_exported, &xdg_exported_listener, window);
+
+ impl->display_server.xdg_exported = xdg_exported;
+ impl->exported.callback = callback;
+ impl->exported.user_data = user_data;
+ impl->exported.destroy_func = destroy_func;
+
+ return TRUE;
+}
+
+/**
+ * gdk_wayland_surface_unexport_handle:
+ * @window: the #GdkSurface to unexport
+ *
+ * Destroys the handle that was obtained with
+ * gdk_wayland_surface_export_handle().
+ *
+ * It is an error to call this function on a window that
+ * does not have a handle.
+ *
+ * Note that this API depends on an unstable Wayland protocol,
+ * and thus may require changes in the future.
+ */
+void
+gdk_wayland_surface_unexport_handle (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl;
+
+ g_return_if_fail (GDK_IS_WAYLAND_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ g_return_if_fail (impl->display_server.xdg_exported);
+
+ g_clear_pointer (&impl->display_server.xdg_exported,
+ zxdg_exported_v1_destroy);
+ g_clear_pointer (&impl->exported.user_data,
+ impl->exported.destroy_func);
+}
+
+static void
+unset_transient_for_exported (GdkSurface *window)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+
+ g_clear_pointer (&impl->imported_transient_for, zxdg_imported_v1_destroy);
+}
+
+static void
+xdg_imported_destroyed (void *data,
+ struct zxdg_imported_v1 *zxdg_imported_v1)
+{
+ GdkSurface *window = data;
+
+ unset_transient_for_exported (window);
+}
+
+static const struct zxdg_imported_v1_listener xdg_imported_listener = {
+ xdg_imported_destroyed,
+};
+
+/**
+ * gdk_wayland_surface_set_transient_for_exported:
+ * @window: the #GdkSurface to make as transient
+ * @parent_handle_str: an exported handle for a surface
+ *
+ * Marks @window as transient for the surface to which the given
+ * @parent_handle_str refers. Typically, the handle will originate
+ * from a gdk_wayland_surface_export_handle() call in another process.
+ *
+ * Note that this API depends on an unstable Wayland protocol,
+ * and thus may require changes in the future.
+ *
+ * Return value: %TRUE if the window has been marked as transient,
+ * %FALSE if an error occurred.
+ */
+gboolean
+gdk_wayland_surface_set_transient_for_exported (GdkSurface *window,
+ char *parent_handle_str)
+{
+ GdkSurfaceImplWayland *impl;
+ GdkWaylandDisplay *display_wayland;
+ GdkDisplay *display = gdk_surface_get_display (window);
+
+ g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), FALSE);
+ g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
+ g_return_val_if_fail (!should_map_as_subsurface (window) &&
+ !should_map_as_popup (window), FALSE);
+
+ impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ display_wayland = GDK_WAYLAND_DISPLAY (display);
+
+ if (!display_wayland->xdg_importer)
+ {
+ g_warning ("Server is missing xdg_foreign support");
+ return FALSE;
+ }
+
+ gdk_surface_set_transient_for (window, NULL);
+
+ impl->imported_transient_for =
+ zxdg_importer_v1_import (display_wayland->xdg_importer, parent_handle_str);
+ zxdg_imported_v1_add_listener (impl->imported_transient_for,
+ &xdg_imported_listener,
+ window);
+
+ gdk_wayland_surface_sync_parent_of_imported (window);
+
+ return TRUE;
+}
+
+static struct zwp_keyboard_shortcuts_inhibitor_v1 *
+gdk_wayland_surface_get_inhibitor (GdkSurfaceImplWayland *impl,
+ struct wl_seat *seat)
+{
+ return g_hash_table_lookup (impl->shortcuts_inhibitors, seat);
+}
+
+void
+gdk_wayland_surface_inhibit_shortcuts (GdkSurface *window,
+ GdkSeat *gdk_seat)
+{
+ GdkSurfaceImplWayland *impl= GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
+ struct wl_surface *surface = impl->display_server.wl_surface;
+ struct wl_seat *seat = gdk_wayland_seat_get_wl_seat (gdk_seat);
+ struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
+
+ if (display->keyboard_shortcuts_inhibit == NULL)
+ return;
+
+ if (gdk_wayland_surface_get_inhibitor (impl, seat))
+ return; /* Already inhibitted */
+
+ inhibitor =
+ zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts (
+ display->keyboard_shortcuts_inhibit, surface, seat);
+
+ g_hash_table_insert (impl->shortcuts_inhibitors, seat, inhibitor);
+}
+
+void
+gdk_wayland_surface_restore_shortcuts (GdkSurface *window,
+ GdkSeat *gdk_seat)
+{
+ GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
+ struct wl_seat *seat = gdk_wayland_seat_get_wl_seat (gdk_seat);
+ struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
+
+ inhibitor = gdk_wayland_surface_get_inhibitor (impl, seat);
+ if (inhibitor == NULL)
+ return; /* Not inhibitted */
+
+ zwp_keyboard_shortcuts_inhibitor_v1_destroy (inhibitor);
+ g_hash_table_remove (impl->shortcuts_inhibitors, seat);
+}
+
#include "gdkinternals.h"
#include "gdkwaylanddisplay.h"
-#include "gdkwaylandwindow.h"
+#include "gdkwaylandsurface.h"
#include "gdkprivate-wayland.h"
G_DEFINE_TYPE (GdkWaylandVulkanContext, gdk_wayland_vulkan_context, GDK_TYPE_VULKAN_CONTEXT)
#include <gdk/wayland/gdkwaylanddevice.h>
#include <gdk/wayland/gdkwaylanddisplay.h>
#include <gdk/wayland/gdkwaylandmonitor.h>
-#include <gdk/wayland/gdkwaylandwindow.h>
+#include <gdk/wayland/gdkwaylandsurface.h>
#include <gdk/wayland/gdkwaylandglcontext.h>
#undef __GDKWAYLAND_H_INSIDE__
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2013 Jan Arne Petersen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_WAYLAND_SURFACE_H__
+#define __GDK_WAYLAND_SURFACE_H__
+
+#if !defined (__GDKWAYLAND_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdkwayland.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+#include <wayland-client.h>
+
+G_BEGIN_DECLS
+
+#ifdef GDK_COMPILATION
+typedef struct _GdkWaylandSurface GdkWaylandSurface;
+#else
+typedef GdkSurface GdkWaylandSurface;
+#endif
+typedef struct _GdkWaylandSurfaceClass GdkWaylandSurfaceClass;
+
+#define GDK_TYPE_WAYLAND_SURFACE (gdk_wayland_surface_get_type())
+#define GDK_WAYLAND_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_SURFACE, GdkWaylandSurface))
+#define GDK_WAYLAND_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WAYLAND_SURFACE, GdkWaylandSurfaceClass))
+#define GDK_IS_WAYLAND_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_SURFACE))
+#define GDK_IS_WAYLAND_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WAYLAND_SURFACE))
+#define GDK_WAYLAND_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WAYLAND_SURFACE, GdkWaylandSurfaceClass))
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_wayland_surface_get_type (void);
+
+GDK_AVAILABLE_IN_ALL
+GdkSurface * gdk_wayland_surface_new_subsurface (GdkDisplay *display,
+ const GdkRectangle *position);
+GDK_AVAILABLE_IN_ALL
+struct wl_surface *gdk_wayland_surface_get_wl_surface (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_wayland_surface_set_use_custom_surface (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_wayland_surface_set_dbus_properties_libgtk_only (GdkSurface *window,
+ const char *application_id,
+ const char *app_menu_path,
+ const char *menubar_path,
+ const char *window_object_path,
+ const char *application_object_path,
+ const char *unique_bus_name);
+
+typedef void (*GdkWaylandSurfaceExported) (GdkSurface *window,
+ const char *handle,
+ gpointer user_data);
+
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_wayland_surface_export_handle (GdkSurface *window,
+ GdkWaylandSurfaceExported callback,
+ gpointer user_data,
+ GDestroyNotify destroy_func);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_wayland_surface_unexport_handle (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+gboolean gdk_wayland_surface_set_transient_for_exported (GdkSurface *window,
+ char *parent_handle_str);
+
+void gdk_wayland_surface_announce_csd (GdkSurface *window);
+
+G_END_DECLS
+
+#endif /* __GDK_WAYLAND_SURFACE_H__ */
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 2013 Jan Arne Petersen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_WAYLAND_SURFACE_H__
-#define __GDK_WAYLAND_SURFACE_H__
-
-#if !defined (__GDKWAYLAND_H_INSIDE__) && !defined (GDK_COMPILATION)
-#error "Only <gdk/gdkwayland.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-#include <wayland-client.h>
-
-G_BEGIN_DECLS
-
-#ifdef GDK_COMPILATION
-typedef struct _GdkWaylandSurface GdkWaylandSurface;
-#else
-typedef GdkSurface GdkWaylandSurface;
-#endif
-typedef struct _GdkWaylandSurfaceClass GdkWaylandSurfaceClass;
-
-#define GDK_TYPE_WAYLAND_SURFACE (gdk_wayland_surface_get_type())
-#define GDK_WAYLAND_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_SURFACE, GdkWaylandSurface))
-#define GDK_WAYLAND_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WAYLAND_SURFACE, GdkWaylandSurfaceClass))
-#define GDK_IS_WAYLAND_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_SURFACE))
-#define GDK_IS_WAYLAND_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WAYLAND_SURFACE))
-#define GDK_WAYLAND_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WAYLAND_SURFACE, GdkWaylandSurfaceClass))
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_wayland_surface_get_type (void);
-
-GDK_AVAILABLE_IN_ALL
-GdkSurface * gdk_wayland_surface_new_subsurface (GdkDisplay *display,
- const GdkRectangle *position);
-GDK_AVAILABLE_IN_ALL
-struct wl_surface *gdk_wayland_surface_get_wl_surface (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_wayland_surface_set_use_custom_surface (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_wayland_surface_set_dbus_properties_libgtk_only (GdkSurface *window,
- const char *application_id,
- const char *app_menu_path,
- const char *menubar_path,
- const char *window_object_path,
- const char *application_object_path,
- const char *unique_bus_name);
-
-typedef void (*GdkWaylandSurfaceExported) (GdkSurface *window,
- const char *handle,
- gpointer user_data);
-
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_wayland_surface_export_handle (GdkSurface *window,
- GdkWaylandSurfaceExported callback,
- gpointer user_data,
- GDestroyNotify destroy_func);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_wayland_surface_unexport_handle (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-gboolean gdk_wayland_surface_set_transient_for_exported (GdkSurface *window,
- char *parent_handle_str);
-
-void gdk_wayland_surface_announce_csd (GdkSurface *window);
-
-G_END_DECLS
-
-#endif /* __GDK_WAYLAND_SURFACE_H__ */
+++ /dev/null
-/*
- * Copyright © 2010 Intel Corporation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include "gdk.h"
-#include "gdkwayland.h"
-
-#include "gdkwindow.h"
-#include "gdkwindowimpl.h"
-#include "gdkdisplay-wayland.h"
-#include "gdkglcontext-wayland.h"
-#include "gdkframeclockprivate.h"
-#include "gdkprivate-wayland.h"
-#include "gdkinternals.h"
-#include "gdkdeviceprivate.h"
-#include "gdkprivate-wayland.h"
-#include "gdkmonitor-wayland.h"
-#include <wayland/xdg-shell-unstable-v6-client-protocol.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-enum {
- COMMITTED,
-
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL];
-
-#define WINDOW_IS_TOPLEVEL(window) \
- (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD)
-
-#define MAX_WL_BUFFER_SIZE (4083) /* 4096 minus header, string argument length and NUL byte */
-
-typedef struct _GdkWaylandSurface GdkWaylandSurface;
-typedef struct _GdkWaylandSurfaceClass GdkWaylandSurfaceClass;
-
-struct _GdkWaylandSurface
-{
- GdkSurface parent;
-};
-
-struct _GdkWaylandSurfaceClass
-{
- GdkSurfaceClass parent_class;
-};
-
-G_DEFINE_TYPE (GdkWaylandSurface, gdk_wayland_surface, GDK_TYPE_SURFACE)
-
-static void
-gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *wayland_surface_class)
-{
-}
-
-static void
-gdk_wayland_surface_init (GdkWaylandSurface *wayland_surface)
-{
-}
-
-#define GDK_TYPE_SURFACE_IMPL_WAYLAND (_gdk_surface_impl_wayland_get_type ())
-#define GDK_SURFACE_IMPL_WAYLAND(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL_WAYLAND, GdkSurfaceImplWayland))
-#define GDK_SURFACE_IMPL_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL_WAYLAND, GdkSurfaceImplWaylandClass))
-#define GDK_IS_SURFACE_IMPL_WAYLAND(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL_WAYLAND))
-#define GDK_IS_SURFACE_IMPL_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL_WAYLAND))
-#define GDK_SURFACE_IMPL_WAYLAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL_WAYLAND, GdkSurfaceImplWaylandClass))
-
-typedef struct _GdkSurfaceImplWayland GdkSurfaceImplWayland;
-typedef struct _GdkSurfaceImplWaylandClass GdkSurfaceImplWaylandClass;
-
-typedef enum _PositionMethod
-{
- POSITION_METHOD_NONE,
- POSITION_METHOD_MOVE_RESIZE,
- POSITION_METHOD_MOVE_TO_RECT
-} PositionMethod;
-
-struct _GdkSurfaceImplWayland
-{
- GdkSurfaceImpl parent_instance;
-
- GdkSurface *wrapper;
-
- struct {
- /* The wl_outputs that this window currently touches */
- GSList *outputs;
-
- struct wl_surface *wl_surface;
- struct zxdg_surface_v6 *xdg_surface;
- struct zxdg_toplevel_v6 *xdg_toplevel;
- struct zxdg_popup_v6 *xdg_popup;
- struct gtk_surface1 *gtk_surface;
- struct wl_subsurface *wl_subsurface;
- struct wl_egl_window *egl_window;
- struct wl_egl_window *dummy_egl_window;
- struct zxdg_exported_v1 *xdg_exported;
- struct org_kde_kwin_server_decoration *server_decoration;
- } display_server;
-
- EGLSurface egl_surface;
- EGLSurface dummy_egl_surface;
-
- unsigned int initial_configure_received : 1;
- unsigned int mapped : 1;
- unsigned int use_custom_surface : 1;
- unsigned int pending_buffer_attached : 1;
- unsigned int pending_commit : 1;
- unsigned int awaiting_frame : 1;
- GdkSurfaceTypeHint hint;
- GdkSurface *transient_for;
- GdkSurface *popup_parent;
- PositionMethod position_method;
-
- cairo_surface_t *staging_cairo_surface;
- cairo_surface_t *committed_cairo_surface;
- cairo_surface_t *backfill_cairo_surface;
-
- int pending_buffer_offset_x;
- int pending_buffer_offset_y;
-
- gchar *title;
-
- struct {
- gboolean was_set;
-
- gchar *application_id;
- gchar *app_menu_path;
- gchar *menubar_path;
- gchar *window_object_path;
- gchar *application_object_path;
- gchar *unique_bus_name;
- } application;
-
- GdkGeometry geometry_hints;
- GdkSurfaceHints geometry_mask;
-
- GdkSeat *grab_input_seat;
-
- gint64 pending_frame_counter;
- guint32 scale;
-
- int margin_left;
- int margin_right;
- int margin_top;
- int margin_bottom;
- gboolean margin_dirty;
-
- struct wl_output *initial_fullscreen_output;
-
- cairo_region_t *opaque_region;
- gboolean opaque_region_dirty;
-
- cairo_region_t *input_region;
- gboolean input_region_dirty;
-
- cairo_region_t *staged_updates_region;
-
- int saved_width;
- int saved_height;
-
- gulong parent_surface_committed_handler;
-
- struct {
- GdkRectangle rect;
- GdkGravity rect_anchor;
- GdkGravity window_anchor;
- GdkAnchorHints anchor_hints;
- gint rect_anchor_dx;
- gint rect_anchor_dy;
- } pending_move_to_rect;
-
- struct {
- int width;
- int height;
- GdkSurfaceState state;
- } pending;
-
- struct {
- GdkWaylandSurfaceExported callback;
- gpointer user_data;
- GDestroyNotify destroy_func;
- } exported;
-
- struct zxdg_imported_v1 *imported_transient_for;
- GHashTable *shortcuts_inhibitors;
-};
-
-struct _GdkSurfaceImplWaylandClass
-{
- GdkSurfaceImplClass parent_class;
-};
-
-static void gdk_wayland_surface_maybe_configure (GdkSurface *window,
- int width,
- int height,
- int scale);
-
-static void maybe_set_gtk_surface_dbus_properties (GdkSurface *window);
-static void maybe_set_gtk_surface_modal (GdkSurface *window);
-
-static void gdk_surface_request_transient_parent_commit (GdkSurface *window);
-
-static void gdk_wayland_surface_sync_margin (GdkSurface *window);
-static void gdk_wayland_surface_sync_input_region (GdkSurface *window);
-static void gdk_wayland_surface_sync_opaque_region (GdkSurface *window);
-
-static void unset_transient_for_exported (GdkSurface *window);
-
-static void calculate_moved_to_rect_result (GdkSurface *window,
- int x,
- int y,
- int width,
- int height,
- GdkRectangle *flipped_rect,
- GdkRectangle *final_rect,
- gboolean *flipped_x,
- gboolean *flipped_y);
-
-static gboolean gdk_wayland_surface_is_exported (GdkSurface *window);
-
-GType _gdk_surface_impl_wayland_get_type (void);
-
-G_DEFINE_TYPE (GdkSurfaceImplWayland, _gdk_surface_impl_wayland, GDK_TYPE_SURFACE_IMPL)
-
-static void
-_gdk_surface_impl_wayland_init (GdkSurfaceImplWayland *impl)
-{
- impl->scale = 1;
- impl->initial_fullscreen_output = NULL;
- impl->saved_width = -1;
- impl->saved_height = -1;
-}
-
-static void
-_gdk_wayland_screen_add_orphan_dialog (GdkSurface *window)
-{
- GdkWaylandDisplay *display_wayland =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
-
- if (!g_list_find (display_wayland->orphan_dialogs, window))
- display_wayland->orphan_dialogs =
- g_list_prepend (display_wayland->orphan_dialogs, window);
-}
-
-static void
-drop_cairo_surfaces (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
- g_clear_pointer (&impl->backfill_cairo_surface, cairo_surface_destroy);
-
- /* We nullify this so if a buffer release comes in later, we won't
- * try to reuse that buffer since it's no longer suitable
- */
- impl->committed_cairo_surface = NULL;
-}
-
-static void
-_gdk_wayland_surface_save_size (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (window->state & (GDK_SURFACE_STATE_FULLSCREEN | GDK_SURFACE_STATE_MAXIMIZED))
- return;
-
- impl->saved_width = window->width - impl->margin_left - impl->margin_right;
- impl->saved_height = window->height - impl->margin_top - impl->margin_bottom;
-}
-
-static void
-_gdk_wayland_surface_clear_saved_size (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (window->state & (GDK_SURFACE_STATE_FULLSCREEN | GDK_SURFACE_STATE_MAXIMIZED))
- return;
-
- impl->saved_width = -1;
- impl->saved_height = -1;
-}
-
-/*
- * gdk_wayland_surface_update_size:
- * @drawable: a #GdkDrawableImplWayland.
- *
- * Updates the state of the drawable (in particular the drawable's
- * cairo surface) when its size has changed.
- */
-static void
-gdk_wayland_surface_update_size (GdkSurface *window,
- int32_t width,
- int32_t height,
- int scale)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkRectangle area;
- cairo_region_t *region;
-
- if ((window->width == width) &&
- (window->height == height) &&
- (impl->scale == scale))
- return;
-
- drop_cairo_surfaces (window);
-
- window->width = width;
- window->height = height;
- impl->scale = scale;
-
- if (impl->display_server.egl_window)
- wl_egl_window_resize (impl->display_server.egl_window, width * scale, height * scale, 0, 0);
- if (impl->display_server.wl_surface)
- wl_surface_set_buffer_scale (impl->display_server.wl_surface, scale);
-
- area.x = 0;
- area.y = 0;
- area.width = window->width;
- area.height = window->height;
-
- region = cairo_region_create_rectangle (&area);
- _gdk_surface_invalidate_for_expose (window, region);
- cairo_region_destroy (region);
-}
-
-static const gchar *
-get_default_title (void)
-{
- const char *title;
-
- title = g_get_application_name ();
- if (!title)
- title = g_get_prgname ();
- if (!title)
- title = "";
-
- return title;
-}
-
-static void
-fill_presentation_time_from_frame_time (GdkFrameTimings *timings,
- guint32 frame_time)
-{
- /* The timestamp in a wayland frame is a msec time value that in some
- * way reflects the time at which the server started drawing the frame.
- * This is not useful from our perspective.
- *
- * However, for the DRM backend of Weston, on reasonably recent
- * Linux, we know that the time is the
- * clock_gettime (CLOCK_MONOTONIC) value at the vblank, and that
- * backend starts drawing immediately after receiving the vblank
- * notification. If we detect this, and make the assumption that the
- * compositor will finish drawing before the next vblank, we can
- * then determine the presentation time as the frame time we
- * received plus one refresh interval.
- *
- * If a backend is using clock_gettime(CLOCK_MONOTONIC), but not
- * picking values right at the vblank, then the presentation times
- * we compute won't be accurate, but not really worse than then
- * the alternative of not providing presentation times at all.
- *
- * The complexity here is dealing with the fact that we receive
- * only the low 32 bits of the CLOCK_MONOTONIC value in milliseconds.
- */
- gint64 now_monotonic = g_get_monotonic_time ();
- gint64 now_monotonic_msec = now_monotonic / 1000;
- uint32_t now_monotonic_low = (uint32_t)now_monotonic_msec;
-
- if (frame_time - now_monotonic_low < 1000 ||
- frame_time - now_monotonic_low > (uint32_t)-1000)
- {
- /* Timestamp we received is within one second of the current time.
- */
- gint64 last_frame_time = now_monotonic + (gint64)1000 * (gint32)(frame_time - now_monotonic_low);
- if ((gint32)now_monotonic_low < 0 && (gint32)frame_time > 0)
- last_frame_time += (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
- else if ((gint32)now_monotonic_low > 0 && (gint32)frame_time < 0)
- last_frame_time -= (gint64)1000 * G_GINT64_CONSTANT(0x100000000);
-
- timings->presentation_time = last_frame_time + timings->refresh_interval;
- }
-}
-
-static void
-read_back_cairo_surface (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- cairo_t *cr;
- cairo_region_t *paint_region = NULL;
-
- if (!impl->backfill_cairo_surface)
- goto out;
-
- paint_region = cairo_region_copy (window->clip_region);
- cairo_region_subtract (paint_region, impl->staged_updates_region);
-
- if (cairo_region_is_empty (paint_region))
- goto out;
-
- cr = cairo_create (impl->staging_cairo_surface);
- cairo_set_source_surface (cr, impl->backfill_cairo_surface, 0, 0);
- gdk_cairo_region (cr, paint_region);
- cairo_clip (cr);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint (cr);
- cairo_destroy (cr);
- cairo_surface_flush (impl->staging_cairo_surface);
-
-out:
- g_clear_pointer (&paint_region, cairo_region_destroy);
- g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
- g_clear_pointer (&impl->backfill_cairo_surface, cairo_surface_destroy);
-}
-
-static void
-frame_callback (void *data,
- struct wl_callback *callback,
- uint32_t time)
-{
- GdkSurface *window = data;
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkWaylandDisplay *display_wayland =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- GdkFrameClock *clock = gdk_surface_get_frame_clock (window);
- GdkFrameTimings *timings;
-
- GDK_DISPLAY_NOTE (GDK_DISPLAY (display_wayland), EVENTS, g_message ("frame %p", window));
-
- wl_callback_destroy (callback);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (!impl->awaiting_frame)
- return;
-
- impl->awaiting_frame = FALSE;
- _gdk_frame_clock_thaw (clock);
-
- timings = gdk_frame_clock_get_timings (clock, impl->pending_frame_counter);
- impl->pending_frame_counter = 0;
-
- if (timings == NULL)
- return;
-
- timings->refresh_interval = 16667; /* default to 1/60th of a second */
- if (impl->display_server.outputs)
- {
- /* We pick a random output out of the outputs that the window touches
- * The rate here is in milli-hertz */
- int refresh_rate =
- gdk_wayland_display_get_output_refresh_rate (display_wayland,
- impl->display_server.outputs->data);
- if (refresh_rate != 0)
- timings->refresh_interval = G_GINT64_CONSTANT(1000000000) / refresh_rate;
- }
-
- fill_presentation_time_from_frame_time (timings, time);
-
- timings->complete = TRUE;
-
-#ifdef G_ENABLE_DEBUG
- if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0)
- _gdk_frame_clock_debug_print_timings (clock, timings);
-#endif
-}
-
-static const struct wl_callback_listener frame_listener = {
- frame_callback
-};
-
-static void
-on_frame_clock_before_paint (GdkFrameClock *clock,
- GdkSurface *window)
-{
- GdkFrameTimings *timings = gdk_frame_clock_get_current_timings (clock);
- gint64 presentation_time;
- gint64 refresh_interval;
-
- if (window->update_freeze_count > 0)
- return;
-
- gdk_frame_clock_get_refresh_info (clock,
- timings->frame_time,
- &refresh_interval, &presentation_time);
-
- if (presentation_time != 0)
- {
- /* Assume the algorithm used by the DRM backend of Weston - it
- * starts drawing at the next vblank after receiving the commit
- * for this frame, and presentation occurs at the vblank
- * after that.
- */
- timings->predicted_presentation_time = presentation_time + refresh_interval;
- }
- else
- {
- /* As above, but we don't actually know the phase of the vblank,
- * so just assume that we're half way through a refresh cycle.
- */
- timings->predicted_presentation_time = timings->frame_time + refresh_interval / 2 + refresh_interval;
- }
-}
-
-static void
-on_frame_clock_after_paint (GdkFrameClock *clock,
- GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- struct wl_callback *callback;
-
- if (!impl->pending_commit)
- return;
-
- if (window->update_freeze_count > 0)
- return;
-
- callback = wl_surface_frame (impl->display_server.wl_surface);
- wl_callback_add_listener (callback, &frame_listener, window);
- _gdk_frame_clock_freeze (clock);
-
- /* Before we commit a new buffer, make sure we've backfilled
- * undrawn parts from any old committed buffer
- */
- if (impl->pending_buffer_attached)
- read_back_cairo_surface (window);
-
- /* From this commit forward, we can't write to the buffer,
- * it's "live". In the future, if we need to stage more changes
- * we have to allocate a new staging buffer and draw to it instead.
- *
- * Our one saving grace is if the compositor releases the buffer
- * before we need to stage any changes, then we can take it back and
- * use it again.
- */
- wl_surface_commit (impl->display_server.wl_surface);
-
- if (impl->pending_buffer_attached)
- impl->committed_cairo_surface = g_steal_pointer (&impl->staging_cairo_surface);
-
- impl->pending_buffer_attached = FALSE;
- impl->pending_commit = FALSE;
- impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock);
- impl->awaiting_frame = TRUE;
-
- g_signal_emit (impl, signals[COMMITTED], 0);
-}
-
-void
-gdk_wayland_surface_update_scale (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- guint32 scale;
- GSList *l;
- GList *children, *c;
-
- if (display_wayland->compositor_version < WL_SURFACE_HAS_BUFFER_SCALE)
- {
- /* We can't set the scale on this surface */
- return;
- }
-
- scale = 1;
- for (l = impl->display_server.outputs; l != NULL; l = l->next)
- {
- guint32 output_scale = gdk_wayland_display_get_output_scale (display_wayland, l->data);
- scale = MAX (scale, output_scale);
- }
-
- /* Notify app that scale changed */
- gdk_wayland_surface_maybe_configure (window, window->width, window->height, scale);
-
- children = gdk_surface_get_children (window);
- for (c = children; c; c = c->next)
- {
- GdkSurface *child = c->data;
- gdk_wayland_surface_update_scale (child);
- }
- g_list_free (children);
-}
-
-static void gdk_wayland_surface_create_surface (GdkSurface *window);
-
-void
-_gdk_wayland_display_create_window_impl (GdkDisplay *display,
- GdkSurface *window,
- GdkSurface *real_parent,
- GdkEventMask event_mask,
- GdkSurfaceAttr *attributes)
-{
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
- GdkSurfaceImplWayland *impl;
- GdkFrameClock *frame_clock;
-
- impl = g_object_new (GDK_TYPE_SURFACE_IMPL_WAYLAND, NULL);
- window->impl = GDK_SURFACE_IMPL (impl);
- impl->wrapper = GDK_SURFACE (window);
- impl->shortcuts_inhibitors = g_hash_table_new (NULL, NULL);
-
- if (window->width > 65535)
- {
- g_warning ("Native Windows wider than 65535 pixels are not supported");
- window->width = 65535;
- }
- if (window->height > 65535)
- {
- g_warning ("Native Windows taller than 65535 pixels are not supported");
- window->height = 65535;
- }
-
- g_object_ref (window);
-
- /* More likely to be right than just assuming 1 */
- if (display_wayland->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE &&
- gdk_display_get_n_monitors (display) > 0)
- impl->scale = gdk_monitor_get_scale_factor (gdk_display_get_monitor (display, 0));
-
- impl->title = NULL;
-
- switch (GDK_SURFACE_TYPE (window))
- {
- case GDK_SURFACE_TOPLEVEL:
- case GDK_SURFACE_TEMP:
- gdk_surface_set_title (window, get_default_title ());
- break;
-
- case GDK_SURFACE_CHILD:
- default:
- break;
- }
-
- if (real_parent == NULL)
- display_wayland->toplevels = g_list_prepend (display_wayland->toplevels, window);
-
- gdk_wayland_surface_create_surface (window);
-
- frame_clock = gdk_surface_get_frame_clock (window);
- g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), window);
- g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), window);
-}
-
-static void
-gdk_wayland_surface_attach_image (GdkSurface *window)
-{
- GdkWaylandDisplay *display;
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- g_assert (_gdk_wayland_is_shm_surface (impl->staging_cairo_surface));
-
- /* Attach this new buffer to the surface */
- wl_surface_attach (impl->display_server.wl_surface,
- _gdk_wayland_shm_surface_get_wl_buffer (impl->staging_cairo_surface),
- impl->pending_buffer_offset_x,
- impl->pending_buffer_offset_y);
- impl->pending_buffer_offset_x = 0;
- impl->pending_buffer_offset_y = 0;
-
- /* Only set the buffer scale if supported by the compositor */
- display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- if (display->compositor_version >= WL_SURFACE_HAS_BUFFER_SCALE)
- wl_surface_set_buffer_scale (impl->display_server.wl_surface, impl->scale);
-
- impl->pending_buffer_attached = TRUE;
- impl->pending_commit = TRUE;
-}
-
-static const cairo_user_data_key_t gdk_wayland_surface_cairo_key;
-
-static void
-buffer_release_callback (void *_data,
- struct wl_buffer *wl_buffer)
-{
- cairo_surface_t *cairo_surface = _data;
- GdkSurfaceImplWayland *impl = cairo_surface_get_user_data (cairo_surface, &gdk_wayland_surface_cairo_key);
-
- g_return_if_fail (GDK_IS_SURFACE_IMPL_WAYLAND (impl));
-
- /* The released buffer isn't the latest committed one, we have no further
- * use for it, so clean it up.
- */
- if (impl->committed_cairo_surface != cairo_surface)
- {
- /* If this fails, then the surface buffer got reused before it was
- * released from the compositor
- */
- g_warn_if_fail (impl->staging_cairo_surface != cairo_surface);
-
- cairo_surface_destroy (cairo_surface);
- return;
- }
-
- if (impl->staged_updates_region != NULL)
- {
- /* If this fails, then we're tracking staged updates on a staging surface
- * that doesn't exist.
- */
- g_warn_if_fail (impl->staging_cairo_surface != NULL);
-
- /* If we've staged updates into a new buffer before the release for this
- * buffer came in, then we can't reuse this buffer, so unref it. It may still
- * be alive as a readback buffer though (via impl->backfill_cairo_surface).
- *
- * It's possible a staging surface was allocated but no updates were staged.
- * If that happened, clean up that staging surface now, since the old commit
- * buffer is available again, and reusing the old commit buffer for future
- * updates will save having to do a read back later.
- */
- if (!cairo_region_is_empty (impl->staged_updates_region))
- {
- g_clear_pointer (&impl->committed_cairo_surface, cairo_surface_destroy);
- return;
- }
- else
- {
- g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
- g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
- }
- }
-
- /* Release came in, we haven't done any interim updates, so we can just use
- * the old committed buffer again.
- */
- impl->staging_cairo_surface = g_steal_pointer (&impl->committed_cairo_surface);
-}
-
-static const struct wl_buffer_listener buffer_listener = {
- buffer_release_callback
-};
-
-static void
-gdk_wayland_surface_ensure_cairo_surface (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- /* If we are drawing using OpenGL then we only need a logical 1x1 surface. */
- if (impl->display_server.egl_window)
- {
- if (impl->staging_cairo_surface &&
- _gdk_wayland_is_shm_surface (impl->staging_cairo_surface))
- g_clear_pointer (&impl->staging_cairo_surface, cairo_surface_destroy);
-
- if (!impl->staging_cairo_surface)
- {
- impl->staging_cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- impl->scale,
- impl->scale);
- cairo_surface_set_device_scale (impl->staging_cairo_surface,
- impl->scale, impl->scale);
- }
- }
- else if (!impl->staging_cairo_surface)
- {
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (impl->wrapper));
- struct wl_buffer *buffer;
-
- impl->staging_cairo_surface = _gdk_wayland_display_create_shm_surface (display_wayland,
- impl->wrapper->width,
- impl->wrapper->height,
- impl->scale);
- cairo_surface_set_user_data (impl->staging_cairo_surface,
- &gdk_wayland_surface_cairo_key,
- g_object_ref (impl),
- (cairo_destroy_func_t)
- g_object_unref);
- buffer = _gdk_wayland_shm_surface_get_wl_buffer (impl->staging_cairo_surface);
- wl_buffer_add_listener (buffer, &buffer_listener, impl->staging_cairo_surface);
- }
-}
-
-/* The cairo surface returned here uses a memory segment that's shared
- * with the display server. This is not a temporary buffer that gets
- * copied to the display server, but the actual buffer the display server
- * will ultimately end up sending to the GPU. At the time this happens
- * impl->committed_cairo_surface gets set to impl->staging_cairo_surface, and
- * impl->staging_cairo_surface gets nullified.
- */
-static cairo_surface_t *
-gdk_wayland_surface_ref_cairo_surface (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_DESTROYED (impl->wrapper))
- return NULL;
-
- gdk_wayland_surface_ensure_cairo_surface (window);
-
- cairo_surface_reference (impl->staging_cairo_surface);
-
- return impl->staging_cairo_surface;
-}
-
-static cairo_surface_t *
-gdk_wayland_surface_create_similar_image_surface (GdkSurface * window,
- cairo_format_t format,
- int width,
- int height)
-{
- return cairo_image_surface_create (format, width, height);
-}
-
-static gboolean
-gdk_surface_impl_wayland_begin_paint (GdkSurface *window)
-{
- gdk_wayland_surface_ensure_cairo_surface (window);
-
- return FALSE;
-}
-
-static void
-gdk_surface_impl_wayland_end_paint (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- cairo_rectangle_int_t rect;
- int i, n;
-
- if (impl->staging_cairo_surface &&
- _gdk_wayland_is_shm_surface (impl->staging_cairo_surface) &&
- !cairo_region_is_empty (window->current_paint.region))
- {
- gdk_wayland_surface_attach_image (window);
-
- /* If there's a committed buffer pending, then track which
- * updates are staged until the next frame, so we can back
- * fill the unstaged parts of the staging buffer with the
- * last frame.
- */
- if (impl->committed_cairo_surface != NULL)
- {
- if (impl->staged_updates_region == NULL)
- {
- impl->staged_updates_region = cairo_region_copy (window->current_paint.region);
- impl->backfill_cairo_surface = cairo_surface_reference (impl->committed_cairo_surface);
- }
- else
- {
- cairo_region_union (impl->staged_updates_region, window->current_paint.region);
- }
- }
-
- n = cairo_region_num_rectangles (window->current_paint.region);
- for (i = 0; i < n; i++)
- {
- cairo_region_get_rectangle (window->current_paint.region, i, &rect);
- wl_surface_damage (impl->display_server.wl_surface, rect.x, rect.y, rect.width, rect.height);
- }
-
- impl->pending_commit = TRUE;
- }
-
- gdk_wayland_surface_sync (window);
-}
-
-void
-gdk_wayland_surface_sync (GdkSurface *window)
-{
- gdk_wayland_surface_sync_margin (window);
- gdk_wayland_surface_sync_opaque_region (window);
- gdk_wayland_surface_sync_input_region (window);
-}
-
-static gboolean
-gdk_surface_impl_wayland_beep (GdkSurface *window)
-{
- gdk_wayland_display_system_bell (gdk_surface_get_display (window),
- window);
-
- return TRUE;
-}
-
-static void
-gdk_surface_impl_wayland_finalize (GObject *object)
-{
- GdkSurface *window = GDK_SURFACE (object);
- GdkSurfaceImplWayland *impl;
-
- g_return_if_fail (GDK_IS_SURFACE_IMPL_WAYLAND (object));
-
- impl = GDK_SURFACE_IMPL_WAYLAND (object);
-
- if (gdk_wayland_surface_is_exported (window))
- gdk_wayland_surface_unexport_handle (window);
-
- g_free (impl->title);
-
- g_free (impl->application.application_id);
- g_free (impl->application.app_menu_path);
- g_free (impl->application.menubar_path);
- g_free (impl->application.window_object_path);
- g_free (impl->application.application_object_path);
- g_free (impl->application.unique_bus_name);
-
- g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
- g_clear_pointer (&impl->input_region, cairo_region_destroy);
- g_clear_pointer (&impl->staged_updates_region, cairo_region_destroy);
-
- g_hash_table_destroy (impl->shortcuts_inhibitors);
-
- G_OBJECT_CLASS (_gdk_surface_impl_wayland_parent_class)->finalize (object);
-}
-
-static void
-gdk_wayland_surface_configure (GdkSurface *window,
- int width,
- int height,
- int scale)
-{
- GdkDisplay *display;
- GdkEvent *event;
-
- event = gdk_event_new (GDK_CONFIGURE);
- event->any.window = g_object_ref (window);
- event->any.send_event = FALSE;
- event->configure.width = width;
- event->configure.height = height;
-
- gdk_wayland_surface_update_size (window, width, height, scale);
- _gdk_surface_update_size (window);
-
- display = gdk_surface_get_display (window);
- _gdk_wayland_display_deliver_event (display, event);
-}
-
-static void
-gdk_wayland_surface_maybe_configure (GdkSurface *window,
- int width,
- int height,
- int scale)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- gboolean is_xdg_popup;
- gboolean is_visible;
-
- if (window->width == width &&
- window->height == height &&
- impl->scale == scale)
- return;
-
- /* For xdg_popup using an xdg_positioner, there is a race condition if
- * the application tries to change the size after it's mapped, but before
- * the initial configure is received, so hide and show the surface again
- * force the new size onto the compositor. See bug #772505.
- */
-
- is_xdg_popup = (impl->display_server.xdg_popup != NULL);
- is_visible = gdk_surface_is_visible (window);
-
- if (is_xdg_popup && is_visible && !impl->initial_configure_received)
- gdk_surface_hide (window);
-
- gdk_wayland_surface_configure (window, width, height, scale);
-
- if (is_xdg_popup && is_visible && !impl->initial_configure_received)
- gdk_surface_show (window);
-}
-
-static void
-gdk_wayland_surface_sync_parent (GdkSurface *window,
- GdkSurface *parent)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkSurfaceImplWayland *impl_parent = NULL;
- struct zxdg_toplevel_v6 *parent_toplevel;
-
- g_assert (parent == NULL ||
- gdk_surface_get_display (window) == gdk_surface_get_display (parent));
-
- if (!impl->display_server.xdg_toplevel)
- return;
-
- if (impl->transient_for)
- impl_parent = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
- else if (parent)
- impl_parent = GDK_SURFACE_IMPL_WAYLAND (parent->impl);
-
- if (impl_parent)
- {
- /* XXX: Is this correct? */
- if (!impl_parent->display_server.wl_surface)
- return;
-
- parent_toplevel = impl_parent->display_server.xdg_toplevel;
- }
- else
- parent_toplevel = NULL;
-
- zxdg_toplevel_v6_set_parent (impl->display_server.xdg_toplevel,
- parent_toplevel);
-}
-
-static void
-gdk_wayland_surface_sync_parent_of_imported (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (!impl->display_server.wl_surface)
- return;
-
- if (!impl->imported_transient_for)
- return;
-
- if (!impl->display_server.xdg_toplevel)
- return;
-
- zxdg_imported_v1_set_parent_of (impl->imported_transient_for,
- impl->display_server.wl_surface);
-}
-
-static void
-gdk_wayland_surface_update_dialogs (GdkSurface *window)
-{
- GdkWaylandDisplay *display_wayland =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- GList *l;
-
- if (!display_wayland->orphan_dialogs)
- return;
-
- for (l = display_wayland->orphan_dialogs; l; l = l->next)
- {
- GdkSurface *w = l->data;
- GdkSurfaceImplWayland *impl;
-
- if (!GDK_IS_SURFACE_IMPL_WAYLAND(w->impl))
- continue;
-
- impl = GDK_SURFACE_IMPL_WAYLAND (w->impl);
- if (w == window)
- continue;
- if (impl->hint != GDK_SURFACE_TYPE_HINT_DIALOG)
- continue;
- if (impl->transient_for)
- continue;
-
- /* Update the parent relationship only for dialogs without transients */
- gdk_wayland_surface_sync_parent (w, window);
- }
-}
-
-static void
-gdk_wayland_surface_sync_title (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (!impl->display_server.xdg_toplevel)
- return;
-
- if (!impl->title)
- return;
-
- zxdg_toplevel_v6_set_title (impl->display_server.xdg_toplevel, impl->title);
-}
-
-static void
-gdk_wayland_surface_get_window_geometry (GdkSurface *window,
- GdkRectangle *geometry)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- *geometry = (GdkRectangle) {
- .x = impl->margin_left,
- .y = impl->margin_top,
- .width = window->width - (impl->margin_left + impl->margin_right),
- .height = window->height - (impl->margin_top + impl->margin_bottom)
- };
-}
-
-static void
-gdk_wayland_surface_sync_margin (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkRectangle geometry;
-
- if (!impl->display_server.xdg_surface)
- return;
-
- gdk_wayland_surface_get_window_geometry (window, &geometry);
- gdk_surface_set_geometry_hints (window,
- &impl->geometry_hints,
- impl->geometry_mask);
- zxdg_surface_v6_set_window_geometry (impl->display_server.xdg_surface,
- geometry.x,
- geometry.y,
- geometry.width,
- geometry.height);
-}
-
-static struct wl_region *
-wl_region_from_cairo_region (GdkWaylandDisplay *display,
- cairo_region_t *region)
-{
- struct wl_region *wl_region;
- int i, n_rects;
-
- wl_region = wl_compositor_create_region (display->compositor);
- if (wl_region == NULL)
- return NULL;
-
- n_rects = cairo_region_num_rectangles (region);
- for (i = 0; i < n_rects; i++)
- {
- cairo_rectangle_int_t rect;
- cairo_region_get_rectangle (region, i, &rect);
- wl_region_add (wl_region, rect.x, rect.y, rect.width, rect.height);
- }
-
- return wl_region;
-}
-
-static void
-gdk_wayland_surface_sync_opaque_region (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- struct wl_region *wl_region = NULL;
-
- if (!impl->display_server.wl_surface)
- return;
-
- if (!impl->opaque_region_dirty)
- return;
-
- if (impl->opaque_region != NULL)
- wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window)),
- impl->opaque_region);
-
- wl_surface_set_opaque_region (impl->display_server.wl_surface, wl_region);
-
- if (wl_region != NULL)
- wl_region_destroy (wl_region);
-
- impl->opaque_region_dirty = FALSE;
-}
-
-static void
-gdk_wayland_surface_sync_input_region (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- struct wl_region *wl_region = NULL;
-
- if (!impl->display_server.wl_surface)
- return;
-
- if (!impl->input_region_dirty)
- return;
-
- if (impl->input_region != NULL)
- wl_region = wl_region_from_cairo_region (GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window)),
- impl->input_region);
-
- wl_surface_set_input_region (impl->display_server.wl_surface, wl_region);
-
- if (wl_region != NULL)
- wl_region_destroy (wl_region);
-
- impl->input_region_dirty = FALSE;
-}
-
-static void
-gdk_wayland_set_input_region_if_empty (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkWaylandDisplay *display;
- struct wl_region *empty;
-
- if (!impl->input_region_dirty)
- return;
-
- if (impl->input_region == NULL)
- return;
-
- if (!cairo_region_is_empty (impl->input_region))
- return;
-
- display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- empty = wl_compositor_create_region (display->compositor);
-
- wl_surface_set_input_region (impl->display_server.wl_surface, empty);
- wl_region_destroy (empty);
-
- impl->input_region_dirty = FALSE;
-}
-
-static void
-surface_enter (void *data,
- struct wl_surface *wl_surface,
- struct wl_output *output)
-{
- GdkSurface *window = GDK_SURFACE (data);
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- GDK_DISPLAY_NOTE (gdk_surface_get_display (window), EVENTS,
- g_message ("surface enter, window %p output %p", window, output));
-
- impl->display_server.outputs = g_slist_prepend (impl->display_server.outputs, output);
-
- gdk_wayland_surface_update_scale (window);
-}
-
-static void
-surface_leave (void *data,
- struct wl_surface *wl_surface,
- struct wl_output *output)
-{
- GdkSurface *window = GDK_SURFACE (data);
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- GDK_DISPLAY_NOTE (gdk_surface_get_display (window), EVENTS,
- g_message ("surface leave, window %p output %p", window, output));
-
- impl->display_server.outputs = g_slist_remove (impl->display_server.outputs, output);
-
- if (impl->display_server.outputs)
- gdk_wayland_surface_update_scale (window);
-}
-
-static const struct wl_surface_listener surface_listener = {
- surface_enter,
- surface_leave
-};
-
-static void
-on_parent_surface_committed (GdkSurfaceImplWayland *parent_impl,
- GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- g_signal_handler_disconnect (parent_impl,
- impl->parent_surface_committed_handler);
- impl->parent_surface_committed_handler = 0;
-
- wl_subsurface_set_desync (impl->display_server.wl_subsurface);
-
- /* Special case if the input region is empty, it won't change on resize */
- gdk_wayland_set_input_region_if_empty (window);
-}
-
-static void
-gdk_wayland_surface_create_subsurface (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl, *parent_impl = NULL;
- GdkWaylandDisplay *display_wayland;
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (!impl->display_server.wl_surface)
- return; /* Bail out, surface and subsurface will be created later when shown */
-
- if (impl->display_server.wl_subsurface)
- return;
-
- if (impl->transient_for)
- parent_impl = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
-
- if (parent_impl && parent_impl->display_server.wl_surface)
- {
- display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- impl->display_server.wl_subsurface =
- wl_subcompositor_get_subsurface (display_wayland->subcompositor,
- impl->display_server.wl_surface, parent_impl->display_server.wl_surface);
- wl_subsurface_set_position (impl->display_server.wl_subsurface,
- window->x + window->abs_x,
- window->y + window->abs_y);
-
- /* In order to synchronize the initial position with the initial frame
- * content, wait with making the subsurface desynchronized until after
- * the parent was committed.
- */
- impl->parent_surface_committed_handler =
- g_signal_connect_object (parent_impl, "committed",
- G_CALLBACK (on_parent_surface_committed),
- window, 0);
- gdk_surface_request_transient_parent_commit (window);
- }
-}
-
-static void
-gdk_wayland_surface_create_surface (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
-
- impl->display_server.wl_surface = wl_compositor_create_surface (display_wayland->compositor);
- wl_surface_add_listener (impl->display_server.wl_surface, &surface_listener, window);
-}
-
-static void
-xdg_surface_configure (void *data,
- struct zxdg_surface_v6 *xdg_surface,
- uint32_t serial)
-{
- GdkSurface *window = GDK_SURFACE (data);
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkSurfaceState new_state;
- int width = impl->pending.width;
- int height = impl->pending.height;
- gboolean fixed_size;
- gboolean saved_size;
-
- if (!impl->initial_configure_received)
- {
- gdk_surface_thaw_updates (window);
- impl->initial_configure_received = TRUE;
- }
-
- if (impl->display_server.xdg_popup)
- {
- zxdg_surface_v6_ack_configure (xdg_surface, serial);
- return;
- }
-
- new_state = impl->pending.state;
- impl->pending.state = 0;
-
- fixed_size =
- new_state & (GDK_SURFACE_STATE_MAXIMIZED | GDK_SURFACE_STATE_FULLSCREEN | GDK_SURFACE_STATE_TILED);
-
- saved_size = (width == 0 && height == 0);
- /* According to xdg_shell, an xdg_surface.configure with size 0x0
- * should be interpreted as that it is up to the client to set a
- * size.
- *
- * When transitioning from maximize or fullscreen state, this means
- * the client should configure its size back to what it was before
- * being maximize or fullscreen.
- */
- if (saved_size && !fixed_size)
- {
- width = impl->saved_width;
- height = impl->saved_height;
- }
-
- if (width > 0 && height > 0)
- {
- GdkSurfaceHints geometry_mask = impl->geometry_mask;
-
- /* Ignore size increments for maximized/fullscreen windows */
- if (fixed_size)
- geometry_mask &= ~GDK_HINT_RESIZE_INC;
- if (!saved_size)
- {
- /* Do not reapply contrains if we are restoring original size */
- gdk_surface_constrain_size (&impl->geometry_hints,
- geometry_mask,
- width + impl->margin_left + impl->margin_right,
- height + impl->margin_top + impl->margin_bottom,
- &width,
- &height);
-
- /* Save size for next time we get 0x0 */
- _gdk_wayland_surface_save_size (window);
- }
-
- gdk_wayland_surface_configure (window, width, height, impl->scale);
- }
-
- GDK_DISPLAY_NOTE (gdk_surface_get_display (window), EVENTS,
- g_message ("configure, window %p %dx%d,%s%s%s%s",
- window, width, height,
- (new_state & GDK_SURFACE_STATE_FULLSCREEN) ? " fullscreen" : "",
- (new_state & GDK_SURFACE_STATE_MAXIMIZED) ? " maximized" : "",
- (new_state & GDK_SURFACE_STATE_FOCUSED) ? " focused" : "",
- (new_state & GDK_SURFACE_STATE_TILED) ? " tiled" : ""));
-
- gdk_surface_set_state (window, new_state);
- zxdg_surface_v6_ack_configure (xdg_surface, serial);
- if (impl->hint != GDK_SURFACE_TYPE_HINT_DIALOG &&
- new_state & GDK_SURFACE_STATE_FOCUSED)
- gdk_wayland_surface_update_dialogs (window);
-}
-
-static const struct zxdg_surface_v6_listener xdg_surface_listener = {
- xdg_surface_configure,
-};
-
-static void
-xdg_toplevel_configure (void *data,
- struct zxdg_toplevel_v6 *xdg_toplevel,
- int32_t width,
- int32_t height,
- struct wl_array *states)
-{
- GdkSurface *window = GDK_SURFACE (data);
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- uint32_t *p;
-
- wl_array_for_each (p, states)
- {
- uint32_t state = *p;
- switch (state)
- {
- case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
- impl->pending.state |= GDK_SURFACE_STATE_FULLSCREEN;
- break;
- case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED:
- impl->pending.state |= GDK_SURFACE_STATE_MAXIMIZED;
- break;
- case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED:
- impl->pending.state |= GDK_SURFACE_STATE_FOCUSED;
- break;
- case ZXDG_TOPLEVEL_V6_STATE_RESIZING:
- break;
- default:
- /* Unknown state */
- break;
- }
- }
-
- impl->pending.width = width;
- impl->pending.height = height;
-}
-
-static void
-xdg_toplevel_close (void *data,
- struct zxdg_toplevel_v6 *xdg_toplevel)
-{
- GdkSurface *window = GDK_SURFACE (data);
- GdkDisplay *display;
- GdkEvent *event;
-
- display = gdk_surface_get_display (window);
-
- GDK_DISPLAY_NOTE (display, EVENTS, g_message ("close %p", window));
-
- event = gdk_event_new (GDK_DELETE);
- event->any.window = g_object_ref (window);
- event->any.send_event = TRUE;
-
- _gdk_wayland_display_deliver_event (display, event);
-}
-
-static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
- xdg_toplevel_configure,
- xdg_toplevel_close,
-};
-
-static void
-gdk_wayland_surface_create_xdg_toplevel (GdkSurface *window)
-{
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- const gchar *app_id;
-
- impl->display_server.xdg_surface =
- zxdg_shell_v6_get_xdg_surface (display_wayland->xdg_shell,
- impl->display_server.wl_surface);
- zxdg_surface_v6_add_listener (impl->display_server.xdg_surface,
- &xdg_surface_listener,
- window);
- gdk_surface_freeze_updates (window);
-
- impl->display_server.xdg_toplevel =
- zxdg_surface_v6_get_toplevel (impl->display_server.xdg_surface);
- zxdg_toplevel_v6_add_listener (impl->display_server.xdg_toplevel,
- &xdg_toplevel_listener,
- window);
-
- gdk_wayland_surface_sync_parent (window, NULL);
- gdk_wayland_surface_sync_parent_of_imported (window);
- gdk_wayland_surface_sync_title (window);
-
- if (window->state & GDK_SURFACE_STATE_MAXIMIZED)
- zxdg_toplevel_v6_set_maximized (impl->display_server.xdg_toplevel);
- if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
- zxdg_toplevel_v6_set_fullscreen (impl->display_server.xdg_toplevel,
- impl->initial_fullscreen_output);
-
- impl->initial_fullscreen_output = NULL;
-
- app_id = g_get_prgname ();
-
- if (app_id == NULL)
- app_id = "GTK+ Application";
-
- zxdg_toplevel_v6_set_app_id (impl->display_server.xdg_toplevel, app_id);
-
- maybe_set_gtk_surface_dbus_properties (window);
- maybe_set_gtk_surface_modal (window);
-
- if (impl->hint == GDK_SURFACE_TYPE_HINT_DIALOG)
- _gdk_wayland_screen_add_orphan_dialog (window);
-
- wl_surface_commit (impl->display_server.wl_surface);
-}
-
-static void
-xdg_popup_configure (void *data,
- struct zxdg_popup_v6 *xdg_popup,
- int32_t x,
- int32_t y,
- int32_t width,
- int32_t height)
-{
- GdkSurface *window = GDK_SURFACE (data);
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkRectangle flipped_rect;
- GdkRectangle final_rect;
- gboolean flipped_x;
- gboolean flipped_y;
-
- g_return_if_fail (impl->transient_for);
-
- if (impl->position_method != POSITION_METHOD_MOVE_TO_RECT)
- return;
-
- calculate_moved_to_rect_result (window, x, y, width, height,
- &flipped_rect,
- &final_rect,
- &flipped_x,
- &flipped_y);
-
- g_signal_emit_by_name (window,
- "moved-to-rect",
- &flipped_rect,
- &final_rect,
- flipped_x,
- flipped_y);
-}
-
-static void
-xdg_popup_done (void *data,
- struct zxdg_popup_v6 *xdg_popup)
-{
- GdkSurface *window = GDK_SURFACE (data);
-
- GDK_DISPLAY_NOTE (gdk_surface_get_display (window), EVENTS, g_message ("done %p", window));
-
- gdk_surface_hide (window);
-}
-
-static const struct zxdg_popup_v6_listener xdg_popup_listener = {
- xdg_popup_configure,
- xdg_popup_done,
-};
-
-static enum zxdg_positioner_v6_anchor
-rect_anchor_to_anchor (GdkGravity rect_anchor)
-{
- switch (rect_anchor)
- {
- case GDK_GRAVITY_NORTH_WEST:
- case GDK_GRAVITY_STATIC:
- return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
- ZXDG_POSITIONER_V6_ANCHOR_LEFT);
- case GDK_GRAVITY_NORTH:
- return ZXDG_POSITIONER_V6_ANCHOR_TOP;
- case GDK_GRAVITY_NORTH_EAST:
- return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
- ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
- case GDK_GRAVITY_WEST:
- return ZXDG_POSITIONER_V6_ANCHOR_LEFT;
- case GDK_GRAVITY_CENTER:
- return ZXDG_POSITIONER_V6_ANCHOR_NONE;
- case GDK_GRAVITY_EAST:
- return ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
- case GDK_GRAVITY_SOUTH_WEST:
- return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
- ZXDG_POSITIONER_V6_ANCHOR_LEFT);
- case GDK_GRAVITY_SOUTH:
- return ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
- case GDK_GRAVITY_SOUTH_EAST:
- return (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
- ZXDG_POSITIONER_V6_ANCHOR_RIGHT);
- default:
- g_assert_not_reached ();
- }
-
- return (ZXDG_POSITIONER_V6_ANCHOR_TOP |
- ZXDG_POSITIONER_V6_ANCHOR_LEFT);
-}
-
-static enum zxdg_positioner_v6_gravity
-window_anchor_to_gravity (GdkGravity rect_anchor)
-{
- switch (rect_anchor)
- {
- case GDK_GRAVITY_NORTH_WEST:
- case GDK_GRAVITY_STATIC:
- return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
- ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
- case GDK_GRAVITY_NORTH:
- return ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
- case GDK_GRAVITY_NORTH_EAST:
- return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
- ZXDG_POSITIONER_V6_GRAVITY_LEFT);
- case GDK_GRAVITY_WEST:
- return ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
- case GDK_GRAVITY_CENTER:
- return ZXDG_POSITIONER_V6_GRAVITY_NONE;
- case GDK_GRAVITY_EAST:
- return ZXDG_POSITIONER_V6_GRAVITY_LEFT;
- case GDK_GRAVITY_SOUTH_WEST:
- return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
- ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
- case GDK_GRAVITY_SOUTH:
- return ZXDG_POSITIONER_V6_GRAVITY_TOP;
- case GDK_GRAVITY_SOUTH_EAST:
- return (ZXDG_POSITIONER_V6_GRAVITY_TOP |
- ZXDG_POSITIONER_V6_GRAVITY_LEFT);
- default:
- g_assert_not_reached ();
- }
-
- return (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
- ZXDG_POSITIONER_V6_GRAVITY_RIGHT);
-}
-
-void
-gdk_wayland_surface_announce_csd (GdkSurface *window)
-{
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- if (!display_wayland->server_decoration_manager)
- return;
- impl->display_server.server_decoration =
- org_kde_kwin_server_decoration_manager_create (display_wayland->server_decoration_manager,
- impl->display_server.wl_surface);
- if (impl->display_server.server_decoration)
- org_kde_kwin_server_decoration_request_mode (impl->display_server.server_decoration,
- ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT);
-}
-
-static GdkSurface *
-get_real_parent_and_translate (GdkSurface *window,
- gint *x,
- gint *y)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkSurface *parent = impl->transient_for;
-
- while (parent)
- {
- GdkSurfaceImplWayland *parent_impl =
- GDK_SURFACE_IMPL_WAYLAND (parent->impl);
- GdkSurface *effective_parent = gdk_surface_get_parent (parent);
-
- if ((gdk_surface_has_native (parent) &&
- !parent_impl->display_server.wl_subsurface) ||
- !effective_parent)
- break;
-
- *x += parent->x;
- *y += parent->y;
-
- if (gdk_surface_has_native (parent) &&
- parent_impl->display_server.wl_subsurface)
- parent = parent->transient_for;
- else
- parent = effective_parent;
- }
-
- return parent;
-}
-
-static void
-translate_to_real_parent_window_geometry (GdkSurface *window,
- gint *x,
- gint *y)
-{
- GdkSurface *parent;
-
- parent = get_real_parent_and_translate (window, x, y);
-
- *x -= parent->shadow_left;
- *y -= parent->shadow_top;
-}
-
-static GdkSurface *
-translate_from_real_parent_window_geometry (GdkSurface *window,
- gint *x,
- gint *y)
-{
- GdkSurface *parent;
- gint dx = 0;
- gint dy = 0;
-
- parent = get_real_parent_and_translate (window, &dx, &dy);
-
- *x -= dx - parent->shadow_left;
- *y -= dy - parent->shadow_top;
-
- return parent;
-}
-
-static void
-calculate_popup_rect (GdkSurface *window,
- GdkGravity rect_anchor,
- GdkGravity window_anchor,
- GdkRectangle *out_rect)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkRectangle geometry;
- GdkRectangle anchor_rect;
- int x = 0, y = 0;
-
- gdk_wayland_surface_get_window_geometry (window, &geometry);
-
- anchor_rect = (GdkRectangle) {
- .x = (impl->pending_move_to_rect.rect.x +
- impl->pending_move_to_rect.rect_anchor_dx),
- .y = (impl->pending_move_to_rect.rect.y +
- impl->pending_move_to_rect.rect_anchor_dy),
- .width = impl->pending_move_to_rect.rect.width,
- .height = impl->pending_move_to_rect.rect.height
- };
-
- switch (rect_anchor)
- {
- default:
- case GDK_GRAVITY_STATIC:
- case GDK_GRAVITY_NORTH_WEST:
- x = anchor_rect.x;
- y = anchor_rect.y;
- break;
- case GDK_GRAVITY_NORTH:
- x = anchor_rect.x + (anchor_rect.width / 2);
- y = anchor_rect.y;
- break;
- case GDK_GRAVITY_NORTH_EAST:
- x = anchor_rect.x + anchor_rect.width;
- y = anchor_rect.y;
- break;
- case GDK_GRAVITY_WEST:
- x = anchor_rect.x;
- y = anchor_rect.y + (anchor_rect.height / 2);
- break;
- case GDK_GRAVITY_CENTER:
- x = anchor_rect.x + (anchor_rect.width / 2);
- y = anchor_rect.y + (anchor_rect.height / 2);
- break;
- case GDK_GRAVITY_EAST:
- x = anchor_rect.x + anchor_rect.width;
- y = anchor_rect.y + (anchor_rect.height / 2);
- break;
- case GDK_GRAVITY_SOUTH_WEST:
- x = anchor_rect.x;
- y = anchor_rect.y + anchor_rect.height;
- break;
- case GDK_GRAVITY_SOUTH:
- x = anchor_rect.x + (anchor_rect.width / 2);
- y = anchor_rect.y + anchor_rect.height;
- break;
- case GDK_GRAVITY_SOUTH_EAST:
- x = anchor_rect.x + anchor_rect.width;
- y = anchor_rect.y + anchor_rect.height;
- break;
- }
-
- switch (window_anchor)
- {
- default:
- case GDK_GRAVITY_STATIC:
- case GDK_GRAVITY_NORTH_WEST:
- break;
- case GDK_GRAVITY_NORTH:
- x -= geometry.width / 2;
- break;
- case GDK_GRAVITY_NORTH_EAST:
- x -= geometry.width;
- break;
- case GDK_GRAVITY_WEST:
- y -= geometry.height / 2;
- break;
- case GDK_GRAVITY_CENTER:
- x -= geometry.width / 2;
- y -= geometry.height / 2;
- break;
- case GDK_GRAVITY_EAST:
- x -= geometry.width;
- y -= geometry.height / 2;
- break;
- case GDK_GRAVITY_SOUTH_WEST:
- y -= geometry.height;
- break;
- case GDK_GRAVITY_SOUTH:
- x -= geometry.width / 2;
- y -= geometry.height;
- break;
- case GDK_GRAVITY_SOUTH_EAST:
- x -= geometry.width;
- y -= geometry.height;
- break;
- }
-
- *out_rect = (GdkRectangle) {
- .x = x,
- .y = y,
- .width = geometry.width,
- .height = geometry.height
- };
-}
-
-static GdkGravity
-flip_anchor_horizontally (GdkGravity anchor)
-{
- switch (anchor)
- {
- default:
- case GDK_GRAVITY_STATIC:
- case GDK_GRAVITY_NORTH_WEST:
- return GDK_GRAVITY_NORTH_EAST;
- case GDK_GRAVITY_NORTH:
- return GDK_GRAVITY_NORTH;
- case GDK_GRAVITY_NORTH_EAST:
- return GDK_GRAVITY_NORTH_WEST;
- case GDK_GRAVITY_WEST:
- return GDK_GRAVITY_EAST;
- case GDK_GRAVITY_CENTER:
- return GDK_GRAVITY_CENTER;
- case GDK_GRAVITY_EAST:
- return GDK_GRAVITY_WEST;
- case GDK_GRAVITY_SOUTH_WEST:
- return GDK_GRAVITY_SOUTH_EAST;
- case GDK_GRAVITY_SOUTH:
- return GDK_GRAVITY_SOUTH;
- case GDK_GRAVITY_SOUTH_EAST:
- return GDK_GRAVITY_SOUTH_WEST;
- }
-
- g_assert_not_reached ();
-}
-
-static GdkGravity
-flip_anchor_vertically (GdkGravity anchor)
-{
- switch (anchor)
- {
- default:
- case GDK_GRAVITY_STATIC:
- case GDK_GRAVITY_NORTH_WEST:
- return GDK_GRAVITY_SOUTH_WEST;
- case GDK_GRAVITY_NORTH:
- return GDK_GRAVITY_SOUTH;
- case GDK_GRAVITY_NORTH_EAST:
- return GDK_GRAVITY_SOUTH_EAST;
- case GDK_GRAVITY_WEST:
- return GDK_GRAVITY_WEST;
- case GDK_GRAVITY_CENTER:
- return GDK_GRAVITY_CENTER;
- case GDK_GRAVITY_EAST:
- return GDK_GRAVITY_EAST;
- case GDK_GRAVITY_SOUTH_WEST:
- return GDK_GRAVITY_NORTH_WEST;
- case GDK_GRAVITY_SOUTH:
- return GDK_GRAVITY_NORTH;
- case GDK_GRAVITY_SOUTH_EAST:
- return GDK_GRAVITY_NORTH_EAST;
- }
-
- g_assert_not_reached ();
-}
-
-static void
-calculate_moved_to_rect_result (GdkSurface *window,
- int x,
- int y,
- int width,
- int height,
- GdkRectangle *flipped_rect,
- GdkRectangle *final_rect,
- gboolean *flipped_x,
- gboolean *flipped_y)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkSurface *parent;
- gint window_x, window_y;
- gint window_width, window_height;
- GdkRectangle best_rect;
-
- parent = translate_from_real_parent_window_geometry (window, &x, &y);
- *final_rect = (GdkRectangle) {
- .x = x,
- .y = y,
- .width = width,
- .height = height,
- };
-
- window_x = parent->x + x;
- window_y = parent->y + y;
- window_width = width + window->shadow_left + window->shadow_right;
- window_height = height + window->shadow_top + window->shadow_bottom;
-
- gdk_surface_move_resize (window,
- window_x, window_y,
- window_width, window_height);
-
- calculate_popup_rect (window,
- impl->pending_move_to_rect.rect_anchor,
- impl->pending_move_to_rect.window_anchor,
- &best_rect);
-
- *flipped_rect = best_rect;
-
- if (x != best_rect.x &&
- impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_X)
- {
- GdkRectangle flipped_x_rect;
- GdkGravity flipped_rect_anchor;
- GdkGravity flipped_window_anchor;
-
- flipped_rect_anchor =
- flip_anchor_horizontally (impl->pending_move_to_rect.rect_anchor);
- flipped_window_anchor =
- flip_anchor_horizontally (impl->pending_move_to_rect.window_anchor),
- calculate_popup_rect (window,
- flipped_rect_anchor,
- flipped_window_anchor,
- &flipped_x_rect);
-
- if (flipped_x_rect.x == x)
- flipped_rect->x = x;
- }
- if (y != best_rect.y &&
- impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_Y)
- {
- GdkRectangle flipped_y_rect;
- GdkGravity flipped_rect_anchor;
- GdkGravity flipped_window_anchor;
-
- flipped_rect_anchor =
- flip_anchor_vertically (impl->pending_move_to_rect.rect_anchor);
- flipped_window_anchor =
- flip_anchor_vertically (impl->pending_move_to_rect.window_anchor),
- calculate_popup_rect (window,
- flipped_rect_anchor,
- flipped_window_anchor,
- &flipped_y_rect);
-
- if (flipped_y_rect.y == y)
- flipped_rect->y = y;
- }
-
- *flipped_x = flipped_rect->x != best_rect.x;
- *flipped_y = flipped_rect->y != best_rect.y;
-}
-
-static struct zxdg_positioner_v6 *
-create_dynamic_positioner (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkWaylandDisplay *display =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- struct zxdg_positioner_v6 *positioner;
- GdkRectangle geometry;
- enum zxdg_positioner_v6_anchor anchor;
- enum zxdg_positioner_v6_gravity gravity;
- uint32_t constraint_adjustment = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE;
- gint real_anchor_rect_x, real_anchor_rect_y;
- gint anchor_rect_width, anchor_rect_height;
-
- positioner = zxdg_shell_v6_create_positioner (display->xdg_shell);
-
- gdk_wayland_surface_get_window_geometry (window, &geometry);
- zxdg_positioner_v6_set_size (positioner, geometry.width, geometry.height);
-
- real_anchor_rect_x = impl->pending_move_to_rect.rect.x;
- real_anchor_rect_y = impl->pending_move_to_rect.rect.y;
- translate_to_real_parent_window_geometry (window,
- &real_anchor_rect_x,
- &real_anchor_rect_y);
-
- anchor_rect_width = impl->pending_move_to_rect.rect.width;
- anchor_rect_height = impl->pending_move_to_rect.rect.height;
- zxdg_positioner_v6_set_anchor_rect (positioner,
- real_anchor_rect_x,
- real_anchor_rect_y,
- anchor_rect_width,
- anchor_rect_height);
-
- zxdg_positioner_v6_set_offset (positioner,
- impl->pending_move_to_rect.rect_anchor_dx,
- impl->pending_move_to_rect.rect_anchor_dy);
-
- anchor = rect_anchor_to_anchor (impl->pending_move_to_rect.rect_anchor);
- zxdg_positioner_v6_set_anchor (positioner, anchor);
-
- gravity = window_anchor_to_gravity (impl->pending_move_to_rect.window_anchor);
- zxdg_positioner_v6_set_gravity (positioner, gravity);
-
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_X)
- constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_Y)
- constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_X)
- constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_Y)
- constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_X)
- constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_Y)
- constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
-
- zxdg_positioner_v6_set_constraint_adjustment (positioner,
- constraint_adjustment);
-
- return positioner;
-}
-
-static struct zxdg_positioner_v6 *
-create_simple_positioner (GdkSurface *window,
- GdkSurface *parent)
-{
- GdkWaylandDisplay *display =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- struct zxdg_positioner_v6 *positioner;
- GdkRectangle geometry;
- GdkRectangle parent_geometry;
- int parent_x, parent_y;
-
- positioner = zxdg_shell_v6_create_positioner (display->xdg_shell);
-
- gdk_wayland_surface_get_window_geometry (window, &geometry);
- zxdg_positioner_v6_set_size (positioner, geometry.width, geometry.height);
-
- parent_x = parent->x;
- parent_y = parent->y;
-
- gdk_wayland_surface_get_window_geometry (parent, &parent_geometry);
- parent_x += parent_geometry.x;
- parent_y += parent_geometry.y;
-
- zxdg_positioner_v6_set_anchor_rect (positioner,
- (window->x + geometry.x) - parent_x,
- (window->y + geometry.y) - parent_y,
- 1, 1);
- zxdg_positioner_v6_set_anchor (positioner,
- (ZXDG_POSITIONER_V6_ANCHOR_TOP |
- ZXDG_POSITIONER_V6_ANCHOR_LEFT));
- zxdg_positioner_v6_set_gravity (positioner,
- (ZXDG_POSITIONER_V6_GRAVITY_BOTTOM |
- ZXDG_POSITIONER_V6_GRAVITY_RIGHT));
-
- return positioner;
-}
-
-static void
-gdk_wayland_surface_create_xdg_popup (GdkSurface *window,
- GdkSurface *parent,
- struct wl_seat *seat)
-{
- GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkSurfaceImplWayland *parent_impl = GDK_SURFACE_IMPL_WAYLAND (parent->impl);
- struct zxdg_positioner_v6 *positioner;
- GdkSeat *gdk_seat;
- guint32 serial;
-
- if (!impl->display_server.wl_surface)
- return;
-
- if (!parent_impl->display_server.xdg_surface)
- return;
-
- if (impl->display_server.xdg_toplevel)
- {
- g_warning ("Can't map popup, already mapped as toplevel");
- return;
- }
- if (impl->display_server.xdg_popup)
- {
- g_warning ("Can't map popup, already mapped");
- return;
- }
- if ((display->current_popups &&
- g_list_last (display->current_popups)->data != parent) ||
- (!display->current_popups &&
- !parent_impl->display_server.xdg_toplevel))
- {
- g_warning ("Tried to map a popup with a non-top most parent");
- return;
- }
-
- impl->display_server.xdg_surface =
- zxdg_shell_v6_get_xdg_surface (display->xdg_shell,
- impl->display_server.wl_surface);
- zxdg_surface_v6_add_listener (impl->display_server.xdg_surface,
- &xdg_surface_listener,
- window);
- gdk_surface_freeze_updates (window);
-
- if (impl->position_method == POSITION_METHOD_MOVE_TO_RECT)
- positioner = create_dynamic_positioner (window);
- else
- positioner = create_simple_positioner (window, parent);
-
- impl->display_server.xdg_popup =
- zxdg_surface_v6_get_popup (impl->display_server.xdg_surface,
- parent_impl->display_server.xdg_surface,
- positioner);
- zxdg_popup_v6_add_listener (impl->display_server.xdg_popup,
- &xdg_popup_listener,
- window);
-
- zxdg_positioner_v6_destroy (positioner);
-
- if (seat)
- {
- gdk_seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
- serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_seat, NULL);
- zxdg_popup_v6_grab (impl->display_server.xdg_popup, seat, serial);
- }
-
- wl_surface_commit (impl->display_server.wl_surface);
-
- impl->popup_parent = parent;
- display->current_popups = g_list_append (display->current_popups, window);
-}
-
-static struct wl_seat *
-find_grab_input_seat (GdkSurface *window, GdkSurface *transient_for)
-{
- GdkSurface *attached_grab_window;
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkSurfaceImplWayland *tmp_impl;
-
- /* Use the device that was used for the grab as the device for
- * the popup window setup - so this relies on GTK+ taking the
- * grab before showing the popup window.
- */
- if (impl->grab_input_seat)
- return gdk_wayland_seat_get_wl_seat (impl->grab_input_seat);
-
- /* HACK: GtkMenu grabs a special window known as the "grab transfer window"
- * and then transfers the grab over to the correct window later. Look for
- * this window when taking the grab to know it's correct.
- *
- * See: associate_menu_grab_transfer_window in gtkmenu.c
- */
- attached_grab_window = g_object_get_data (G_OBJECT (window), "gdk-attached-grab-window");
- if (attached_grab_window)
- {
- tmp_impl = GDK_SURFACE_IMPL_WAYLAND (attached_grab_window->impl);
- if (tmp_impl->grab_input_seat)
- return gdk_wayland_seat_get_wl_seat (tmp_impl->grab_input_seat);
- }
-
- while (transient_for)
- {
- tmp_impl = GDK_SURFACE_IMPL_WAYLAND (transient_for->impl);
-
- if (tmp_impl->grab_input_seat)
- return gdk_wayland_seat_get_wl_seat (tmp_impl->grab_input_seat);
-
- transient_for = tmp_impl->transient_for;
- }
-
- return NULL;
-}
-
-static gboolean
-should_be_mapped (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- /* Don't map crazy temp that GTK+ uses for internal X11 shenanigans. */
- if (window->window_type == GDK_SURFACE_TEMP && window->x < 0 && window->y < 0)
- return FALSE;
-
- if (impl->hint == GDK_SURFACE_TYPE_HINT_DND)
- return FALSE;
-
- return TRUE;
-}
-
-static gboolean
-should_map_as_popup (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- /* Ideally, popup would be temp windows with a parent and grab */
- if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP)
- {
- /* If a temp window has a parent and a grab, we can use a popup */
- if (impl->transient_for)
- {
- if (impl->grab_input_seat)
- return TRUE;
- }
- else
- g_message ("Window %p is a temporary window without parent, "
- "application will not be able to position it on screen.",
- window);
- }
-
- /* Yet we need to keep the window type hint tests for compatibility */
- switch ((guint) impl->hint)
- {
- case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
- case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU:
- case GDK_SURFACE_TYPE_HINT_COMBO:
- return TRUE;
-
- default:
- break;
- }
-
- return FALSE;
-}
-
-static gboolean
-should_map_as_subsurface (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_SUBSURFACE)
- return TRUE;
-
- if (GDK_SURFACE_TYPE (window) != GDK_SURFACE_TEMP)
- return FALSE;
-
- /* if we want a popup, we do not want a subsurface */
- if (should_map_as_popup (window))
- return FALSE;
-
- if (impl->transient_for)
- {
- GdkSurfaceImplWayland *impl_parent;
-
- impl_parent = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
- /* subsurface require that the parent is mapped */
- if (impl_parent->mapped)
- return TRUE;
- else
- g_warning ("Couldn't map window %p as subsurface because its parent is not mapped.",
- window);
-
- }
-
- return FALSE;
-}
-
-/* Get the window that can be used as a parent for a popup, i.e. a xdg_toplevel
- * or xdg_popup. If the window is not, traverse up the transiency parents until
- * we find one.
- */
-static GdkSurface *
-get_popup_parent (GdkSurface *window)
-{
- while (window)
- {
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (impl->display_server.xdg_popup || impl->display_server.xdg_toplevel)
- return window;
-
- window = impl->transient_for;
- }
-
- return NULL;
-}
-
-static void
-gdk_wayland_surface_map (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkSurface *transient_for = NULL;
-
- if (!should_be_mapped (window))
- return;
-
- if (impl->mapped || impl->use_custom_surface)
- return;
-
- if (should_map_as_subsurface (window))
- {
- if (impl->transient_for)
- gdk_wayland_surface_create_subsurface (window);
- else
- g_warning ("Couldn't map window %p as susburface yet because it doesn't have a parent",
- window);
- }
- else if (should_map_as_popup (window))
- {
- gboolean create_fallback = FALSE;
- struct wl_seat *grab_input_seat;
-
- /* Popup menus can appear without a transient parent, which means they
- * cannot be positioned properly on Wayland. This attempts to guess the
- * surface they should be positioned with by finding the surface beneath
- * the device that created the grab for the popup window.
- */
- if (!impl->transient_for && impl->hint == GDK_SURFACE_TYPE_HINT_POPUP_MENU)
- {
- GdkDevice *grab_device = NULL;
-
- /* The popup menu window is not the grabbed window. This may mean
- * that a "transfer window" (see gtkmenu.c) is used, and we need
- * to find that window to get the grab device. If so is the case
- * the "transfer window" can be retrieved via the
- * "gdk-attached-grab-window" associated data field.
- */
- if (!impl->grab_input_seat)
- {
- GdkSurface *attached_grab_window =
- g_object_get_data (G_OBJECT (window),
- "gdk-attached-grab-window");
- if (attached_grab_window)
- {
- GdkSurfaceImplWayland *attached_impl =
- GDK_SURFACE_IMPL_WAYLAND (attached_grab_window->impl);
- grab_device = gdk_seat_get_pointer (attached_impl->grab_input_seat);
- transient_for =
- gdk_device_get_window_at_position (grab_device,
- NULL, NULL);
- }
- }
- else
- {
- grab_device = gdk_seat_get_pointer (impl->grab_input_seat);
- transient_for =
- gdk_device_get_window_at_position (grab_device, NULL, NULL);
- }
-
- if (transient_for)
- transient_for = get_popup_parent (gdk_surface_get_toplevel (transient_for));
-
- /* If the position was not explicitly set, start the popup at the
- * position of the device that holds the grab.
- */
- if (impl->position_method == POSITION_METHOD_NONE && grab_device)
- gdk_surface_get_device_position (transient_for, grab_device,
- &window->x, &window->y, NULL);
- }
- else
- {
- transient_for = gdk_surface_get_toplevel (impl->transient_for);
- transient_for = get_popup_parent (transient_for);
- }
-
- if (!transient_for)
- {
- g_warning ("Couldn't map as window %p as popup because it doesn't have a parent",
- window);
-
- create_fallback = TRUE;
- }
- else
- {
- grab_input_seat = find_grab_input_seat (window, transient_for);
- }
-
- if (!create_fallback)
- {
- gdk_wayland_surface_create_xdg_popup (window,
- transient_for,
- grab_input_seat);
- }
- else
- {
- gdk_wayland_surface_create_xdg_toplevel (window);
- }
- }
- else
- {
- gdk_wayland_surface_create_xdg_toplevel (window);
- }
-
- impl->mapped = TRUE;
-}
-
-static void
-gdk_wayland_surface_show (GdkSurface *window,
- gboolean already_mapped)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (!impl->display_server.wl_surface)
- gdk_wayland_surface_create_surface (window);
-
- gdk_wayland_surface_map (window);
-
- _gdk_make_event (window, GDK_MAP, NULL, FALSE);
-
- if (impl->staging_cairo_surface &&
- _gdk_wayland_is_shm_surface (impl->staging_cairo_surface))
- gdk_wayland_surface_attach_image (window);
-}
-
-static void
-unmap_subsurface (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkSurfaceImplWayland *parent_impl;
-
- g_return_if_fail (impl->display_server.wl_subsurface);
- g_return_if_fail (impl->transient_for);
-
- parent_impl = GDK_SURFACE_IMPL_WAYLAND (impl->transient_for->impl);
- wl_subsurface_destroy (impl->display_server.wl_subsurface);
- if (impl->parent_surface_committed_handler)
- {
- g_signal_handler_disconnect (parent_impl,
- impl->parent_surface_committed_handler);
- impl->parent_surface_committed_handler = 0;
- }
- impl->display_server.wl_subsurface = NULL;
-}
-
-static void
-unmap_popups_for_window (GdkSurface *window)
-{
- GdkWaylandDisplay *display_wayland;
- GList *l;
-
- display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- for (l = display_wayland->current_popups; l; l = l->next)
- {
- GdkSurface *popup = l->data;
- GdkSurfaceImplWayland *popup_impl = GDK_SURFACE_IMPL_WAYLAND (popup->impl);
-
- if (popup_impl->popup_parent == window)
- {
- g_warning ("Tried to unmap the parent of a popup");
- gdk_surface_hide (popup);
-
- return;
- }
- }
-}
-
-static void
-gdk_wayland_surface_hide_surface (GdkSurface *window)
-{
- GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- unmap_popups_for_window (window);
-
- if (impl->display_server.wl_surface)
- {
- if (impl->dummy_egl_surface)
- {
- eglDestroySurface (display_wayland->egl_display, impl->dummy_egl_surface);
- impl->dummy_egl_surface = NULL;
- }
-
- if (impl->display_server.dummy_egl_window)
- {
- wl_egl_window_destroy (impl->display_server.dummy_egl_window);
- impl->display_server.dummy_egl_window = NULL;
- }
-
- if (impl->egl_surface)
- {
- eglDestroySurface (display_wayland->egl_display, impl->egl_surface);
- impl->egl_surface = NULL;
- }
-
- if (impl->display_server.egl_window)
- {
- wl_egl_window_destroy (impl->display_server.egl_window);
- impl->display_server.egl_window = NULL;
- }
-
- if (impl->display_server.xdg_toplevel)
- {
- zxdg_toplevel_v6_destroy (impl->display_server.xdg_toplevel);
- impl->display_server.xdg_toplevel = NULL;
- }
- else if (impl->display_server.xdg_popup)
- {
- zxdg_popup_v6_destroy (impl->display_server.xdg_popup);
- impl->display_server.xdg_popup = NULL;
- display_wayland->current_popups =
- g_list_remove (display_wayland->current_popups, window);
- }
- if (impl->display_server.xdg_surface)
- {
- zxdg_surface_v6_destroy (impl->display_server.xdg_surface);
- impl->display_server.xdg_surface = NULL;
- if (!impl->initial_configure_received)
- gdk_surface_thaw_updates (window);
- else
- impl->initial_configure_received = FALSE;
- }
-
- if (impl->display_server.wl_subsurface)
- unmap_subsurface (window);
-
- if (impl->awaiting_frame)
- {
- GdkFrameClock *frame_clock;
-
- impl->awaiting_frame = FALSE;
- frame_clock = gdk_surface_get_frame_clock (window);
- if (frame_clock)
- _gdk_frame_clock_thaw (frame_clock);
- }
-
- if (impl->display_server.gtk_surface)
- {
- gtk_surface1_destroy (impl->display_server.gtk_surface);
- impl->display_server.gtk_surface = NULL;
- impl->application.was_set = FALSE;
- }
-
- wl_surface_destroy (impl->display_server.wl_surface);
- impl->display_server.wl_surface = NULL;
-
- g_slist_free (impl->display_server.outputs);
- impl->display_server.outputs = NULL;
-
- if (impl->hint == GDK_SURFACE_TYPE_HINT_DIALOG && !impl->transient_for)
- display_wayland->orphan_dialogs =
- g_list_remove (display_wayland->orphan_dialogs, window);
- }
-
- unset_transient_for_exported (window);
-
- _gdk_wayland_surface_clear_saved_size (window);
- impl->pending_commit = FALSE;
- impl->mapped = FALSE;
-}
-
-static void
-gdk_wayland_surface_hide (GdkSurface *window)
-{
- gdk_wayland_surface_hide_surface (window);
- _gdk_surface_clear_update_area (window);
-}
-
-static void
-gdk_surface_wayland_withdraw (GdkSurface *window)
-{
- if (!window->destroyed)
- {
- if (GDK_SURFACE_IS_MAPPED (window))
- gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_WITHDRAWN);
-
- g_assert (!GDK_SURFACE_IS_MAPPED (window));
-
- gdk_wayland_surface_hide_surface (window);
- }
-}
-
-static void
-gdk_surface_wayland_set_events (GdkSurface *window,
- GdkEventMask event_mask)
-{
- GDK_SURFACE (window)->event_mask = event_mask;
-}
-
-static GdkEventMask
-gdk_surface_wayland_get_events (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return 0;
- else
- return GDK_SURFACE (window)->event_mask;
-}
-
-static void
-gdk_surface_wayland_raise (GdkSurface *window)
-{
-}
-
-static void
-gdk_surface_wayland_lower (GdkSurface *window)
-{
-}
-
-static void
-gdk_surface_wayland_restack_toplevel (GdkSurface *window,
- GdkSurface *sibling,
- gboolean above)
-{
-}
-
-static void
-gdk_surface_request_transient_parent_commit (GdkSurface *window)
-{
- GdkSurfaceImplWayland *window_impl, *impl;
- GdkFrameClock *frame_clock;
-
- window_impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (!window_impl->transient_for)
- return;
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window_impl->transient_for->impl);
-
- if (!impl->display_server.wl_surface || impl->pending_commit)
- return;
-
- frame_clock = gdk_surface_get_frame_clock (window_impl->transient_for);
-
- if (!frame_clock)
- return;
-
- impl->pending_commit = TRUE;
- gdk_frame_clock_request_phase (frame_clock,
- GDK_FRAME_CLOCK_PHASE_AFTER_PAINT);
-}
-
-static void
-gdk_surface_wayland_move_resize (GdkSurface *window,
- gboolean with_move,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (with_move)
- {
- /* Each toplevel has in its own "root" coordinate system */
- if (GDK_SURFACE_TYPE (window) != GDK_SURFACE_TOPLEVEL)
- {
- window->x = x;
- window->y = y;
- impl->position_method = POSITION_METHOD_MOVE_RESIZE;
-
- if (impl->display_server.wl_subsurface)
- {
- wl_subsurface_set_position (impl->display_server.wl_subsurface,
- window->x + window->abs_x,
- window->y + window->abs_y);
- gdk_surface_request_transient_parent_commit (window);
- }
- }
- }
-
- /* If this function is called with width and height = -1 then that means
- * just move the window - don't update its size
- */
- if (width > 0 && height > 0)
- gdk_wayland_surface_maybe_configure (window, width, height, impl->scale);
-}
-
-/* Avoid zero width/height as this is a protocol error */
-static void
-sanitize_anchor_rect (GdkSurface *window,
- GdkRectangle *rect)
-{
- gint original_width = rect->width;
- gint original_height = rect->height;
-
- rect->width = MAX (1, rect->width);
- rect->height = MAX (1, rect->height);
- rect->x = MAX (rect->x + original_width - rect->width, 0);
- rect->y = MAX (rect->y + original_height - rect->height, 0);
-}
-
-static void
-gdk_surface_wayland_move_to_rect (GdkSurface *window,
- const GdkRectangle *rect,
- GdkGravity rect_anchor,
- GdkGravity window_anchor,
- GdkAnchorHints anchor_hints,
- gint rect_anchor_dx,
- gint rect_anchor_dy)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- impl->pending_move_to_rect.rect = *rect;
- sanitize_anchor_rect (window, &impl->pending_move_to_rect.rect);
-
- impl->pending_move_to_rect.rect_anchor = rect_anchor;
- impl->pending_move_to_rect.window_anchor = window_anchor;
- impl->pending_move_to_rect.anchor_hints = anchor_hints;
- impl->pending_move_to_rect.rect_anchor_dx = rect_anchor_dx;
- impl->pending_move_to_rect.rect_anchor_dy = rect_anchor_dy;
-
- impl->position_method = POSITION_METHOD_MOVE_TO_RECT;
-}
-
-static void
-gdk_surface_wayland_get_geometry (GdkSurface *window,
- gint *x,
- gint *y,
- gint *width,
- gint *height)
-{
- if (!GDK_SURFACE_DESTROYED (window))
- {
- if (x)
- *x = window->x;
- if (y)
- *y = window->y;
- if (width)
- *width = window->width;
- if (height)
- *height = window->height;
- }
-}
-
-static void
-gdk_surface_wayland_get_root_coords (GdkSurface *window,
- gint x,
- gint y,
- gint *root_x,
- gint *root_y)
-{
- /*
- * Wayland does not have a global coordinate space shared between surfaces. In
- * fact, for regular toplevels, we have no idea where our surfaces are
- * positioned, relatively.
- *
- * However, there are some cases like popups and subsurfaces where we do have
- * some amount of control over the placement of our window, and we can
- * semi-accurately control the x/y position of these windows, if they are
- * relative to another surface.
- *
- * To pretend we have something called a root coordinate space, assume all
- * parent-less windows are positioned in (0, 0), and all relative positioned
- * popups and subsurfaces are placed within this fake root coordinate space.
- *
- * For example a 200x200 large toplevel window will have the position (0, 0).
- * If a popup positioned in the middle of the toplevel will have the fake
- * position (100,100). Furthermore, if a positioned is placed in the middle
- * that popup, will have the fake position (150,150), even though it has the
- * relative position (50,50). These three windows would make up one single
- * fake root coordinate space.
- */
-
- if (root_x)
- *root_x = window->x + x;
-
- if (root_y)
- *root_y = window->y + y;
-}
-
-static gboolean
-gdk_surface_wayland_get_device_state (GdkSurface *window,
- GdkDevice *device,
- gdouble *x,
- gdouble *y,
- GdkModifierType *mask)
-{
- gboolean return_val;
-
- g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), FALSE);
-
- return_val = TRUE;
-
- if (!GDK_SURFACE_DESTROYED (window))
- {
- GdkSurface *child;
-
- GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
- &child,
- NULL, NULL,
- x, y, mask);
- return_val = (child != NULL);
- }
-
- return return_val;
-}
-
-static void
-gdk_surface_wayland_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
-}
-
-static void
-gdk_surface_wayland_input_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- g_clear_pointer (&impl->input_region, cairo_region_destroy);
-
- if (shape_region)
- {
- impl->input_region = cairo_region_copy (shape_region);
- cairo_region_translate (impl->input_region, offset_x, offset_y);
- }
-
- impl->input_region_dirty = TRUE;
-}
-
-static void
-gdk_wayland_surface_destroy (GdkSurface *window,
- gboolean recursing,
- gboolean foreign_destroy)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- /* Wayland windows can't be externally destroyed; we may possibly
- * eventually want to use this path at display close-down
- */
- g_return_if_fail (!foreign_destroy);
-
- gdk_wayland_surface_hide_surface (window);
- drop_cairo_surfaces (window);
-
- if (window->parent == NULL)
- {
- GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- display->toplevels = g_list_remove (display->toplevels, window);
- }
-}
-
-static void
-gdk_wayland_surface_focus (GdkSurface *window,
- guint32 timestamp)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (!impl->display_server.gtk_surface)
- return;
-
- /* We didn't have an event to fetch a time from, meaning we have nothing valid
- * to send. This should rather be translated to a 'needs-attention' request or
- * something.
- */
- if (timestamp == GDK_CURRENT_TIME)
- return;
-
- gtk_surface1_present (impl->display_server.gtk_surface, timestamp);
-}
-
-static void
-gdk_wayland_surface_set_type_hint (GdkSurface *window,
- GdkSurfaceTypeHint hint)
-{
- GdkSurfaceImplWayland *impl;
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- impl->hint = hint;
-}
-
-static GdkSurfaceTypeHint
-gdk_wayland_surface_get_type_hint (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl;
-
- if (GDK_SURFACE_DESTROYED (window))
- return GDK_SURFACE_TYPE_HINT_NORMAL;
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- return impl->hint;
-}
-
-static void
-gtk_surface_configure (void *data,
- struct gtk_surface1 *gtk_surface,
- struct wl_array *states)
-{
- GdkSurface *window = GDK_SURFACE (data);
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkSurfaceState new_state = 0;
- uint32_t *p;
-
- wl_array_for_each (p, states)
- {
- uint32_t state = *p;
-
- switch (state)
- {
- case GTK_SURFACE1_STATE_TILED:
- new_state |= GDK_SURFACE_STATE_TILED;
- break;
-
- /* Since v2 */
- case GTK_SURFACE1_STATE_TILED_TOP:
- new_state |= (GDK_SURFACE_STATE_TILED | GDK_SURFACE_STATE_TOP_TILED);
- break;
- case GTK_SURFACE1_STATE_TILED_RIGHT:
- new_state |= (GDK_SURFACE_STATE_TILED | GDK_SURFACE_STATE_RIGHT_TILED);
- break;
- case GTK_SURFACE1_STATE_TILED_BOTTOM:
- new_state |= (GDK_SURFACE_STATE_TILED | GDK_SURFACE_STATE_BOTTOM_TILED);
- break;
- case GTK_SURFACE1_STATE_TILED_LEFT:
- new_state |= (GDK_SURFACE_STATE_TILED | GDK_SURFACE_STATE_LEFT_TILED);
- break;
- default:
- /* Unknown state */
- break;
- }
- }
-
- impl->pending.state |= new_state;
-}
-
-static void
-gtk_surface_configure_edges (void *data,
- struct gtk_surface1 *gtk_surface,
- struct wl_array *edge_constraints)
-{
- GdkSurface *window = GDK_SURFACE (data);
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkSurfaceState new_state = 0;
- uint32_t *p;
-
- wl_array_for_each (p, edge_constraints)
- {
- uint32_t constraint = *p;
-
- switch (constraint)
- {
- case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_TOP:
- new_state |= GDK_SURFACE_STATE_TOP_RESIZABLE;
- break;
- case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_RIGHT:
- new_state |= GDK_SURFACE_STATE_RIGHT_RESIZABLE;
- break;
- case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_BOTTOM:
- new_state |= GDK_SURFACE_STATE_BOTTOM_RESIZABLE;
- break;
- case GTK_SURFACE1_EDGE_CONSTRAINT_RESIZABLE_LEFT:
- new_state |= GDK_SURFACE_STATE_LEFT_RESIZABLE;
- break;
- default:
- /* Unknown state */
- break;
- }
- }
-
- impl->pending.state |= new_state;
-}
-
-static const struct gtk_surface1_listener gtk_surface_listener = {
- gtk_surface_configure,
- gtk_surface_configure_edges
-};
-
-static void
-gdk_wayland_surface_init_gtk_surface (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkWaylandDisplay *display =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
-
- if (impl->display_server.gtk_surface != NULL)
- return;
- if (impl->display_server.xdg_surface == NULL)
- return;
- if (display->gtk_shell == NULL)
- return;
-
- impl->display_server.gtk_surface =
- gtk_shell1_get_gtk_surface (display->gtk_shell,
- impl->display_server.wl_surface);
- gdk_surface_set_geometry_hints (window,
- &impl->geometry_hints,
- impl->geometry_mask);
- gtk_surface1_add_listener (impl->display_server.gtk_surface,
- >k_surface_listener,
- window);
-}
-
-static void
-maybe_set_gtk_surface_modal (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- gdk_wayland_surface_init_gtk_surface (window);
- if (impl->display_server.gtk_surface == NULL)
- return;
-
- if (window->modal_hint)
- gtk_surface1_set_modal (impl->display_server.gtk_surface);
- else
- gtk_surface1_unset_modal (impl->display_server.gtk_surface);
-
-}
-
-static void
-gdk_wayland_surface_set_modal_hint (GdkSurface *window,
- gboolean modal)
-{
- window->modal_hint = modal;
- maybe_set_gtk_surface_modal (window);
-}
-
-static void
-gdk_wayland_surface_set_skip_taskbar_hint (GdkSurface *window,
- gboolean skips_taskbar)
-{
-}
-
-static void
-gdk_wayland_surface_set_skip_pager_hint (GdkSurface *window,
- gboolean skips_pager)
-{
-}
-
-static void
-gdk_wayland_surface_set_urgency_hint (GdkSurface *window,
- gboolean urgent)
-{
-}
-
-static void
-gdk_wayland_surface_set_geometry_hints (GdkSurface *window,
- const GdkGeometry *geometry,
- GdkSurfaceHints geom_mask)
-{
- GdkSurfaceImplWayland *impl;
- int width, height;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- impl->geometry_hints = *geometry;
- impl->geometry_mask = geom_mask;
-
- if (!impl->display_server.xdg_toplevel)
- return;
-
- if (geom_mask & GDK_HINT_MIN_SIZE)
- {
- width = MAX (0, geometry->min_width - (impl->margin_left + impl->margin_right));
- height = MAX (0, geometry->min_height - (impl->margin_top + impl->margin_bottom));
- }
- else
- {
- width = 0;
- height = 0;
- }
-
- zxdg_toplevel_v6_set_min_size (impl->display_server.xdg_toplevel, width, height);
-
- if (geom_mask & GDK_HINT_MAX_SIZE)
- {
- width = MAX (0, geometry->max_width - (impl->margin_left + impl->margin_right));
- height = MAX (0, geometry->max_height - (impl->margin_top + impl->margin_bottom));
- }
- else
- {
- width = 0;
- height = 0;
- }
-
- zxdg_toplevel_v6_set_max_size (impl->display_server.xdg_toplevel, width, height);
-}
-
-static void
-gdk_wayland_surface_set_title (GdkSurface *window,
- const gchar *title)
-{
- GdkSurfaceImplWayland *impl;
- const char *end;
- gsize title_length;
-
- g_return_if_fail (title != NULL);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (g_strcmp0 (impl->title, title) == 0)
- return;
-
- g_free (impl->title);
-
- title_length = MIN (strlen (title), MAX_WL_BUFFER_SIZE);
- if (g_utf8_validate (title, title_length, &end))
- {
- impl->title = g_malloc (end - title + 1);
- memcpy (impl->title, title, end - title);
- impl->title[end - title] = '\0';
- }
- else
- {
- impl->title = g_utf8_make_valid (title, title_length);
- g_warning ("Invalid utf8 passed to gdk_surface_set_title: '%s'", title);
- }
-
- gdk_wayland_surface_sync_title (window);
-}
-
-static void
-gdk_wayland_surface_set_role (GdkSurface *window,
- const gchar *role)
-{
-}
-
-static void
-gdk_wayland_surface_set_startup_id (GdkSurface *window,
- const gchar *startup_id)
-{
-}
-
-static gboolean
-check_transient_for_loop (GdkSurface *window,
- GdkSurface *parent)
-{
- while (parent)
- {
- GdkSurfaceImplWayland *impl;
-
- if (!GDK_IS_SURFACE_IMPL_WAYLAND(parent->impl))
- return FALSE;
-
- impl = GDK_SURFACE_IMPL_WAYLAND (parent->impl);
- if (impl->transient_for == window)
- return TRUE;
- parent = impl->transient_for;
- }
- return FALSE;
-}
-
-static void
-gdk_wayland_surface_set_transient_for (GdkSurface *window,
- GdkSurface *parent)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkWaylandDisplay *display_wayland =
- GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- GdkSurface *previous_parent;
-
- g_assert (parent == NULL ||
- gdk_surface_get_display (window) == gdk_surface_get_display (parent));
-
- if (check_transient_for_loop (window, parent))
- {
- g_warning ("Setting %p transient for %p would create a loop", window, parent);
- return;
- }
-
- unset_transient_for_exported (window);
-
- if (impl->display_server.wl_subsurface)
- unmap_subsurface (window);
-
- previous_parent = impl->transient_for;
- impl->transient_for = parent;
-
- if (impl->hint == GDK_SURFACE_TYPE_HINT_DIALOG)
- {
- if (!parent)
- _gdk_wayland_screen_add_orphan_dialog (window);
- else if (!previous_parent)
- display_wayland->orphan_dialogs =
- g_list_remove (display_wayland->orphan_dialogs, window);
- }
- gdk_wayland_surface_sync_parent (window, NULL);
- if (should_map_as_subsurface (window) &&
- parent && gdk_surface_is_visible (window))
- gdk_wayland_surface_create_subsurface (window);
-}
-
-static void
-gdk_wayland_surface_get_frame_extents (GdkSurface *window,
- GdkRectangle *rect)
-{
- *rect = (GdkRectangle) {
- .x = window->x,
- .y = window->y,
- .width = window->width,
- .height = window->height
- };
-}
-
-static void
-gdk_wayland_surface_set_accept_focus (GdkSurface *window,
- gboolean accept_focus)
-{
-}
-
-static void
-gdk_wayland_surface_set_focus_on_map (GdkSurface *window,
- gboolean focus_on_map)
-{
-}
-
-static void
-gdk_wayland_surface_set_icon_list (GdkSurface *window,
- GList *surfaces)
-{
-}
-
-static void
-gdk_wayland_surface_set_icon_name (GdkSurface *window,
- const gchar *name)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return;
-}
-
-static void
-gdk_wayland_surface_iconify (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- if (!impl->display_server.xdg_toplevel)
- return;
-
- zxdg_toplevel_v6_set_minimized (impl->display_server.xdg_toplevel);
-}
-
-static void
-gdk_wayland_surface_deiconify (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- gdk_surface_show (window);
- else
- /* Flip our client side flag, the real work happens on map. */
- gdk_synthesize_window_state (window, GDK_SURFACE_STATE_ICONIFIED, 0);
-}
-
-static void
-gdk_wayland_surface_stick (GdkSurface *window)
-{
-}
-
-static void
-gdk_wayland_surface_unstick (GdkSurface *window)
-{
-}
-
-static void
-gdk_wayland_surface_maximize (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- _gdk_wayland_surface_save_size (window);
- if (impl->display_server.xdg_toplevel)
- zxdg_toplevel_v6_set_maximized (impl->display_server.xdg_toplevel);
- else
- gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_MAXIMIZED);
-}
-
-static void
-gdk_wayland_surface_unmaximize (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (impl->display_server.xdg_toplevel)
- zxdg_toplevel_v6_unset_maximized (impl->display_server.xdg_toplevel);
- else
- gdk_synthesize_window_state (window, GDK_SURFACE_STATE_MAXIMIZED, 0);
-}
-
-static void
-gdk_wayland_surface_fullscreen_on_monitor (GdkSurface *window,
- GdkMonitor *monitor)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- struct wl_output *output = ((GdkWaylandMonitor *)monitor)->output;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- _gdk_wayland_surface_save_size (window);
- if (impl->display_server.xdg_toplevel)
- {
- zxdg_toplevel_v6_set_fullscreen (impl->display_server.xdg_toplevel, output);
- }
- else
- {
- gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
- impl->initial_fullscreen_output = output;
- }
-}
-
-static void
-gdk_wayland_surface_fullscreen (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- impl->initial_fullscreen_output = NULL;
-
- _gdk_wayland_surface_save_size (window);
- if (impl->display_server.xdg_toplevel)
- zxdg_toplevel_v6_set_fullscreen (impl->display_server.xdg_toplevel, NULL);
- else
- gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
-}
-
-static void
-gdk_wayland_surface_unfullscreen (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- impl->initial_fullscreen_output = NULL;
-
- if (impl->display_server.xdg_toplevel)
- zxdg_toplevel_v6_unset_fullscreen (impl->display_server.xdg_toplevel);
- else
- gdk_synthesize_window_state (window, GDK_SURFACE_STATE_FULLSCREEN, 0);
-}
-
-static void
-gdk_wayland_surface_set_keep_above (GdkSurface *window, gboolean setting)
-{
-}
-
-static void
-gdk_wayland_surface_set_keep_below (GdkSurface *window, gboolean setting)
-{
-}
-
-static GdkSurface *
-gdk_wayland_surface_get_group (GdkSurface *window)
-{
- return NULL;
-}
-
-static void
-gdk_wayland_surface_set_group (GdkSurface *window,
- GdkSurface *leader)
-{
-}
-
-static void
-gdk_wayland_surface_set_decorations (GdkSurface *window,
- GdkWMDecoration decorations)
-{
-}
-
-static gboolean
-gdk_wayland_surface_get_decorations (GdkSurface *window,
- GdkWMDecoration *decorations)
-{
- return FALSE;
-}
-
-static void
-gdk_wayland_surface_set_functions (GdkSurface *window,
- GdkWMFunction functions)
-{
-}
-
-static void
-gdk_wayland_surface_begin_resize_drag (GdkSurface *window,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GdkSurfaceImplWayland *impl;
- GdkEventSequence *sequence;
- uint32_t resize_edges, serial;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- switch (edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT;
- break;
-
- case GDK_SURFACE_EDGE_NORTH:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP;
- break;
-
- case GDK_SURFACE_EDGE_NORTH_EAST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT;
- break;
-
- case GDK_SURFACE_EDGE_WEST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT;
- break;
-
- case GDK_SURFACE_EDGE_EAST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- resize_edges = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT;
- break;
-
- default:
- g_warning ("gdk_surface_begin_resize_drag: bad resize edge %d!", edge);
- return;
- }
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (!impl->display_server.xdg_toplevel)
- return;
-
- serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_device_get_seat (device),
- &sequence);
-
- zxdg_toplevel_v6_resize (impl->display_server.xdg_toplevel,
- gdk_wayland_device_get_wl_seat (device),
- serial, resize_edges);
-
- if (sequence)
- gdk_wayland_device_unset_touch_grab (device, sequence);
-
- /* This is needed since Wayland will absorb all the pointer events after the
- * above function - FIXME: Is this always safe..?
- */
- gdk_seat_ungrab (gdk_device_get_seat (device));
-}
-
-static void
-gdk_wayland_surface_begin_move_drag (GdkSurface *window,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GdkSurfaceImplWayland *impl;
- GdkEventSequence *sequence;
- uint32_t serial;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (!impl->display_server.xdg_toplevel)
- return;
-
- serial = _gdk_wayland_seat_get_last_implicit_grab_serial (gdk_device_get_seat (device),
- &sequence);
- zxdg_toplevel_v6_move (impl->display_server.xdg_toplevel,
- gdk_wayland_device_get_wl_seat (device),
- serial);
- if (sequence)
- gdk_wayland_device_unset_touch_grab (device, sequence);
-
- /* This is needed since Wayland will absorb all the pointer events after the
- * above function - FIXME: Is this always safe..?
- */
- gdk_seat_ungrab (gdk_device_get_seat (device));
-}
-
-static void
-gdk_wayland_surface_set_opacity (GdkSurface *window,
- gdouble opacity)
-{
-}
-
-static void
-gdk_wayland_surface_destroy_notify (GdkSurface *window)
-{
- if (!GDK_SURFACE_DESTROYED (window))
- {
- g_warning ("GdkSurface %p unexpectedly destroyed", window);
- _gdk_surface_destroy (window, TRUE);
- }
-
- g_object_unref (window);
-}
-
-static gint
-gdk_wayland_surface_get_scale_factor (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return 1;
-
- return impl->scale;
-}
-
-static void
-gdk_wayland_surface_set_opaque_region (GdkSurface *window,
- cairo_region_t *region)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
- impl->opaque_region = cairo_region_reference (region);
- impl->opaque_region_dirty = TRUE;
-}
-
-static void
-gdk_wayland_surface_set_shadow_width (GdkSurface *window,
- int left,
- int right,
- int top,
- int bottom)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- gint new_width, new_height;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- /* Reconfigure window to keep the same window geometry */
- new_width = window->width -
- (impl->margin_left + impl->margin_right) + (left + right);
- new_height = window->height -
- (impl->margin_top + impl->margin_bottom) + (top + bottom);
- gdk_wayland_surface_maybe_configure (window, new_width, new_height, impl->scale);
-
- impl->margin_left = left;
- impl->margin_right = right;
- impl->margin_top = top;
- impl->margin_bottom = bottom;
-}
-
-static gboolean
-gdk_wayland_surface_show_window_menu (GdkSurface *window,
- GdkEvent *event)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- struct wl_seat *seat;
- GdkWaylandDevice *device;
- double x, y;
- uint32_t serial;
-
- switch ((guint) event->any.type)
- {
- case GDK_BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- case GDK_TOUCH_BEGIN:
- case GDK_TOUCH_END:
- break;
- default:
- return FALSE;
- }
-
- if (!impl->display_server.xdg_surface)
- return FALSE;
-
- device = GDK_WAYLAND_DEVICE (gdk_event_get_device (event));
- seat = gdk_wayland_device_get_wl_seat (GDK_DEVICE (device));
- gdk_event_get_coords (event, &x, &y);
-
- serial = _gdk_wayland_device_get_implicit_grab_serial (device, event);
- zxdg_toplevel_v6_show_window_menu (impl->display_server.xdg_toplevel,
- seat, serial, x, y);
- return TRUE;
-}
-
-static gboolean
-gdk_wayland_surface_supports_edge_constraints (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- struct gtk_surface1 *gtk_surface = impl->display_server.gtk_surface;
-
- if (!gtk_surface)
- return FALSE;
-
- return gtk_surface1_get_version (gtk_surface) >= GTK_SURFACE1_CONFIGURE_EDGES_SINCE_VERSION;
-}
-
-static void
-_gdk_surface_impl_wayland_class_init (GdkSurfaceImplWaylandClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_CLASS (klass);
-
- object_class->finalize = gdk_surface_impl_wayland_finalize;
-
- impl_class->ref_cairo_surface = gdk_wayland_surface_ref_cairo_surface;
- impl_class->create_similar_image_surface = gdk_wayland_surface_create_similar_image_surface;
- impl_class->show = gdk_wayland_surface_show;
- impl_class->hide = gdk_wayland_surface_hide;
- impl_class->withdraw = gdk_surface_wayland_withdraw;
- impl_class->set_events = gdk_surface_wayland_set_events;
- impl_class->get_events = gdk_surface_wayland_get_events;
- impl_class->raise = gdk_surface_wayland_raise;
- impl_class->lower = gdk_surface_wayland_lower;
- impl_class->restack_toplevel = gdk_surface_wayland_restack_toplevel;
- impl_class->move_resize = gdk_surface_wayland_move_resize;
- impl_class->move_to_rect = gdk_surface_wayland_move_to_rect;
- impl_class->get_geometry = gdk_surface_wayland_get_geometry;
- impl_class->get_root_coords = gdk_surface_wayland_get_root_coords;
- impl_class->get_device_state = gdk_surface_wayland_get_device_state;
- impl_class->shape_combine_region = gdk_surface_wayland_shape_combine_region;
- impl_class->input_shape_combine_region = gdk_surface_wayland_input_shape_combine_region;
- impl_class->destroy = gdk_wayland_surface_destroy;
- impl_class->begin_paint = gdk_surface_impl_wayland_begin_paint;
- impl_class->end_paint = gdk_surface_impl_wayland_end_paint;
- impl_class->beep = gdk_surface_impl_wayland_beep;
-
- impl_class->focus = gdk_wayland_surface_focus;
- impl_class->set_type_hint = gdk_wayland_surface_set_type_hint;
- impl_class->get_type_hint = gdk_wayland_surface_get_type_hint;
- impl_class->set_modal_hint = gdk_wayland_surface_set_modal_hint;
- impl_class->set_skip_taskbar_hint = gdk_wayland_surface_set_skip_taskbar_hint;
- impl_class->set_skip_pager_hint = gdk_wayland_surface_set_skip_pager_hint;
- impl_class->set_urgency_hint = gdk_wayland_surface_set_urgency_hint;
- impl_class->set_geometry_hints = gdk_wayland_surface_set_geometry_hints;
- impl_class->set_title = gdk_wayland_surface_set_title;
- impl_class->set_role = gdk_wayland_surface_set_role;
- impl_class->set_startup_id = gdk_wayland_surface_set_startup_id;
- impl_class->set_transient_for = gdk_wayland_surface_set_transient_for;
- impl_class->get_frame_extents = gdk_wayland_surface_get_frame_extents;
- impl_class->set_accept_focus = gdk_wayland_surface_set_accept_focus;
- impl_class->set_focus_on_map = gdk_wayland_surface_set_focus_on_map;
- impl_class->set_icon_list = gdk_wayland_surface_set_icon_list;
- impl_class->set_icon_name = gdk_wayland_surface_set_icon_name;
- impl_class->iconify = gdk_wayland_surface_iconify;
- impl_class->deiconify = gdk_wayland_surface_deiconify;
- impl_class->stick = gdk_wayland_surface_stick;
- impl_class->unstick = gdk_wayland_surface_unstick;
- impl_class->maximize = gdk_wayland_surface_maximize;
- impl_class->unmaximize = gdk_wayland_surface_unmaximize;
- impl_class->fullscreen = gdk_wayland_surface_fullscreen;
- impl_class->fullscreen_on_monitor = gdk_wayland_surface_fullscreen_on_monitor;
- impl_class->unfullscreen = gdk_wayland_surface_unfullscreen;
- impl_class->set_keep_above = gdk_wayland_surface_set_keep_above;
- impl_class->set_keep_below = gdk_wayland_surface_set_keep_below;
- impl_class->get_group = gdk_wayland_surface_get_group;
- impl_class->set_group = gdk_wayland_surface_set_group;
- impl_class->set_decorations = gdk_wayland_surface_set_decorations;
- impl_class->get_decorations = gdk_wayland_surface_get_decorations;
- impl_class->set_functions = gdk_wayland_surface_set_functions;
- impl_class->begin_resize_drag = gdk_wayland_surface_begin_resize_drag;
- impl_class->begin_move_drag = gdk_wayland_surface_begin_move_drag;
- impl_class->set_opacity = gdk_wayland_surface_set_opacity;
- impl_class->destroy_notify = gdk_wayland_surface_destroy_notify;
- impl_class->register_dnd = _gdk_wayland_surface_register_dnd;
- impl_class->drag_begin = _gdk_wayland_surface_drag_begin;
- impl_class->get_scale_factor = gdk_wayland_surface_get_scale_factor;
- impl_class->set_opaque_region = gdk_wayland_surface_set_opaque_region;
- impl_class->set_shadow_width = gdk_wayland_surface_set_shadow_width;
- impl_class->show_window_menu = gdk_wayland_surface_show_window_menu;
- impl_class->create_gl_context = gdk_wayland_surface_create_gl_context;
- impl_class->supports_edge_constraints = gdk_wayland_surface_supports_edge_constraints;
-
- signals[COMMITTED] = g_signal_new (g_intern_static_string ("committed"),
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL, NULL,
- G_TYPE_NONE, 0);
-}
-
-void
-_gdk_wayland_surface_set_grab_seat (GdkSurface *window,
- GdkSeat *seat)
-{
- GdkSurfaceImplWayland *impl;
-
- g_return_if_fail (window != NULL);
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- impl->grab_input_seat = seat;
-}
-
-/**
- * gdk_wayland_surface_new_subsurface: (constructor)
- * @display: the display to create the window on
- * @position: position relative to the transient window
- *
- * Creates a new subsurface window.
- *
- * Returns: (transfer full): the new #GdkSurface
- **/
-GdkSurface *
-gdk_wayland_surface_new_subsurface (GdkDisplay *display,
- const GdkRectangle *position)
-{
- GdkSurfaceAttr attr;
-
- g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
- g_return_val_if_fail (position != NULL, NULL);
-
- attr.wclass = GDK_INPUT_OUTPUT;
- attr.x = position->x;
- attr.y = position->y;
- attr.width = position->width;
- attr.height = position->height;
- attr.window_type = GDK_SURFACE_SUBSURFACE;
-
- return gdk_surface_new (display, NULL, &attr);
-}
-
-/**
- * gdk_wayland_surface_get_wl_surface:
- * @window: (type GdkWaylandSurface): a #GdkSurface
- *
- * Returns the Wayland surface of a #GdkSurface.
- *
- * Returns: (transfer none): a Wayland wl_surface
- */
-struct wl_surface *
-gdk_wayland_surface_get_wl_surface (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), NULL);
-
- return GDK_SURFACE_IMPL_WAYLAND (window->impl)->display_server.wl_surface;
-}
-
-struct wl_output *
-gdk_wayland_surface_get_wl_output (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl;
-
- g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), NULL);
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- /* We pick the head of the list as this is the last entered output */
- if (impl->display_server.outputs)
- return (struct wl_output *) impl->display_server.outputs->data;
-
- return NULL;
-}
-
-static struct wl_egl_window *
-gdk_wayland_surface_get_wl_egl_window (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (impl->display_server.egl_window == NULL)
- {
- impl->display_server.egl_window =
- wl_egl_window_create (impl->display_server.wl_surface,
- impl->wrapper->width * impl->scale,
- impl->wrapper->height * impl->scale);
- wl_surface_set_buffer_scale (impl->display_server.wl_surface, impl->scale);
- }
-
- return impl->display_server.egl_window;
-}
-
-EGLSurface
-gdk_wayland_surface_get_egl_surface (GdkSurface *window,
- EGLConfig config)
-{
- GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- GdkSurfaceImplWayland *impl;
- struct wl_egl_window *egl_window;
-
- g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), NULL);
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (impl->egl_surface == NULL)
- {
- egl_window = gdk_wayland_surface_get_wl_egl_window (window);
-
- impl->egl_surface =
- eglCreateWindowSurface (display->egl_display, config, egl_window, NULL);
- }
-
- return impl->egl_surface;
-}
-
-EGLSurface
-gdk_wayland_surface_get_dummy_egl_surface (GdkSurface *window,
- EGLConfig config)
-{
- GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- GdkSurfaceImplWayland *impl;
-
- g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), NULL);
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (impl->dummy_egl_surface == NULL)
- {
- impl->display_server.dummy_egl_window =
- wl_egl_window_create (impl->display_server.wl_surface, 1, 1);
-
- impl->dummy_egl_surface =
- eglCreateWindowSurface (display->egl_display, config, impl->display_server.dummy_egl_window, NULL);
- }
-
- return impl->dummy_egl_surface;
-}
-
-struct gtk_surface1 *
-gdk_wayland_surface_get_gtk_surface (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), NULL);
-
- return GDK_SURFACE_IMPL_WAYLAND (window->impl)->display_server.gtk_surface;
-}
-
-/**
- * gdk_wayland_surface_set_use_custom_surface:
- * @window: (type GdkWaylandSurface): a #GdkSurface
- *
- * Marks a #GdkSurface as a custom Wayland surface. The application is
- * expected to register the surface as some type of surface using
- * some Wayland interface.
- *
- * A good example would be writing a panel or on-screen-keyboard as an
- * out-of-process helper - as opposed to having those in the compositor
- * process. In this case the underlying surface isn’t an xdg_shell
- * surface and the panel or OSK client need to identify the wl_surface
- * as a panel or OSK to the compositor. The assumption is that the
- * compositor will expose a private interface to the special client
- * that lets the client identify the wl_surface as a panel or such.
- *
- * This function should be called before a #GdkSurface is shown. This is
- * best done by connecting to the #GtkWidget::realize signal:
- *
- * |[<!-- language="C" -->
- * static void
- * widget_realize_cb (GtkWidget *widget)
- * {
- * GdkSurface *window;
- * struct wl_surface *surface;
- * struct input_panel_surface *ip_surface;
- *
- * window = gtk_widget_get_window (widget);
- * gdk_wayland_surface_set_custom_surface (window);
- *
- * surface = gdk_wayland_surface_get_wl_surface (window);
- * ip_surface = input_panel_get_input_panel_surface (input_panel, surface);
- * input_panel_surface_set_panel (ip_surface);
- * }
- *
- * static void
- * setup_window (GtkWindow *window)
- * {
- * g_signal_connect (window, "realize", G_CALLBACK (widget_realize_cb), NULL);
- * }
- * ]|
- */
-void
-gdk_wayland_surface_set_use_custom_surface (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl;
-
- g_return_if_fail (GDK_IS_WAYLAND_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (!impl->display_server.wl_surface)
- gdk_wayland_surface_create_surface (window);
-
- impl->use_custom_surface = TRUE;
-}
-
-static void
-maybe_set_gtk_surface_dbus_properties (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- if (impl->application.was_set)
- return;
-
- if (impl->application.application_id == NULL &&
- impl->application.app_menu_path == NULL &&
- impl->application.menubar_path == NULL &&
- impl->application.window_object_path == NULL &&
- impl->application.application_object_path == NULL &&
- impl->application.unique_bus_name == NULL)
- return;
-
- gdk_wayland_surface_init_gtk_surface (window);
- if (impl->display_server.gtk_surface == NULL)
- return;
-
- gtk_surface1_set_dbus_properties (impl->display_server.gtk_surface,
- impl->application.application_id,
- impl->application.app_menu_path,
- impl->application.menubar_path,
- impl->application.window_object_path,
- impl->application.application_object_path,
- impl->application.unique_bus_name);
- impl->application.was_set = TRUE;
-}
-
-void
-gdk_wayland_surface_set_dbus_properties_libgtk_only (GdkSurface *window,
- const char *application_id,
- const char *app_menu_path,
- const char *menubar_path,
- const char *window_object_path,
- const char *application_object_path,
- const char *unique_bus_name)
-{
- GdkSurfaceImplWayland *impl;
-
- g_return_if_fail (GDK_IS_WAYLAND_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- impl->application.application_id = g_strdup (application_id);
- impl->application.app_menu_path = g_strdup (app_menu_path);
- impl->application.menubar_path = g_strdup (menubar_path);
- impl->application.window_object_path = g_strdup (window_object_path);
- impl->application.application_object_path =
- g_strdup (application_object_path);
- impl->application.unique_bus_name = g_strdup (unique_bus_name);
-
- maybe_set_gtk_surface_dbus_properties (window);
-}
-
-void
-_gdk_wayland_surface_offset_next_wl_buffer (GdkSurface *window,
- int x,
- int y)
-{
- GdkSurfaceImplWayland *impl;
-
- g_return_if_fail (GDK_IS_WAYLAND_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- impl->pending_buffer_offset_x = x;
- impl->pending_buffer_offset_y = y;
-}
-
-static void
-xdg_exported_handle (void *data,
- struct zxdg_exported_v1 *zxdg_exported_v1,
- const char *handle)
-{
- GdkSurface *window = data;
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- impl->exported.callback (window, handle, impl->exported.user_data);
- g_clear_pointer (&impl->exported.user_data,
- impl->exported.destroy_func);
-}
-
-static const struct zxdg_exported_v1_listener xdg_exported_listener = {
- xdg_exported_handle
-};
-
-/**
- * GdkWaylandSurfaceExported:
- * @window: the #GdkSurface that is exported
- * @handle: the handle
- * @user_data: user data that was passed to gdk_wayland_surface_export_handle()
- *
- * Callback that gets called when the handle for a window has been
- * obtained from the Wayland compositor. The handle can be passed
- * to other processes, for the purpose of marking windows as transient
- * for out-of-process surfaces.
- */
-
-static gboolean
-gdk_wayland_surface_is_exported (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- return !!impl->display_server.xdg_exported;
-}
-
-/**
- * gdk_wayland_surface_export_handle:
- * @window: the #GdkSurface to obtain a handle for
- * @callback: callback to call with the handle
- * @user_data: user data for @callback
- * @destroy_func: destroy notify for @user_data
- *
- * Asynchronously obtains a handle for a surface that can be passed
- * to other processes. When the handle has been obtained, @callback
- * will be called.
- *
- * It is an error to call this function on a window that is already
- * exported.
- *
- * When the handle is no longer needed, gdk_wayland_surface_unexport_handle()
- * should be called to clean up resources.
- *
- * The main purpose for obtaining a handle is to mark a surface
- * from another window as transient for this one, see
- * gdk_wayland_surface_set_transient_for_exported().
- *
- * Note that this API depends on an unstable Wayland protocol,
- * and thus may require changes in the future.
- *
- * Return value: %TRUE if the handle has been requested, %FALSE if
- * an error occurred.
- */
-gboolean
-gdk_wayland_surface_export_handle (GdkSurface *window,
- GdkWaylandSurfaceExported callback,
- gpointer user_data,
- GDestroyNotify destroy_func)
-{
- GdkSurfaceImplWayland *impl;
- GdkWaylandDisplay *display_wayland;
- GdkDisplay *display = gdk_surface_get_display (window);
- struct zxdg_exported_v1 *xdg_exported;
-
- g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), FALSE);
- g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- display_wayland = GDK_WAYLAND_DISPLAY (display);
-
- g_return_val_if_fail (!impl->display_server.xdg_exported, FALSE);
-
- if (!display_wayland->xdg_exporter)
- {
- g_warning ("Server is missing xdg_foreign support");
- return FALSE;
- }
-
- xdg_exported = zxdg_exporter_v1_export (display_wayland->xdg_exporter,
- impl->display_server.wl_surface);
- zxdg_exported_v1_add_listener (xdg_exported, &xdg_exported_listener, window);
-
- impl->display_server.xdg_exported = xdg_exported;
- impl->exported.callback = callback;
- impl->exported.user_data = user_data;
- impl->exported.destroy_func = destroy_func;
-
- return TRUE;
-}
-
-/**
- * gdk_wayland_surface_unexport_handle:
- * @window: the #GdkSurface to unexport
- *
- * Destroys the handle that was obtained with
- * gdk_wayland_surface_export_handle().
- *
- * It is an error to call this function on a window that
- * does not have a handle.
- *
- * Note that this API depends on an unstable Wayland protocol,
- * and thus may require changes in the future.
- */
-void
-gdk_wayland_surface_unexport_handle (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl;
-
- g_return_if_fail (GDK_IS_WAYLAND_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- g_return_if_fail (impl->display_server.xdg_exported);
-
- g_clear_pointer (&impl->display_server.xdg_exported,
- zxdg_exported_v1_destroy);
- g_clear_pointer (&impl->exported.user_data,
- impl->exported.destroy_func);
-}
-
-static void
-unset_transient_for_exported (GdkSurface *window)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
-
- g_clear_pointer (&impl->imported_transient_for, zxdg_imported_v1_destroy);
-}
-
-static void
-xdg_imported_destroyed (void *data,
- struct zxdg_imported_v1 *zxdg_imported_v1)
-{
- GdkSurface *window = data;
-
- unset_transient_for_exported (window);
-}
-
-static const struct zxdg_imported_v1_listener xdg_imported_listener = {
- xdg_imported_destroyed,
-};
-
-/**
- * gdk_wayland_surface_set_transient_for_exported:
- * @window: the #GdkSurface to make as transient
- * @parent_handle_str: an exported handle for a surface
- *
- * Marks @window as transient for the surface to which the given
- * @parent_handle_str refers. Typically, the handle will originate
- * from a gdk_wayland_surface_export_handle() call in another process.
- *
- * Note that this API depends on an unstable Wayland protocol,
- * and thus may require changes in the future.
- *
- * Return value: %TRUE if the window has been marked as transient,
- * %FALSE if an error occurred.
- */
-gboolean
-gdk_wayland_surface_set_transient_for_exported (GdkSurface *window,
- char *parent_handle_str)
-{
- GdkSurfaceImplWayland *impl;
- GdkWaylandDisplay *display_wayland;
- GdkDisplay *display = gdk_surface_get_display (window);
-
- g_return_val_if_fail (GDK_IS_WAYLAND_SURFACE (window), FALSE);
- g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), FALSE);
- g_return_val_if_fail (!should_map_as_subsurface (window) &&
- !should_map_as_popup (window), FALSE);
-
- impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- display_wayland = GDK_WAYLAND_DISPLAY (display);
-
- if (!display_wayland->xdg_importer)
- {
- g_warning ("Server is missing xdg_foreign support");
- return FALSE;
- }
-
- gdk_surface_set_transient_for (window, NULL);
-
- impl->imported_transient_for =
- zxdg_importer_v1_import (display_wayland->xdg_importer, parent_handle_str);
- zxdg_imported_v1_add_listener (impl->imported_transient_for,
- &xdg_imported_listener,
- window);
-
- gdk_wayland_surface_sync_parent_of_imported (window);
-
- return TRUE;
-}
-
-static struct zwp_keyboard_shortcuts_inhibitor_v1 *
-gdk_wayland_surface_get_inhibitor (GdkSurfaceImplWayland *impl,
- struct wl_seat *seat)
-{
- return g_hash_table_lookup (impl->shortcuts_inhibitors, seat);
-}
-
-void
-gdk_wayland_surface_inhibit_shortcuts (GdkSurface *window,
- GdkSeat *gdk_seat)
-{
- GdkSurfaceImplWayland *impl= GDK_SURFACE_IMPL_WAYLAND (window->impl);
- GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (window));
- struct wl_surface *surface = impl->display_server.wl_surface;
- struct wl_seat *seat = gdk_wayland_seat_get_wl_seat (gdk_seat);
- struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
-
- if (display->keyboard_shortcuts_inhibit == NULL)
- return;
-
- if (gdk_wayland_surface_get_inhibitor (impl, seat))
- return; /* Already inhibitted */
-
- inhibitor =
- zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts (
- display->keyboard_shortcuts_inhibit, surface, seat);
-
- g_hash_table_insert (impl->shortcuts_inhibitors, seat, inhibitor);
-}
-
-void
-gdk_wayland_surface_restore_shortcuts (GdkSurface *window,
- GdkSeat *gdk_seat)
-{
- GdkSurfaceImplWayland *impl = GDK_SURFACE_IMPL_WAYLAND (window->impl);
- struct wl_seat *seat = gdk_wayland_seat_get_wl_seat (gdk_seat);
- struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
-
- inhibitor = gdk_wayland_surface_get_inhibitor (impl, seat);
- if (inhibitor == NULL)
- return; /* Not inhibitted */
-
- zwp_keyboard_shortcuts_inhibitor_v1_destroy (inhibitor);
- g_hash_table_remove (impl->shortcuts_inhibitors, seat);
-}
-
'gdkprimary-wayland.c',
'gdkselection-wayland.c',
'gdkvulkancontext-wayland.c',
- 'gdkwindow-wayland.c',
+ 'gdksurface-wayland.c',
'wm-button-layout-translation.c',
])
'gdkwaylanddisplay.h',
'gdkwaylandglcontext.h',
'gdkwaylandmonitor.h',
- 'gdkwaylandwindow.h'
+ 'gdkwaylandsurface.h'
])
install_headers(gdk_wayland_public_headers, subdir: 'gtk-4.0/gdk/wayland/')
/* Convert a pixbuf to an HICON (or HCURSOR). Supports alpha under
* Windows XP, thresholds alpha otherwise. Also used from
- * gdkwindow-win32.c for creating application icons.
+ * gdksurface-win32.c for creating application icons.
*/
static HBITMAP
#include "config.h"
-#include <gdk/gdkwindow.h>
+#include <gdk/gdksurface.h>
#include <windowsx.h>
#include <objbase.h>
#include "config.h"
-#include <gdk/gdkwindow.h>
+#include <gdk/gdksurface.h>
#include <windowsx.h>
#include <objbase.h>
#include "config.h"
-#include <gdk/gdkwindow.h>
+#include <gdk/gdksurface.h>
#include <windowsx.h>
#include <objbase.h>
#include "gdkglcontext-win32.h"
#include "gdkwin32display.h"
#include "gdkwin32screen.h"
-#include "gdkwin32window.h"
+#include "gdkwin32surface.h"
#include "gdkmonitor-win32.h"
#include "gdkwin32.h"
#include "gdkvulkancontext-win32.h"
#include "config.h"
#include "gdkprivate-win32.h"
-#include "gdkwindow-win32.h"
+#include "gdksurface-win32.h"
#include "gdkglcontext-win32.h"
#include "gdkdisplay-win32.h"
#include "gdkwin32glcontext.h"
#include "gdkwin32misc.h"
#include "gdkwin32screen.h"
-#include "gdkwin32window.h"
+#include "gdkwin32surface.h"
#include "gdkglcontext.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkinternals.h"
#include "gdkintl.h"
#include "gdkglcontextprivate.h"
#include "gdkdisplayprivate.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkinternals.h"
G_BEGIN_DECLS
#endif
#include <gdk/gdkcursorprivate.h>
-#include <gdk/win32/gdkwindow-win32.h>
+#include <gdk/win32/gdksurface-win32.h>
#include <gdk/win32/gdkwin32display.h>
#include <gdk/win32/gdkwin32screen.h>
#include <gdk/win32/gdkwin32keys.h>
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1998-2004 Tor Lillqvist
+ * Copyright (C) 2001-2011 Hans Breuer
+ * Copyright (C) 2007-2009 Cody Russell
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+
+#include "gdk.h"
+#include "gdksurfaceimpl.h"
+#include "gdkprivate-win32.h"
+#include "gdkdeviceprivate.h"
+#include "gdkdevicemanager-win32.h"
+#include "gdkenumtypes.h"
+#include "gdkwin32.h"
+#include "gdkdisplayprivate.h"
+#include "gdkmonitorprivate.h"
+#include "gdkwin32surface.h"
+#include "gdkglcontext-win32.h"
+#include "gdkdisplay-win32.h"
+
+#include <cairo-win32.h>
+#include <dwmapi.h>
+#include <math.h>
+#include "fallback-c89.c"
+
+static void gdk_surface_impl_win32_init (GdkSurfaceImplWin32 *window);
+static void gdk_surface_impl_win32_class_init (GdkSurfaceImplWin32Class *klass);
+static void gdk_surface_impl_win32_finalize (GObject *object);
+
+static gpointer parent_class = NULL;
+static GSList *modal_window_stack = NULL;
+
+static const cairo_user_data_key_t gdk_win32_cairo_key;
+typedef struct _FullscreenInfo FullscreenInfo;
+
+struct _FullscreenInfo
+{
+ RECT r;
+ guint hint_flags;
+ LONG style;
+};
+
+struct _AeroSnapEdgeRegion
+{
+ /* The rectangle along the edge of the desktop
+ * that allows application of the snap transformation.
+ */
+ GdkRectangle edge;
+
+ /* A subregion of the "edge". When the pointer hits
+ * this region, the transformation is revealed.
+ * Usually it is 1-pixel thick and is located at the
+ * very edge of the screen. When there's a toolbar
+ * at that edge, the "trigger" and the "edge" regions
+ * are extended to cover that toolbar.
+ */
+ GdkRectangle trigger;
+};
+
+typedef struct _AeroSnapEdgeRegion AeroSnapEdgeRegion;
+
+/* Use this for hWndInsertAfter (2nd argument to SetWindowPos()) if
+ * SWP_NOZORDER flag is used. Otherwise it's unobvious why a particular
+ * argument is used. Using NULL is misleading, because
+ * NULL is equivalent to HWND_TOP.
+ */
+#define SWP_NOZORDER_SPECIFIED HWND_TOP
+
+/* Size of the regions at the edges of the desktop where
+ * snapping can take place (in pixels)
+ */
+#define AEROSNAP_REGION_THICKNESS (20)
+/* Size of the subregions that actually trigger the snapping prompt
+ * (in pixels).
+ */
+#define AEROSNAP_REGION_TRIGGER_THICKNESS (1)
+
+/* The gap between the snap indicator and the edge of the work area
+ * (in pixels).
+ */
+#define AEROSNAP_INDICATOR_EDGE_GAP (10)
+
+/* Width of the outline of the snap indicator
+ * (in pixels).
+ */
+#define AEROSNAP_INDICATOR_LINE_WIDTH (3.0)
+
+/* Corner radius of the snap indicator.
+ */
+#define AEROSNAP_INDICATOR_CORNER_RADIUS (3.0)
+
+/* The time it takes for snap indicator to expand/shrink
+ * from current window size to future position of the
+ * snapped window (in microseconds).
+ */
+#define AEROSNAP_INDICATOR_ANIMATION_DURATION (200 * 1000)
+
+/* Opacity if the snap indicator. */
+#define AEROSNAP_INDICATOR_OPACITY (0.5)
+
+/* The interval between snap indicator redraws (in milliseconds).
+ * 16 is ~ 1/60 of a second, for ~60 FPS.
+ */
+#define AEROSNAP_INDICATOR_ANIMATION_TICK (16)
+
+static gboolean _gdk_surface_get_functions (GdkSurface *window,
+ GdkWMFunction *functions);
+static HDC _gdk_win32_impl_acquire_dc (GdkSurfaceImplWin32 *impl);
+static void _gdk_win32_impl_release_dc (GdkSurfaceImplWin32 *impl);
+
+#define WINDOW_IS_TOPLEVEL(window) \
+ (GDK_SURFACE_TYPE (window) != GDK_SURFACE_FOREIGN)
+
+struct _GdkWin32Surface {
+ GdkSurface parent;
+};
+
+struct _GdkWin32SurfaceClass {
+ GdkSurfaceClass parent_class;
+};
+
+G_DEFINE_TYPE (GdkWin32Surface, gdk_win32_surface, GDK_TYPE_SURFACE)
+
+static void
+gdk_win32_surface_class_init (GdkWin32SurfaceClass *window_class)
+{
+}
+
+static void
+gdk_win32_surface_init (GdkWin32Surface *window)
+{
+}
+
+
+G_DEFINE_TYPE (GdkSurfaceImplWin32, gdk_surface_impl_win32, GDK_TYPE_SURFACE_IMPL)
+
+GType
+_gdk_surface_impl_win32_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (!object_type)
+ {
+ const GTypeInfo object_info =
+ {
+ sizeof (GdkSurfaceImplWin32Class),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gdk_surface_impl_win32_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GdkSurfaceImplWin32),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gdk_surface_impl_win32_init,
+ };
+
+ object_type = g_type_register_static (GDK_TYPE_SURFACE_IMPL,
+ "GdkSurfaceImplWin32",
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+static void
+gdk_surface_impl_win32_init (GdkSurfaceImplWin32 *impl)
+{
+ GdkDisplay *display = gdk_display_get_default ();
+
+ impl->toplevel_window_type = -1;
+ impl->hicon_big = NULL;
+ impl->hicon_small = NULL;
+ impl->hint_flags = 0;
+ impl->type_hint = GDK_SURFACE_TYPE_HINT_NORMAL;
+ impl->transient_owner = NULL;
+ impl->transient_children = NULL;
+ impl->num_transients = 0;
+ impl->changing_state = FALSE;
+ impl->window_scale = 1;
+}
+
+static void
+gdk_surface_impl_win32_finalize (GObject *object)
+{
+ GdkSurface *wrapper;
+ GdkSurfaceImplWin32 *window_impl;
+
+ g_return_if_fail (GDK_IS_SURFACE_IMPL_WIN32 (object));
+
+ window_impl = GDK_SURFACE_IMPL_WIN32 (object);
+
+ wrapper = window_impl->wrapper;
+
+ if (!GDK_SURFACE_DESTROYED (wrapper))
+ {
+ gdk_win32_handle_table_remove (window_impl->handle);
+ }
+
+ g_clear_pointer (&window_impl->snap_stash, g_free);
+ g_clear_pointer (&window_impl->snap_stash_int, g_free);
+
+ if (window_impl->hicon_big != NULL)
+ {
+ GDI_CALL (DestroyIcon, (window_impl->hicon_big));
+ window_impl->hicon_big = NULL;
+ }
+
+ if (window_impl->hicon_small != NULL)
+ {
+ GDI_CALL (DestroyIcon, (window_impl->hicon_small));
+ window_impl->hicon_small = NULL;
+ }
+
+ g_free (window_impl->decorations);
+
+ if (window_impl->cache_surface)
+ {
+ cairo_surface_destroy (window_impl->cache_surface);
+ window_impl->cache_surface = NULL;
+ }
+
+ if (window_impl->cairo_surface)
+ {
+ cairo_surface_destroy (window_impl->cairo_surface);
+ window_impl->cairo_surface = NULL;
+ }
+
+ g_assert (window_impl->transient_owner == NULL);
+ g_assert (window_impl->transient_children == NULL);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gdk_win32_get_window_client_area_rect (GdkSurface *window,
+ gint scale,
+ RECT *rect)
+{
+ gint x, y, width, height;
+
+ gdk_surface_get_position (window, &x, &y);
+ width = gdk_surface_get_width (window);
+ height = gdk_surface_get_height (window);
+ rect->left = x * scale;
+ rect->top = y * scale;
+ rect->right = rect->left + width * scale;
+ rect->bottom = rect->top + height * scale;
+}
+
+static void
+gdk_win32_surface_get_queued_window_rect (GdkSurface *window,
+ RECT *return_window_rect)
+{
+ RECT window_rect;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ gdk_win32_get_window_client_area_rect (window, impl->window_scale, &window_rect);
+
+ /* Turn client area into window area */
+ _gdk_win32_adjust_client_rect (window, &window_rect);
+
+ /* Convert GDK screen coordinates to W32 desktop coordinates */
+ window_rect.left -= _gdk_offset_x * impl->window_scale;
+ window_rect.right -= _gdk_offset_x * impl->window_scale;
+ window_rect.top -= _gdk_offset_y * impl->window_scale;
+ window_rect.bottom -= _gdk_offset_y * impl->window_scale;
+
+ *return_window_rect = window_rect;
+}
+
+static void
+gdk_win32_surface_apply_queued_move_resize (GdkSurface *window,
+ RECT window_rect)
+{
+ if (!IsIconic (GDK_SURFACE_HWND (window)))
+ {
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ GDK_NOTE (EVENTS, g_print ("Setting window position ... "));
+
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ SWP_NOZORDER_SPECIFIED,
+ window_rect.left, window_rect.top,
+ window_rect.right - window_rect.left,
+ window_rect.bottom - window_rect.top,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW));
+
+ GDK_NOTE (EVENTS, g_print (" ... set window position\n"));
+
+ return;
+ }
+
+ /* Don't move iconic windows */
+ /* TODO: use SetWindowPlacement() to change non-minimized window position */
+}
+
+static gboolean
+gdk_win32_surface_begin_paint (GdkSurface *window)
+{
+ GdkSurfaceImplWin32 *impl;
+ RECT window_rect;
+
+ if (window == NULL || GDK_SURFACE_DESTROYED (window))
+ return TRUE;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ /* Layered windows are moved *after* repaint.
+ * We supply our own surface, return FALSE to make GDK use it.
+ */
+ if (impl->layered)
+ return FALSE;
+
+ /* FIXME: Possibly remove the following lines when we transition to GL
+ * drawing fully. This will probably mean that we won't
+ * be able to use layered windows, as layered windows seem
+ * to support only up to OpenGL 1.1, which is not enough for our
+ * needs here.
+ */
+
+ /* Non-GL windows are moved *after* repaint.
+ * We don't supply our own surface, return TRUE to make GDK create
+ * one by itself.
+ *//*
+ if (!window->current_paint.use_gl)
+ return TRUE;*/
+
+ /* GL windows are moved *before* repaint (otherwise
+ * repainting doesn't work), but if there's no move queued up,
+ * return immediately. Doesn't matter what we return, GDK
+ * will create a surface anyway, as if we returned TRUE.
+ */
+ if (!impl->drag_move_resize_context.native_move_resize_pending)
+ return TRUE;
+
+ impl->drag_move_resize_context.native_move_resize_pending = FALSE;
+
+ /* Get the position/size of the window that GDK wants,
+ * apply it.
+ */
+ gdk_win32_surface_get_queued_window_rect (window, &window_rect);
+ gdk_win32_surface_apply_queued_move_resize (window, window_rect);
+
+ return TRUE;
+}
+
+static void
+gdk_win32_surface_end_paint (GdkSurface *window)
+{
+ /* FIXME: Possibly make gdk_win32_surface_end_paint() a
+ * no-op stub, like what is done in Wayland, as
+ * the items here rely on layered window usage,
+ * when we transition to full GL drawing, as
+ * layered windows do not support enough GL
+ * for our needs here
+ */
+ GdkSurfaceImplWin32 *impl;
+ RECT window_rect;
+ HDC hdc;
+ POINT window_position;
+ SIZE window_size;
+ POINT source_point;
+ BLENDFUNCTION blender;
+ cairo_t *cr;
+
+ if (window == NULL || GDK_SURFACE_DESTROYED (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ /* GL windows are moved *before* repaint */
+ /*if (window->current_paint.use_gl)
+ return;*/
+
+ /* No move/resize is queued up, and we don't need to update
+ * the contents of a layered window, so return immediately.
+ */
+ if (!impl->layered &&
+ !impl->drag_move_resize_context.native_move_resize_pending)
+ return;
+
+ impl->drag_move_resize_context.native_move_resize_pending = FALSE;
+
+ /* Get the position/size of the window that GDK wants. */
+ gdk_win32_surface_get_queued_window_rect (window, &window_rect);
+
+ if (!impl->layered)
+ {
+ gdk_win32_surface_apply_queued_move_resize (window, window_rect);
+
+ return;
+ }
+
+ window_position.x = window_rect.left;
+ window_position.y = window_rect.top;
+
+ window_size.cx = window_rect.right - window_rect.left;
+ window_size.cy = window_rect.bottom - window_rect.top;
+
+ cairo_surface_flush (impl->cairo_surface);
+
+ /* we always draw in the top-left corner of the surface */
+ source_point.x = source_point.y = 0;
+
+ blender.BlendOp = AC_SRC_OVER;
+ blender.BlendFlags = 0;
+ blender.AlphaFormat = AC_SRC_ALPHA;
+ blender.SourceConstantAlpha = impl->layered_opacity * 255;
+
+ /* Update cache surface contents */
+ cr = cairo_create (impl->cache_surface);
+
+ cairo_set_source_surface (cr, window->current_paint.surface, 0, 0);
+ gdk_cairo_region (cr, window->current_paint.region);
+ cairo_clip (cr);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+
+ cairo_surface_flush (impl->cache_surface);
+ hdc = cairo_win32_surface_get_dc (impl->cache_surface);
+
+ /* Don't use UpdateLayeredWindow on minimized windows */
+ if (IsIconic (GDK_SURFACE_HWND (window)))
+ {
+ gdk_win32_surface_apply_queued_move_resize (window, window_rect);
+
+ return;
+ }
+
+ /* Move, resize and redraw layered window in one call */
+ API_CALL (UpdateLayeredWindow, (GDK_SURFACE_HWND (window), NULL,
+ &window_position, &window_size,
+ hdc, &source_point,
+ 0, &blender, ULW_ALPHA));
+}
+
+void
+_gdk_win32_adjust_client_rect (GdkSurface *window,
+ RECT *rect)
+{
+ LONG style, exstyle;
+
+ style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
+ exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
+ API_CALL (AdjustWindowRectEx, (rect, style, FALSE, exstyle));
+}
+
+gboolean
+_gdk_win32_surface_enable_transparency (GdkSurface *window)
+{
+ GdkSurfaceImplWin32 *impl;
+ DWM_BLURBEHIND blur_behind;
+ HRGN empty_region;
+ HRESULT call_result;
+ HWND parent, thiswindow;
+
+ if (window == NULL || GDK_SURFACE_HWND (window) == NULL)
+ return FALSE;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ /* layered windows don't need blurbehind for transparency */
+ if (impl->layered)
+ return TRUE;
+
+ if (!gdk_display_is_composited (gdk_surface_get_display (window)))
+ return FALSE;
+
+ thiswindow = GDK_SURFACE_HWND (window);
+
+ /* Blurbehind only works on toplevel windows */
+ parent = GetAncestor (thiswindow, GA_PARENT);
+ if (!(GetWindowLong (thiswindow, GWL_STYLE) & WS_POPUP) &&
+ (parent == NULL || parent != GetDesktopWindow ()))
+ return FALSE;
+
+ empty_region = CreateRectRgn (0, 0, -1, -1);
+
+ if (empty_region == NULL)
+ return FALSE;
+
+ memset (&blur_behind, 0, sizeof (blur_behind));
+ blur_behind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ blur_behind.hRgnBlur = empty_region;
+ blur_behind.fEnable = TRUE;
+ call_result = DwmEnableBlurBehindWindow (thiswindow, &blur_behind);
+
+ if (!SUCCEEDED (call_result))
+ g_warning ("%s: %s (%p) failed: %" G_GINT32_MODIFIER "x",
+ G_STRLOC, "DwmEnableBlurBehindWindow", thiswindow, (guint32) call_result);
+
+ DeleteObject (empty_region);
+
+ return SUCCEEDED (call_result);
+}
+
+static const gchar *
+get_default_title (void)
+{
+ const char *title;
+ title = g_get_application_name ();
+ if (!title)
+ title = g_get_prgname ();
+
+ return title;
+}
+
+/* RegisterGdkClass
+ * is a wrapper function for RegisterWindowClassEx.
+ * It creates at least one unique class for every
+ * GdkSurfaceType. If support for single window-specific icons
+ * is ever needed (e.g Dialog specific), every such window should
+ * get its own class
+ */
+static ATOM
+RegisterGdkClass (GdkSurfaceType wtype, GdkSurfaceTypeHint wtype_hint)
+{
+ static ATOM klassTOPLEVEL = 0;
+ static ATOM klassCHILD = 0;
+ static ATOM klassTEMP = 0;
+ static ATOM klassTEMPSHADOW = 0;
+ static HICON hAppIcon = NULL;
+ static HICON hAppIconSm = NULL;
+ static WNDCLASSEXW wcl;
+ ATOM klass = 0;
+
+ wcl.cbSize = sizeof (WNDCLASSEX);
+ wcl.style = 0; /* DON'T set CS_<H,V>REDRAW. It causes total redraw
+ * on WM_SIZE and WM_MOVE. Flicker, Performance!
+ */
+ wcl.lpfnWndProc = _gdk_win32_surface_procedure;
+ wcl.cbClsExtra = 0;
+ wcl.cbWndExtra = 0;
+ wcl.hInstance = _gdk_app_hmodule;
+ wcl.hIcon = 0;
+ wcl.hIconSm = 0;
+
+ /* initialize once! */
+ if (0 == hAppIcon && 0 == hAppIconSm)
+ {
+ gchar sLoc [MAX_PATH+1];
+
+ if (0 != GetModuleFileName (_gdk_app_hmodule, sLoc, MAX_PATH))
+ {
+ ExtractIconEx (sLoc, 0, &hAppIcon, &hAppIconSm, 1);
+
+ if (0 == hAppIcon && 0 == hAppIconSm)
+ {
+ if (0 != GetModuleFileName (_gdk_dll_hinstance, sLoc, MAX_PATH))
+ {
+ ExtractIconEx (sLoc, 0, &hAppIcon, &hAppIconSm, 1);
+ }
+ }
+ }
+
+ if (0 == hAppIcon && 0 == hAppIconSm)
+ {
+ hAppIcon = LoadImage (NULL, IDI_APPLICATION, IMAGE_ICON,
+ GetSystemMetrics (SM_CXICON),
+ GetSystemMetrics (SM_CYICON), 0);
+ hAppIconSm = LoadImage (NULL, IDI_APPLICATION, IMAGE_ICON,
+ GetSystemMetrics (SM_CXSMICON),
+ GetSystemMetrics (SM_CYSMICON), 0);
+ }
+ }
+
+ if (0 == hAppIcon)
+ hAppIcon = hAppIconSm;
+ else if (0 == hAppIconSm)
+ hAppIconSm = hAppIcon;
+
+ wcl.lpszMenuName = NULL;
+
+ /* initialize once per class */
+ /*
+ * HB: Setting the background brush leads to flicker, because we
+ * don't get asked how to clear the background. This is not what
+ * we want, at least not for input_only windows ...
+ */
+#define ONCE_PER_CLASS() \
+ wcl.hIcon = CopyIcon (hAppIcon); \
+ wcl.hIconSm = CopyIcon (hAppIconSm); \
+ wcl.hbrBackground = NULL; \
+ wcl.hCursor = LoadCursor (NULL, IDC_ARROW);
+
+ switch (wtype)
+ {
+ case GDK_SURFACE_TOPLEVEL:
+ /* MSDN: CS_OWNDC is needed for OpenGL contexts */
+ wcl.style |= CS_OWNDC;
+ if (0 == klassTOPLEVEL)
+ {
+ wcl.lpszClassName = L"gdkWindowToplevel";
+
+ ONCE_PER_CLASS ();
+ klassTOPLEVEL = RegisterClassExW (&wcl);
+ }
+ klass = klassTOPLEVEL;
+ break;
+
+ case GDK_SURFACE_TEMP:
+ if ((wtype_hint == GDK_SURFACE_TYPE_HINT_MENU) ||
+ (wtype_hint == GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU) ||
+ (wtype_hint == GDK_SURFACE_TYPE_HINT_POPUP_MENU))
+ {
+ if (klassTEMPSHADOW == 0)
+ {
+ wcl.lpszClassName = L"gdkWindowTempShadow";
+ wcl.style |= CS_SAVEBITS;
+ wcl.style |= 0x00020000; /* CS_DROPSHADOW */
+
+ ONCE_PER_CLASS ();
+ klassTEMPSHADOW = RegisterClassExW (&wcl);
+ }
+
+ klass = klassTEMPSHADOW;
+ }
+ else
+ {
+ if (klassTEMP == 0)
+ {
+ wcl.lpszClassName = L"gdkWindowTemp";
+ wcl.style |= CS_SAVEBITS;
+ ONCE_PER_CLASS ();
+ klassTEMP = RegisterClassExW (&wcl);
+ }
+
+ klass = klassTEMP;
+ }
+ break;
+
+ case GDK_SURFACE_CHILD:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (klass == 0)
+ {
+ WIN32_API_FAILED ("RegisterClassExW");
+ g_error ("That is a fatal error");
+ }
+ return klass;
+}
+
+/*
+ * Create native windows.
+ *
+ * With the default Gdk the created windows are mostly toplevel windows.
+ *
+ * Placement of the window is derived from the passed in window,
+ * except for toplevel window where OS/Window Manager placement
+ * is used.
+ *
+ * From attributes the only things used is: colormap, title,
+ * wmclass and type_hint. [1]. We are checking redundant information
+ * and complain if that changes, which would break this implementation
+ * again.
+ *
+ * [1] http://mail.gnome.org/archives/gtk-devel-list/2010-August/msg00214.html
+ */
+void
+_gdk_win32_display_create_window_impl (GdkDisplay *display,
+ GdkSurface *window,
+ GdkSurface *real_parent,
+ GdkEventMask event_mask,
+ GdkSurfaceAttr *attributes)
+{
+ HWND hwndNew;
+ HANDLE hparent;
+ ATOM klass = 0;
+ DWORD dwStyle = 0, dwExStyle;
+ RECT rect;
+ GdkSurfaceImplWin32 *impl;
+ GdkWin32Display *display_win32;
+ const gchar *title;
+ wchar_t *wtitle;
+ gint window_width, window_height;
+ gint offset_x = 0, offset_y = 0;
+ gint x, y, real_x = 0, real_y = 0;
+
+ g_return_if_fail (display == _gdk_display);
+
+ GDK_NOTE (MISC,
+ g_print ("_gdk_surface_impl_new: %s %s\n", (window->window_type == GDK_SURFACE_TOPLEVEL ? "TOPLEVEL" :
+ (window->window_type == GDK_SURFACE_TEMP ? "TEMP" : "???")),
+ (attributes->wclass == GDK_INPUT_OUTPUT ? "" : "input-only")));
+
+ hparent = (real_parent != NULL) ? GDK_SURFACE_HWND (real_parent) : NULL;
+
+ impl = g_object_new (GDK_TYPE_SURFACE_IMPL_WIN32, NULL);
+ impl->wrapper = GDK_SURFACE (window);
+ window->impl = GDK_SURFACE_IMPL (impl);
+
+ impl->layered = FALSE;
+ impl->layered_opacity = 1.0;
+
+ display_win32 = GDK_WIN32_DISPLAY (display);
+ impl->window_scale = _gdk_win32_display_get_monitor_scale_factor (display_win32, NULL, NULL, NULL);
+ impl->unscaled_width = window->width * impl->window_scale;
+ impl->unscaled_height = window->height * impl->window_scale;
+
+ if (!window->input_only)
+ {
+ dwExStyle = 0;
+ }
+ else
+ {
+ /* I very much doubt using WS_EX_TRANSPARENT actually
+ * corresponds to how X11 InputOnly windows work, but it appears
+ * to work well enough for the actual use cases in gtk.
+ */
+ dwExStyle = WS_EX_TRANSPARENT;
+ GDK_NOTE (MISC, g_print ("... GDK_INPUT_ONLY\n"));
+ }
+
+ switch (window->window_type)
+ {
+ case GDK_SURFACE_TOPLEVEL:
+ if (window->parent)
+ {
+ /* The common code warns for this case. */
+ hparent = GetDesktopWindow ();
+ }
+ /* Children of foreign windows aren't toplevel windows */
+ if (real_parent != NULL && GDK_SURFACE_TYPE (real_parent) == GDK_SURFACE_FOREIGN)
+ {
+ dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN;
+ }
+ else
+ {
+ /* MSDN: We need WS_CLIPCHILDREN and WS_CLIPSIBLINGS for GL Context Creation */
+ if (window->window_type == GDK_SURFACE_TOPLEVEL)
+ dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+ else
+ dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN;
+
+ offset_x = _gdk_offset_x;
+ offset_y = _gdk_offset_y;
+ }
+ break;
+
+ case GDK_SURFACE_TEMP:
+ /* A temp window is not necessarily a top level window */
+ dwStyle = real_parent == NULL ? WS_POPUP : WS_CHILDWINDOW;
+ dwStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
+ dwExStyle |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
+ offset_x = _gdk_offset_x;
+ offset_y = _gdk_offset_y;
+ break;
+
+
+ case GDK_SURFACE_CHILD:
+ default:
+ g_assert_not_reached ();
+ }
+
+ rect.left = window->x * impl->window_scale;
+ rect.top = window->y * impl->window_scale;
+ rect.right = rect.left + window->width * impl->window_scale;
+ rect.bottom = rect.top + window->height * impl->window_scale;
+
+ AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
+
+ real_x = (window->x - offset_x) * impl->window_scale;
+ real_y = (window->y - offset_y) * impl->window_scale;
+
+ if (window->window_type == GDK_SURFACE_TOPLEVEL)
+ {
+ /* We initially place it at default so that we can get the
+ default window positioning if we want */
+ x = y = CW_USEDEFAULT;
+ }
+ else
+ {
+ /* TEMP, FOREIGN: Put these where requested */
+ x = real_x;
+ y = real_y;
+ }
+
+ window_width = rect.right - rect.left;
+ window_height = rect.bottom - rect.top;
+
+ title = get_default_title ();
+ if (!title || !*title)
+ title = "";
+
+ impl->native_event_mask = GDK_STRUCTURE_MASK | event_mask;
+
+ if (impl->type_hint == GDK_SURFACE_TYPE_HINT_UTILITY)
+ dwExStyle |= WS_EX_TOOLWINDOW;
+
+ /* WS_EX_TRANSPARENT means "try draw this window last, and ignore input".
+ * It's the last part we're after. We don't want DND indicator to accept
+ * input, because that will make it a potential drop target, and if it's
+ * under the mouse cursor, this will kill any DND.
+ */
+ if (impl->type_hint == GDK_SURFACE_TYPE_HINT_DND)
+ dwExStyle |= WS_EX_TRANSPARENT;
+
+ klass = RegisterGdkClass (window->window_type, impl->type_hint);
+
+ wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
+
+ hwndNew = CreateWindowExW (dwExStyle,
+ MAKEINTRESOURCEW (klass),
+ wtitle,
+ dwStyle,
+ x,
+ y,
+ window_width, window_height,
+ hparent,
+ NULL,
+ _gdk_app_hmodule,
+ window);
+ if (GDK_SURFACE_HWND (window) != hwndNew)
+ {
+ g_warning ("gdk_surface_new: gdk_event_translate::WM_CREATE (%p, %p) HWND mismatch.",
+ GDK_SURFACE_HWND (window),
+ hwndNew);
+
+ /* HB: IHMO due to a race condition the handle was increased by
+ * one, which causes much trouble. Because I can't find the
+ * real bug, try to workaround it ...
+ * To reproduce: compile with MSVC 5, DEBUG=1
+ */
+# if 0
+ gdk_win32_handle_table_remove (GDK_SURFACE_HWND (window));
+ GDK_SURFACE_HWND (window) = hwndNew;
+ gdk_win32_handle_table_insert (&GDK_SURFACE_HWND (window), window);
+# else
+ /* the old behaviour, but with warning */
+ impl->handle = hwndNew;
+# endif
+
+ }
+
+ GetWindowRect (GDK_SURFACE_HWND (window), &rect);
+ impl->initial_x = rect.left;
+ impl->initial_y = rect.top;
+
+ /* Now we know the initial position, move to actually specified position */
+ if (real_x != x || real_y != y)
+ {
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ SWP_NOZORDER_SPECIFIED,
+ real_x, real_y, 0, 0,
+ SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
+ }
+
+ g_object_ref (window);
+ gdk_win32_handle_table_insert (&GDK_SURFACE_HWND (window), window);
+
+ GDK_NOTE (MISC, g_print ("... \"%s\" %dx%d@%+d%+d %p = %p\n",
+ title,
+ window_width, window_height,
+ window->x - offset_x,
+ window->y - offset_y,
+ hparent,
+ GDK_SURFACE_HWND (window)));
+
+ /* Add window handle to title */
+ GDK_NOTE (MISC_OR_EVENTS, gdk_surface_set_title (window, title));
+
+ g_free (wtitle);
+
+ if (impl->handle == NULL)
+ {
+ WIN32_API_FAILED ("CreateWindowExW");
+ g_object_unref (window);
+ return;
+ }
+
+// if (!from_set_skip_taskbar_hint && window->window_type == GDK_SURFACE_TEMP)
+// gdk_surface_set_skip_taskbar_hint (window, TRUE);
+
+ _gdk_win32_surface_enable_transparency (window);
+}
+
+GdkSurface *
+gdk_win32_surface_foreign_new_for_display (GdkDisplay *display,
+ HWND anid)
+{
+ GdkSurface *window;
+ GdkSurfaceImplWin32 *impl;
+
+ HANDLE parent;
+ RECT rect;
+ POINT point;
+
+ if ((window = gdk_win32_surface_lookup_for_display (display, anid)) != NULL)
+ return g_object_ref (window);
+
+ window = _gdk_display_create_window (display);
+ window->impl = g_object_new (GDK_TYPE_SURFACE_IMPL_WIN32, NULL);
+ window->impl_window = window;
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ impl->wrapper = window;
+ parent = GetParent (anid);
+
+ /* Always treat foreigns as toplevels */
+ window->parent = NULL;
+
+ GetClientRect ((HWND) anid, &rect);
+ point.x = rect.left;
+ point.y = rect.right;
+ ClientToScreen ((HWND) anid, &point);
+ if (parent != GetDesktopWindow ())
+ ScreenToClient (parent, &point);
+ window->x = point.x / impl->window_scale;
+ window->y = point.y / impl->window_scale;
+ impl->unscaled_width = rect.right - rect.left;
+ impl->unscaled_height = rect.bottom - rect.top;
+ window->width = (impl->unscaled_width + impl->window_scale - 1) / impl->window_scale;
+ window->height = (impl->unscaled_height + impl->window_scale - 1) / impl->window_scale;
+ window->window_type = GDK_SURFACE_FOREIGN;
+ window->destroyed = FALSE;
+ window->event_mask = GDK_ALL_EVENTS_MASK; /* XXX */
+ if (IsWindowVisible ((HWND) anid))
+ window->state &= (~GDK_SURFACE_STATE_WITHDRAWN);
+ else
+ window->state |= GDK_SURFACE_STATE_WITHDRAWN;
+ if (GetWindowLong ((HWND)anid, GWL_EXSTYLE) & WS_EX_TOPMOST)
+ window->state |= GDK_SURFACE_STATE_ABOVE;
+ else
+ window->state &= (~GDK_SURFACE_STATE_ABOVE);
+ window->state &= (~GDK_SURFACE_STATE_BELOW);
+ window->viewable = TRUE;
+
+ GDK_SURFACE_HWND (window) = anid;
+
+ g_object_ref (window);
+ gdk_win32_handle_table_insert (&GDK_SURFACE_HWND (window), window);
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_foreign_new_for_display: %p: %s@%+d%+d\n",
+ (HWND) anid,
+ _gdk_win32_surface_description (window),
+ window->x, window->y));
+
+ return window;
+}
+
+static void
+gdk_win32_surface_destroy (GdkSurface *window,
+ gboolean recursing,
+ gboolean foreign_destroy)
+{
+ GdkSurfaceImplWin32 *window_impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ GSList *tmp;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_destroy: %p\n",
+ GDK_SURFACE_HWND (window)));
+
+ /* Remove ourself from the modal stack */
+ _gdk_remove_modal_window (window);
+
+ /* Remove all our transient children */
+ tmp = window_impl->transient_children;
+ while (tmp != NULL)
+ {
+ GdkSurface *child = tmp->data;
+ GdkSurfaceImplWin32 *child_impl = GDK_SURFACE_IMPL_WIN32 (GDK_SURFACE (child)->impl);
+
+ child_impl->transient_owner = NULL;
+ tmp = tmp->next;
+ }
+ g_slist_free (window_impl->transient_children);
+ window_impl->transient_children = NULL;
+
+ /* Remove ourself from our transient owner */
+ if (window_impl->transient_owner != NULL)
+ {
+ gdk_surface_set_transient_for (window, NULL);
+ }
+
+ if (!recursing && !foreign_destroy)
+ {
+ window->destroyed = TRUE;
+ DestroyWindow (GDK_SURFACE_HWND (window));
+ }
+}
+
+/* This function is called when the window really gone.
+ */
+static void
+gdk_win32_surface_destroy_notify (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ GDK_NOTE (EVENTS,
+ g_print ("gdk_surface_destroy_notify: %p%s\n",
+ GDK_SURFACE_HWND (window),
+ (GDK_SURFACE_DESTROYED (window) ? " (destroyed)" : "")));
+
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ if (GDK_SURFACE_TYPE (window) != GDK_SURFACE_FOREIGN)
+ g_warning ("window %p unexpectedly destroyed",
+ GDK_SURFACE_HWND (window));
+
+ _gdk_surface_destroy (window, TRUE);
+ }
+
+ gdk_win32_handle_table_remove (GDK_SURFACE_HWND (window));
+ g_object_unref (window);
+}
+
+static void
+get_outer_rect (GdkSurface *window,
+ gint width,
+ gint height,
+ RECT *rect)
+{
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ rect->left = rect->top = 0;
+ rect->right = width * impl->window_scale;
+ rect->bottom = height * impl->window_scale;
+
+ _gdk_win32_adjust_client_rect (window, rect);
+}
+
+static void
+adjust_for_gravity_hints (GdkSurface *window,
+ RECT *outer_rect,
+ gint *x,
+ gint *y)
+{
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ if (impl->hint_flags & GDK_HINT_WIN_GRAVITY)
+ {
+#ifdef G_ENABLE_DEBUG
+ gint orig_x = *x, orig_y = *y;
+#endif
+
+ switch (impl->hints.win_gravity)
+ {
+ case GDK_GRAVITY_NORTH:
+ case GDK_GRAVITY_CENTER:
+ case GDK_GRAVITY_SOUTH:
+ *x -= (outer_rect->right - outer_rect->left / 2) / impl->window_scale;
+ *x += window->width / 2;
+ break;
+
+ case GDK_GRAVITY_SOUTH_EAST:
+ case GDK_GRAVITY_EAST:
+ case GDK_GRAVITY_NORTH_EAST:
+ *x -= (outer_rect->right - outer_rect->left) / impl->window_scale;
+ *x += window->width;
+ break;
+
+ case GDK_GRAVITY_STATIC:
+ *x += outer_rect->left / impl->window_scale;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (impl->hints.win_gravity)
+ {
+ case GDK_GRAVITY_WEST:
+ case GDK_GRAVITY_CENTER:
+ case GDK_GRAVITY_EAST:
+ *y -= ((outer_rect->bottom - outer_rect->top) / 2) / impl->window_scale;
+ *y += window->height / 2;
+ break;
+
+ case GDK_GRAVITY_SOUTH_WEST:
+ case GDK_GRAVITY_SOUTH:
+ case GDK_GRAVITY_SOUTH_EAST:
+ *y -= (outer_rect->bottom - outer_rect->top) / impl->window_scale;
+ *y += window->height;
+ break;
+
+ case GDK_GRAVITY_STATIC:
+ *y += outer_rect->top * impl->window_scale;
+ break;
+
+ default:
+ break;
+ }
+ GDK_NOTE (MISC,
+ (orig_x != *x || orig_y != *y) ?
+ g_print ("adjust_for_gravity_hints: x: %d->%d, y: %d->%d\n",
+ orig_x, *x, orig_y, *y)
+ : (void) 0);
+ }
+}
+
+static void
+show_window_internal (GdkSurface *window,
+ gboolean already_mapped,
+ gboolean deiconify)
+{
+ GdkSurfaceImplWin32 *window_impl;
+ gboolean focus_on_map = FALSE;
+ DWORD exstyle;
+
+ if (window->destroyed)
+ return;
+
+ GDK_NOTE (MISC, g_print ("show_window_internal: %p: %s%s\n",
+ GDK_SURFACE_HWND (window),
+ _gdk_win32_surface_state_to_string (window->state),
+ (deiconify ? " deiconify" : "")));
+
+ /* If asked to show (not deiconify) an withdrawn and iconified
+ * window, do that.
+ */
+ if (!deiconify &&
+ !already_mapped &&
+ (window->state & GDK_SURFACE_STATE_ICONIFIED))
+ {
+ GtkShowWindow (window, SW_SHOWMINNOACTIVE);
+ return;
+ }
+
+ /* If asked to just show an iconified window, do nothing. */
+ if (!deiconify && (window->state & GDK_SURFACE_STATE_ICONIFIED))
+ return;
+
+ /* If asked to deiconify an already noniconified window, do
+ * nothing. (Especially, don't cause the window to rise and
+ * activate. There are different calls for that.)
+ */
+ if (deiconify && !(window->state & GDK_SURFACE_STATE_ICONIFIED))
+ return;
+
+ /* If asked to show (but not raise) a window that is already
+ * visible, do nothing.
+ */
+ if (!deiconify && !already_mapped && IsWindowVisible (GDK_SURFACE_HWND (window)))
+ return;
+
+ /* Other cases */
+
+ if (!already_mapped)
+ focus_on_map = window->focus_on_map;
+
+ exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
+
+ /* Use SetWindowPos to show transparent windows so automatic redraws
+ * in other windows can be suppressed.
+ */
+ if (exstyle & WS_EX_TRANSPARENT)
+ {
+ UINT flags = SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
+
+ if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP || !focus_on_map)
+ flags |= SWP_NOACTIVATE;
+
+ SetWindowPos (GDK_SURFACE_HWND (window),
+ SWP_NOZORDER_SPECIFIED, 0, 0, 0, 0, flags);
+
+ return;
+ }
+
+ /* For initial map of "normal" windows we want to emulate WM window
+ * positioning behaviour, which means:
+ * + Use user specified position if GDK_HINT_POS or GDK_HINT_USER_POS
+ * otherwise:
+ * + default to the initial CW_USEDEFAULT placement,
+ * no matter if the user moved the window before showing it.
+ * + Certain window types and hints have more elaborate positioning
+ * schemes.
+ */
+ window_impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ if (!already_mapped &&
+ GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL &&
+ (window_impl->hint_flags & (GDK_HINT_POS | GDK_HINT_USER_POS)) == 0)
+ {
+ gboolean center = FALSE;
+ RECT window_rect, center_on_rect;
+ int x, y;
+
+ x = window_impl->initial_x;
+ y = window_impl->initial_y;
+
+ if (window_impl->type_hint == GDK_SURFACE_TYPE_HINT_SPLASHSCREEN)
+ {
+ HMONITOR monitor;
+ MONITORINFO mi;
+
+ monitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
+ mi.cbSize = sizeof (mi);
+ if (monitor && GetMonitorInfo (monitor, &mi))
+ center_on_rect = mi.rcMonitor;
+ else
+ {
+ center_on_rect.left = 0;
+ center_on_rect.top = 0;
+ center_on_rect.right = GetSystemMetrics (SM_CXSCREEN);
+ center_on_rect.bottom = GetSystemMetrics (SM_CYSCREEN);
+ }
+ center = TRUE;
+ }
+ else if (window_impl->transient_owner != NULL &&
+ GDK_SURFACE_IS_MAPPED (window_impl->transient_owner))
+ {
+ GdkSurface *owner = window_impl->transient_owner;
+ /* Center on transient parent */
+ center_on_rect.left = (owner->x - _gdk_offset_x) * window_impl->window_scale;
+ center_on_rect.top = (owner->y - _gdk_offset_y) * window_impl->window_scale;
+ center_on_rect.right = center_on_rect.left + owner->width * window_impl->window_scale;
+ center_on_rect.bottom = center_on_rect.top + owner->height * window_impl->window_scale;
+
+ _gdk_win32_adjust_client_rect (GDK_SURFACE (owner), ¢er_on_rect);
+ center = TRUE;
+ }
+
+ if (center)
+ {
+ window_rect.left = 0;
+ window_rect.top = 0;
+ window_rect.right = window->width * window_impl->window_scale;
+ window_rect.bottom = window->height * window_impl->window_scale;
+ _gdk_win32_adjust_client_rect (window, &window_rect);
+
+ x = center_on_rect.left + ((center_on_rect.right - center_on_rect.left) - (window_rect.right - window_rect.left)) / 2;
+ y = center_on_rect.top + ((center_on_rect.bottom - center_on_rect.top) - (window_rect.bottom - window_rect.top)) / 2;
+ }
+
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ SWP_NOZORDER_SPECIFIED,
+ x, y, 0, 0,
+ SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
+ }
+
+ if (!already_mapped &&
+ GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL)
+ {
+ /* Ensure new windows are fully onscreen */
+ RECT window_rect;
+ HMONITOR monitor;
+ MONITORINFO mi;
+ int x, y;
+
+ GetWindowRect (GDK_SURFACE_HWND (window), &window_rect);
+
+ monitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
+ mi.cbSize = sizeof (mi);
+ if (monitor && GetMonitorInfo (monitor, &mi))
+ {
+ x = window_rect.left;
+ y = window_rect.top;
+
+ if (window_rect.right > mi.rcWork.right)
+ {
+ window_rect.left -= (window_rect.right - mi.rcWork.right);
+ window_rect.right -= (window_rect.right - mi.rcWork.right);
+ }
+
+ if (window_rect.bottom > mi.rcWork.bottom)
+ {
+ window_rect.top -= (window_rect.bottom - mi.rcWork.bottom);
+ window_rect.bottom -= (window_rect.bottom - mi.rcWork.bottom);
+ }
+
+ if (window_rect.left < mi.rcWork.left)
+ {
+ window_rect.right += (mi.rcWork.left - window_rect.left);
+ window_rect.left += (mi.rcWork.left - window_rect.left);
+ }
+
+ if (window_rect.top < mi.rcWork.top)
+ {
+ window_rect.bottom += (mi.rcWork.top - window_rect.top);
+ window_rect.top += (mi.rcWork.top - window_rect.top);
+ }
+
+ if (x != window_rect.left || y != window_rect.top)
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ SWP_NOZORDER_SPECIFIED,
+ window_rect.left, window_rect.top, 0, 0,
+ SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
+ }
+ }
+
+
+ if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
+ {
+ gdk_surface_fullscreen (window);
+ }
+ else if (window->state & GDK_SURFACE_STATE_MAXIMIZED)
+ {
+ GtkShowWindow (window, SW_MAXIMIZE);
+ }
+ else if (window->state & GDK_SURFACE_STATE_ICONIFIED)
+ {
+ if (focus_on_map)
+ GtkShowWindow (window, SW_RESTORE);
+ else
+ GtkShowWindow (window, SW_SHOWNOACTIVATE);
+ }
+ else if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP || !focus_on_map)
+ {
+ if (!IsWindowVisible (GDK_SURFACE_HWND (window)))
+ GtkShowWindow (window, SW_SHOWNOACTIVATE);
+ else
+ GtkShowWindow (window, SW_SHOWNA);
+ }
+ else if (!IsWindowVisible (GDK_SURFACE_HWND (window)))
+ {
+ GtkShowWindow (window, SW_SHOWNORMAL);
+ }
+ else
+ {
+ GtkShowWindow (window, SW_SHOW);
+ }
+
+ /* Sync STATE_ABOVE to TOPMOST */
+ if (GDK_SURFACE_TYPE (window) != GDK_SURFACE_TEMP &&
+ (((window->state & GDK_SURFACE_STATE_ABOVE) &&
+ !(exstyle & WS_EX_TOPMOST)) ||
+ (!(window->state & GDK_SURFACE_STATE_ABOVE) &&
+ (exstyle & WS_EX_TOPMOST))))
+ {
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ (window->state & GDK_SURFACE_STATE_ABOVE)?HWND_TOPMOST:HWND_NOTOPMOST,
+ 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
+ }
+}
+
+static void
+gdk_win32_surface_show (GdkSurface *window,
+ gboolean already_mapped)
+{
+ show_window_internal (window, FALSE, FALSE);
+}
+
+static void
+gdk_win32_surface_hide (GdkSurface *window)
+{
+ if (window->destroyed)
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_hide: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ _gdk_win32_surface_state_to_string (window->state)));
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_SURFACE_STATE_WITHDRAWN);
+
+ _gdk_surface_clear_update_area (window);
+
+ if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL)
+ ShowOwnedPopups (GDK_SURFACE_HWND (window), FALSE);
+
+ /* Use SetWindowPos to hide transparent windows so automatic redraws
+ * in other windows can be suppressed.
+ */
+ if (GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE) & WS_EX_TRANSPARENT)
+ {
+ SetWindowPos (GDK_SURFACE_HWND (window), SWP_NOZORDER_SPECIFIED,
+ 0, 0, 0, 0,
+ SWP_HIDEWINDOW | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
+ }
+ else
+ {
+ GtkShowWindow (window, SW_HIDE);
+ }
+}
+
+static void
+gdk_win32_surface_withdraw (GdkSurface *window)
+{
+ if (window->destroyed)
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_withdraw: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ _gdk_win32_surface_state_to_string (window->state)));
+
+ gdk_surface_hide (window); /* ??? */
+}
+
+static void
+gdk_win32_surface_move (GdkSurface *window,
+ gint x, gint y)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_move: %p: %+d%+d\n",
+ GDK_SURFACE_HWND (window), x, y));
+
+ if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
+ return;
+
+ /* Don't check GDK_SURFACE_TYPE (window) == GDK_SURFACE_CHILD.
+ * Foreign windows (another app's windows) might be children of our
+ * windows! Especially in the case of gtkplug/socket.
+ */
+ if (GetAncestor (GDK_SURFACE_HWND (window), GA_PARENT) != GetDesktopWindow ())
+ {
+ _gdk_surface_move_resize_child (window, x, y, window->width, window->height);
+ }
+ else
+ {
+ RECT outer_rect;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ get_outer_rect (window, window->width, window->height, &outer_rect);
+
+ adjust_for_gravity_hints (window, &outer_rect, &x, &y);
+
+ GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,0,0,"
+ "NOACTIVATE|NOSIZE|NOZORDER)\n",
+ GDK_SURFACE_HWND (window),
+ (x - _gdk_offset_x) * impl->window_scale,
+ (y - _gdk_offset_y) * impl->window_scale));
+
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ SWP_NOZORDER_SPECIFIED,
+ (x - _gdk_offset_x) * impl->window_scale,
+ (y - _gdk_offset_y) * impl->window_scale,
+ 0, 0,
+ SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
+ }
+}
+
+static void
+gdk_win32_surface_resize (GdkSurface *window,
+ gint width, gint height)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (width < 1)
+ width = 1;
+ if (height < 1)
+ height = 1;
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_resize: %p: %dx%d\n",
+ GDK_SURFACE_HWND (window), width, height));
+
+ if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
+ return;
+
+ if (GetAncestor (GDK_SURFACE_HWND (window), GA_PARENT) != GetDesktopWindow ())
+ {
+ _gdk_surface_move_resize_child (window, window->x, window->y, width, height);
+ }
+ else
+ {
+ RECT outer_rect;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ get_outer_rect (window, width, height, &outer_rect);
+
+ GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,0,0,%ld,%ld,"
+ "NOACTIVATE|NOMOVE|NOZORDER)\n",
+ GDK_SURFACE_HWND (window),
+ outer_rect.right - outer_rect.left,
+ outer_rect.bottom - outer_rect.top));
+
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ SWP_NOZORDER_SPECIFIED,
+ 0, 0,
+ outer_rect.right - outer_rect.left,
+ outer_rect.bottom - outer_rect.top,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER));
+ window->resize_count += 1;
+ }
+}
+
+static void
+gdk_win32_surface_move_resize_internal (GdkSurface *window,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (width < 1)
+ width = 1;
+ if (height < 1)
+ height = 1;
+
+ if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_move_resize: %p: %dx%d@%+d%+d\n",
+ GDK_SURFACE_HWND (window),
+ width, height, x, y));
+
+ if (GetAncestor (GDK_SURFACE_HWND (window), GA_PARENT) != GetDesktopWindow ())
+ {
+ _gdk_surface_move_resize_child (window, x, y, width, height);
+ }
+ else
+ {
+ RECT outer_rect;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ get_outer_rect (window, width, height, &outer_rect);
+
+ adjust_for_gravity_hints (window, &outer_rect, &x, &y);
+
+ GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%ld,%ld,"
+ "NOACTIVATE|NOZORDER)\n",
+ GDK_SURFACE_HWND (window),
+ (x - _gdk_offset_x) * impl->window_scale,
+ (y - _gdk_offset_y) * impl->window_scale,
+ outer_rect.right - outer_rect.left,
+ outer_rect.bottom - outer_rect.top));
+
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ SWP_NOZORDER_SPECIFIED,
+ (x - _gdk_offset_x) * impl->window_scale,
+ (y - _gdk_offset_y) * impl->window_scale,
+ outer_rect.right - outer_rect.left,
+ outer_rect.bottom - outer_rect.top,
+ SWP_NOACTIVATE | SWP_NOZORDER));
+ }
+}
+
+static void
+gdk_win32_surface_move_resize (GdkSurface *window,
+ gboolean with_move,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GdkSurfaceImplWin32 *window_impl;
+
+ window_impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ window_impl->inhibit_configure = TRUE;
+
+ /* We ignore changes to the window being moved or resized by the
+ user, as we don't want to fight the user */
+ if (GDK_SURFACE_HWND (window) == _modal_move_resize_window)
+ goto out;
+
+ if (with_move && (width < 0 && height < 0))
+ {
+ gdk_win32_surface_move (window, x, y);
+ }
+ else
+ {
+ if (with_move)
+ {
+ gdk_win32_surface_move_resize_internal (window, x, y, width, height);
+ }
+ else
+ {
+ gdk_win32_surface_resize (window, width, height);
+ }
+ }
+
+ out:
+ window_impl->inhibit_configure = FALSE;
+
+ if (WINDOW_IS_TOPLEVEL (window))
+ _gdk_win32_emit_configure_event (window);
+}
+
+static void
+gdk_win32_surface_raise (GdkSurface *window)
+{
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_raise: %p\n",
+ GDK_SURFACE_HWND (window)));
+
+ if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP)
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOPMOST,
+ 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
+ else if (window->accept_focus)
+ /* Do not wrap this in an API_CALL macro as SetForegroundWindow might
+ * fail when for example dragging a window belonging to a different
+ * application at the time of a gtk_window_present() call due to focus
+ * stealing prevention. */
+ SetForegroundWindow (GDK_SURFACE_HWND (window));
+ else
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOP,
+ 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
+ }
+}
+
+static void
+gdk_win32_surface_lower (GdkSurface *window)
+{
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_lower: %p\n"
+ "... SetWindowPos(%p,HWND_BOTTOM,0,0,0,0,"
+ "NOACTIVATE|NOMOVE|NOSIZE)\n",
+ GDK_SURFACE_HWND (window),
+ GDK_SURFACE_HWND (window)));
+
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_BOTTOM,
+ 0, 0, 0, 0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
+ }
+}
+
+static void
+gdk_win32_surface_set_urgency_hint (GdkSurface *window,
+ gboolean urgent)
+{
+ FLASHWINFO flashwinfo;
+ typedef BOOL (WINAPI *PFN_FlashWindowEx) (FLASHWINFO*);
+ PFN_FlashWindowEx flashWindowEx = NULL;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ flashWindowEx = (PFN_FlashWindowEx) GetProcAddress (GetModuleHandle ("user32.dll"), "FlashWindowEx");
+
+ if (flashWindowEx)
+ {
+ flashwinfo.cbSize = sizeof (flashwinfo);
+ flashwinfo.hwnd = GDK_SURFACE_HWND (window);
+ if (urgent)
+ flashwinfo.dwFlags = FLASHW_ALL | FLASHW_TIMER;
+ else
+ flashwinfo.dwFlags = FLASHW_STOP;
+ flashwinfo.uCount = 0;
+ flashwinfo.dwTimeout = 0;
+
+ flashWindowEx (&flashwinfo);
+ }
+ else
+ {
+ FlashWindow (GDK_SURFACE_HWND (window), urgent);
+ }
+}
+
+static gboolean
+get_effective_window_decorations (GdkSurface *window,
+ GdkWMDecoration *decoration)
+{
+ GdkSurfaceImplWin32 *impl;
+
+ impl = (GdkSurfaceImplWin32 *)window->impl;
+
+ if (gdk_surface_get_decorations (window, decoration))
+ return TRUE;
+
+ if (window->window_type != GDK_SURFACE_TOPLEVEL)
+ {
+ return FALSE;
+ }
+
+ if ((impl->hint_flags & GDK_HINT_MIN_SIZE) &&
+ (impl->hint_flags & GDK_HINT_MAX_SIZE) &&
+ impl->hints.min_width == impl->hints.max_width &&
+ impl->hints.min_height == impl->hints.max_height)
+ {
+ *decoration = GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MAXIMIZE;
+
+ if (impl->type_hint == GDK_SURFACE_TYPE_HINT_DIALOG ||
+ impl->type_hint == GDK_SURFACE_TYPE_HINT_MENU ||
+ impl->type_hint == GDK_SURFACE_TYPE_HINT_TOOLBAR)
+ {
+ *decoration |= GDK_DECOR_MINIMIZE;
+ }
+ else if (impl->type_hint == GDK_SURFACE_TYPE_HINT_SPLASHSCREEN)
+ {
+ *decoration |= GDK_DECOR_MENU | GDK_DECOR_MINIMIZE;
+ }
+
+ return TRUE;
+ }
+ else if (impl->hint_flags & GDK_HINT_MAX_SIZE)
+ {
+ *decoration = GDK_DECOR_ALL | GDK_DECOR_MAXIMIZE;
+ if (impl->type_hint == GDK_SURFACE_TYPE_HINT_DIALOG ||
+ impl->type_hint == GDK_SURFACE_TYPE_HINT_MENU ||
+ impl->type_hint == GDK_SURFACE_TYPE_HINT_TOOLBAR)
+ {
+ *decoration |= GDK_DECOR_MINIMIZE;
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ switch (impl->type_hint)
+ {
+ case GDK_SURFACE_TYPE_HINT_DIALOG:
+ *decoration = (GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
+ return TRUE;
+
+ case GDK_SURFACE_TYPE_HINT_MENU:
+ *decoration = (GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
+ return TRUE;
+
+ case GDK_SURFACE_TYPE_HINT_TOOLBAR:
+ case GDK_SURFACE_TYPE_HINT_UTILITY:
+ gdk_surface_set_skip_taskbar_hint (window, TRUE);
+ gdk_surface_set_skip_pager_hint (window, TRUE);
+ *decoration = (GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
+ return TRUE;
+
+ case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
+ *decoration = (GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MENU |
+ GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
+ return TRUE;
+
+ case GDK_SURFACE_TYPE_HINT_DOCK:
+ return FALSE;
+
+ case GDK_SURFACE_TYPE_HINT_DESKTOP:
+ return FALSE;
+
+ default:
+ /* Fall thru */
+ case GDK_SURFACE_TYPE_HINT_NORMAL:
+ *decoration = GDK_DECOR_ALL;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+gdk_win32_surface_set_geometry_hints (GdkSurface *window,
+ const GdkGeometry *geometry,
+ GdkSurfaceHints geom_mask)
+{
+ GdkSurfaceImplWin32 *impl;
+ FullscreenInfo *fi;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_set_geometry_hints: %p\n",
+ GDK_SURFACE_HWND (window)));
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ fi = g_object_get_data (G_OBJECT (window), "fullscreen-info");
+ if (fi)
+ fi->hint_flags = geom_mask;
+ else
+ impl->hint_flags = geom_mask;
+ impl->hints = *geometry;
+
+ if (geom_mask & GDK_HINT_POS)
+ {
+ /* even the X11 mplementation doesn't care */
+ }
+
+ if (geom_mask & GDK_HINT_MIN_SIZE)
+ {
+ GDK_NOTE (MISC, g_print ("... MIN_SIZE: %dx%d\n",
+ geometry->min_width, geometry->min_height));
+ }
+
+ if (geom_mask & GDK_HINT_MAX_SIZE)
+ {
+ GDK_NOTE (MISC, g_print ("... MAX_SIZE: %dx%d\n",
+ geometry->max_width, geometry->max_height));
+ }
+
+ if (geom_mask & GDK_HINT_BASE_SIZE)
+ {
+ GDK_NOTE (MISC, g_print ("... BASE_SIZE: %dx%d\n",
+ geometry->base_width, geometry->base_height));
+ }
+
+ if (geom_mask & GDK_HINT_RESIZE_INC)
+ {
+ GDK_NOTE (MISC, g_print ("... RESIZE_INC: (%d,%d)\n",
+ geometry->width_inc, geometry->height_inc));
+ }
+
+ if (geom_mask & GDK_HINT_ASPECT)
+ {
+ GDK_NOTE (MISC, g_print ("... ASPECT: %g--%g\n",
+ geometry->min_aspect, geometry->max_aspect));
+ }
+
+ if (geom_mask & GDK_HINT_WIN_GRAVITY)
+ {
+ GDK_NOTE (MISC, g_print ("... GRAVITY: %d\n", geometry->win_gravity));
+ }
+
+ _gdk_win32_surface_update_style_bits (window);
+}
+
+static void
+gdk_win32_surface_set_title (GdkSurface *window,
+ const gchar *title)
+{
+ wchar_t *wtitle;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (title != NULL);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ /* Empty window titles not allowed, so set it to just a period. */
+ if (!title[0])
+ title = ".";
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_set_title: %p: %s\n",
+ GDK_SURFACE_HWND (window), title));
+
+ GDK_NOTE (MISC_OR_EVENTS, title = g_strdup_printf ("%p %s", GDK_SURFACE_HWND (window), title));
+
+ wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
+ API_CALL (SetWindowTextW, (GDK_SURFACE_HWND (window), wtitle));
+ g_free (wtitle);
+
+ GDK_NOTE (MISC_OR_EVENTS, g_free ((char *) title));
+}
+
+static void
+gdk_win32_surface_set_role (GdkSurface *window,
+ const gchar *role)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_set_role: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ (role ? role : "NULL")));
+ /* XXX */
+}
+
+static void
+gdk_win32_surface_set_transient_for (GdkSurface *window,
+ GdkSurface *parent)
+{
+ HWND window_id, parent_id;
+ LONG_PTR old_ptr;
+ DWORD w32_error;
+ GdkSurfaceImplWin32 *window_impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ GdkSurfaceImplWin32 *parent_impl = NULL;
+ GSList *item;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ window_id = GDK_SURFACE_HWND (window);
+ parent_id = parent != NULL ? GDK_SURFACE_HWND (parent) : NULL;
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_set_transient_for: %p: %p\n", window_id, parent_id));
+
+ if (GDK_SURFACE_DESTROYED (window) || (parent && GDK_SURFACE_DESTROYED (parent)))
+ {
+ if (GDK_SURFACE_DESTROYED (window))
+ GDK_NOTE (MISC, g_print ("... destroyed!\n"));
+ else
+ GDK_NOTE (MISC, g_print ("... owner destroyed!\n"));
+
+ return;
+ }
+
+ if (parent == NULL)
+ {
+ GdkSurfaceImplWin32 *trans_impl = GDK_SURFACE_IMPL_WIN32 (window_impl->transient_owner->impl);
+ if (trans_impl->transient_children != NULL)
+ {
+ item = g_slist_find (trans_impl->transient_children, window);
+ item->data = NULL;
+ trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item);
+ trans_impl->num_transients--;
+
+ if (!trans_impl->num_transients)
+ {
+ trans_impl->transient_children = NULL;
+ }
+ }
+ g_object_unref (G_OBJECT (window_impl->transient_owner));
+ g_object_unref (G_OBJECT (window));
+
+ window_impl->transient_owner = NULL;
+ }
+ else
+ {
+ parent_impl = GDK_SURFACE_IMPL_WIN32 (parent->impl);
+
+ parent_impl->transient_children = g_slist_append (parent_impl->transient_children, window);
+ g_object_ref (G_OBJECT (window));
+ parent_impl->num_transients++;
+ window_impl->transient_owner = parent;
+ g_object_ref (G_OBJECT (parent));
+ }
+
+ SetLastError (0);
+ old_ptr = GetWindowLongPtr (window_id, GWLP_HWNDPARENT);
+ w32_error = GetLastError ();
+
+ /* Don't re-set GWLP_HWNDPARENT to the same value */
+ if ((HWND) old_ptr == parent_id && w32_error == NO_ERROR)
+ return;
+
+ /* Don't return if it failed, try SetWindowLongPtr() anyway */
+ if (old_ptr == 0 && w32_error != NO_ERROR)
+ WIN32_API_FAILED ("GetWindowLongPtr");
+
+ /* This changes the *owner* of the window, despite the misleading
+ * name. (Owner and parent are unrelated concepts.) At least that's
+ * what people who seem to know what they talk about say on
+ * USENET. Search on Google.
+ */
+ SetLastError (0);
+ old_ptr = SetWindowLongPtr (window_id, GWLP_HWNDPARENT, (LONG_PTR) parent_id);
+ w32_error = GetLastError ();
+
+ if (old_ptr == 0 && w32_error != NO_ERROR)
+ WIN32_API_FAILED ("SetWindowLongPtr");
+}
+
+void
+_gdk_push_modal_window (GdkSurface *window)
+{
+ modal_window_stack = g_slist_prepend (modal_window_stack,
+ window);
+}
+
+void
+_gdk_remove_modal_window (GdkSurface *window)
+{
+ GSList *tmp;
+
+ g_return_if_fail (window != NULL);
+
+ /* It's possible to be NULL here if someone sets the modal hint of the window
+ * to FALSE before a modal window stack has ever been created. */
+ if (modal_window_stack == NULL)
+ return;
+
+ /* Find the requested window in the stack and remove it. Yeah, I realize this
+ * means we're not a 'real stack', strictly speaking. Sue me. :) */
+ tmp = g_slist_find (modal_window_stack, window);
+ if (tmp != NULL)
+ {
+ modal_window_stack = g_slist_delete_link (modal_window_stack, tmp);
+ }
+}
+
+gboolean
+_gdk_modal_blocked (GdkSurface *window)
+{
+ GSList *l;
+ gboolean found_any = FALSE;
+
+ for (l = modal_window_stack; l != NULL; l = l->next)
+ {
+ GdkSurface *modal = l->data;
+
+ if (modal == window)
+ return FALSE;
+
+ if (GDK_SURFACE_IS_MAPPED (modal))
+ found_any = TRUE;
+ }
+
+ return found_any;
+}
+
+GdkSurface *
+_gdk_modal_current (void)
+{
+ GSList *l;
+
+ for (l = modal_window_stack; l != NULL; l = l->next)
+ {
+ GdkSurface *modal = l->data;
+
+ if (GDK_SURFACE_IS_MAPPED (modal))
+ return modal;
+ }
+
+ return NULL;
+}
+
+static void
+gdk_win32_surface_get_geometry (GdkSurface *window,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height)
+{
+ GdkDisplay *display;
+ gboolean window_is_root;
+
+ display = gdk_surface_get_display (window);
+
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ RECT rect;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ API_CALL (GetClientRect, (GDK_SURFACE_HWND (window), &rect));
+
+ POINT pt;
+ GdkSurface *parent = gdk_surface_get_parent (window);
+
+ pt.x = rect.left;
+ pt.y = rect.top;
+ ClientToScreen (GDK_SURFACE_HWND (window), &pt);
+ if (parent)
+ ScreenToClient (GDK_SURFACE_HWND (parent), &pt);
+ rect.left = pt.x;
+ rect.top = pt.y;
+
+ pt.x = rect.right;
+ pt.y = rect.bottom;
+ ClientToScreen (GDK_SURFACE_HWND (window), &pt);
+ if (parent)
+ ScreenToClient (GDK_SURFACE_HWND (parent), &pt);
+ rect.right = pt.x;
+ rect.bottom = pt.y;
+
+ if (parent == NULL)
+ {
+ rect.left += _gdk_offset_x * impl->window_scale;
+ rect.top += _gdk_offset_y * impl->window_scale;
+ rect.right += _gdk_offset_x * impl->window_scale;
+ rect.bottom += _gdk_offset_y * impl->window_scale;
+ }
+
+ if (x)
+ *x = rect.left / impl->window_scale;
+ if (y)
+ *y = rect.top / impl->window_scale;
+ if (width)
+ *width = (rect.right - rect.left) / impl->window_scale;
+ if (height)
+ *height = (rect.bottom - rect.top) / impl->window_scale;
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_get_geometry: %p: %ldx%ld@%+ld%\n",
+ GDK_SURFACE_HWND (window),
+ (rect.right - rect.left) / impl->window_scale,
+ (rect.bottom - rect.top) / impl->window_scale,
+ rect.left, rect.top));
+ }
+}
+
+static void
+gdk_win32_surface_get_root_coords (GdkSurface *window,
+ gint x,
+ gint y,
+ gint *root_x,
+ gint *root_y)
+{
+ gint tx;
+ gint ty;
+ POINT pt;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ pt.x = x * impl->window_scale;
+ pt.y = y * impl->window_scale;
+ ClientToScreen (GDK_SURFACE_HWND (window), &pt);
+ tx = pt.x;
+ ty = pt.y;
+
+ if (root_x)
+ *root_x = (tx + _gdk_offset_x) / impl->window_scale;
+ if (root_y)
+ *root_y = (ty + _gdk_offset_y) / impl->window_scale;
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_get_root_coords: %p: %+d%+d %+d%+d\n",
+ GDK_SURFACE_HWND (window),
+ x * impl->window_scale,
+ y * impl->window_scale,
+ (tx + _gdk_offset_x) / impl->window_scale,
+ (ty + _gdk_offset_y) / impl->window_scale));
+}
+
+static void
+gdk_win32_surface_restack_toplevel (GdkSurface *window,
+ GdkSurface *sibling,
+ gboolean above)
+{
+ // ### TODO
+}
+
+static void
+gdk_win32_surface_get_frame_extents (GdkSurface *window,
+ GdkRectangle *rect)
+{
+ HWND hwnd;
+ RECT r;
+ GdkSurfaceImplWin32 *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (rect != NULL);
+
+ rect->x = 0;
+ rect->y = 0;
+ rect->width = 1;
+ rect->height = 1;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ /* FIXME: window is documented to be a toplevel GdkSurface, so is it really
+ * necessary to walk its parent chain?
+ */
+ while (window->parent && window->parent->parent)
+ window = window->parent;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ hwnd = GDK_SURFACE_HWND (window);
+ API_CALL (GetWindowRect, (hwnd, &r));
+
+ /* Initialize to real, unscaled size */
+ rect->x = r.left + _gdk_offset_x * impl->window_scale;
+ rect->y = r.top + _gdk_offset_y * impl->window_scale;
+ rect->width = (r.right - r.left);
+ rect->height = (r.bottom - r.top);
+
+ /* Extend width and height to ensure that they cover the real size when de-scaled,
+ * and replace everyting with scaled values
+ */
+ rect->width = (rect->width + rect->x % impl->window_scale + impl->window_scale - 1) / impl->window_scale;
+ rect->height = (rect->height + rect->y % impl->window_scale + impl->window_scale - 1) / impl->window_scale;
+ rect->x = r.left / impl->window_scale + _gdk_offset_x;
+ rect->y = r.top / impl->window_scale + _gdk_offset_y;
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_get_frame_extents: %p: %ldx%ld@%+ld%+ld\n",
+ GDK_SURFACE_HWND (window),
+ rect->width,
+ rect->height,
+ rect->x, rect->y));
+}
+
+static gboolean
+gdk_surface_win32_get_device_state (GdkSurface *window,
+ GdkDevice *device,
+ gdouble *x,
+ gdouble *y,
+ GdkModifierType *mask)
+{
+ GdkSurface *child;
+
+ g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), FALSE);
+
+ GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
+ &child,
+ NULL, NULL,
+ x, y, mask);
+ return (child != NULL);
+}
+
+void
+gdk_display_warp_device (GdkDisplay *display,
+ GdkDevice *device,
+ gint x,
+ gint y)
+{
+ g_return_if_fail (display == gdk_display_get_default ());
+ g_return_if_fail (GDK_IS_DEVICE (device));
+ g_return_if_fail (display == gdk_device_get_display (device));
+
+ GDK_DEVICE_GET_CLASS (device)->warp (device, x, y);
+}
+
+static GdkEventMask
+gdk_win32_surface_get_events (GdkSurface *window)
+{
+ GdkSurfaceImplWin32 *impl;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return 0;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ return impl->native_event_mask;
+}
+
+static void
+gdk_win32_surface_set_events (GdkSurface *window,
+ GdkEventMask event_mask)
+{
+ GdkSurfaceImplWin32 *impl;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ /* gdk_surface_new() always sets the GDK_STRUCTURE_MASK, so better
+ * set it here, too. Not that I know or remember why it is
+ * necessary, will have to test some day.
+ */
+ impl->native_event_mask = GDK_STRUCTURE_MASK | event_mask;
+}
+
+static void
+do_shape_combine_region (GdkSurface *window,
+ HRGN hrgn,
+ gint x, gint y)
+{
+ RECT rect;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ GetClientRect (GDK_SURFACE_HWND (window), &rect);
+
+ _gdk_win32_adjust_client_rect (window, &rect);
+
+ OffsetRgn (hrgn, -rect.left, -rect.top);
+ OffsetRgn (hrgn, x, y);
+
+ /* If this is a top-level window, add the title bar to the region */
+ if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL)
+ {
+ HRGN tmp = CreateRectRgn (0, 0, rect.right - rect.left, -rect.top);
+ CombineRgn (hrgn, hrgn, tmp, RGN_OR);
+ DeleteObject (tmp);
+ }
+
+ SetWindowRgn (GDK_SURFACE_HWND (window), hrgn, TRUE);
+}
+
+static void
+gdk_win32_surface_set_accept_focus (GdkSurface *window,
+ gboolean accept_focus)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ accept_focus = accept_focus != FALSE;
+
+ if (window->accept_focus != accept_focus)
+ window->accept_focus = accept_focus;
+}
+
+static void
+gdk_win32_surface_set_focus_on_map (GdkSurface *window,
+ gboolean focus_on_map)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ focus_on_map = focus_on_map != FALSE;
+
+ if (window->focus_on_map != focus_on_map)
+ window->focus_on_map = focus_on_map;
+}
+
+static void
+gdk_win32_surface_set_icon_list (GdkSurface *window,
+ GList *textures)
+{
+ GdkTexture *big_texture, *small_texture;
+ gint big_diff, small_diff;
+ gint big_w, big_h, small_w, small_h;
+ gint w, h;
+ gint dw, dh, diff;
+ HICON small_hicon, big_hicon;
+ GdkSurfaceImplWin32 *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) || textures == NULL)
+ return;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ /* ideal sizes for small and large icons */
+ big_w = GetSystemMetrics (SM_CXICON);
+ big_h = GetSystemMetrics (SM_CYICON);
+ small_w = GetSystemMetrics (SM_CXSMICON);
+ small_h = GetSystemMetrics (SM_CYSMICON);
+
+ /* find closest sized icons in the list */
+ big_texture = NULL;
+ small_texture = NULL;
+ big_diff = 0;
+ small_diff = 0;
+
+ for (GList *l = textures; l; l = l->next)
+ {
+ GdkTexture *texture = l->data;
+ w = gdk_texture_get_width (texture);
+ h = gdk_texture_get_height (texture);
+
+ dw = ABS (w - big_w);
+ dh = ABS (h - big_h);
+ diff = dw*dw + dh*dh;
+ if (big_texture == NULL || diff < big_diff)
+ {
+ big_texture = texture;
+ big_diff = diff;
+ }
+
+ dw = ABS (w - small_w);
+ dh = ABS (h - small_h);
+ diff = dw*dw + dh*dh;
+ if (small_texture == NULL || diff < small_diff)
+ {
+ small_texture = texture;
+ small_diff = diff;
+ }
+
+ textures = textures->next;
+ }
+
+ /* Create the icons */
+ big_hicon = _gdk_win32_texture_to_hicon (big_texture);
+ g_object_unref (big_texture);
+ small_hicon = _gdk_win32_texture_to_hicon (small_texture);
+ g_object_unref (small_texture);
+
+ /* Set the icons */
+ SendMessageW (GDK_SURFACE_HWND (window), WM_SETICON, ICON_BIG,
+ (LPARAM)big_hicon);
+ SendMessageW (GDK_SURFACE_HWND (window), WM_SETICON, ICON_SMALL,
+ (LPARAM)small_hicon);
+
+ /* Store the icons, destroying any previous icons */
+ if (impl->hicon_big)
+ GDI_CALL (DestroyIcon, (impl->hicon_big));
+ impl->hicon_big = big_hicon;
+ if (impl->hicon_small)
+ GDI_CALL (DestroyIcon, (impl->hicon_small));
+ impl->hicon_small = small_hicon;
+}
+
+static void
+gdk_win32_surface_set_icon_name (GdkSurface *window,
+ const gchar *name)
+{
+ /* In case I manage to confuse this again (or somebody else does):
+ * Please note that "icon name" here really *does* mean the name or
+ * title of an window minimized as an icon on the desktop, or in the
+ * taskbar. It has nothing to do with the freedesktop.org icon
+ * naming stuff.
+ */
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+#if 0
+ /* This is not the correct thing to do. We should keep both the
+ * "normal" window title, and the icon name. When the window is
+ * minimized, call SetWindowText() with the icon name, and when the
+ * window is restored, with the normal window title. Also, the name
+ * is in UTF-8, so we should do the normal conversion to either wide
+ * chars or system codepage, and use either the W or A version of
+ * SetWindowText(), depending on Windows version.
+ */
+ API_CALL (SetWindowText, (GDK_SURFACE_HWND (window), name));
+#endif
+}
+
+static GdkSurface *
+gdk_win32_surface_get_group (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return NULL;
+
+ g_warning ("gdk_surface_get_group not yet implemented");
+
+ return NULL;
+}
+
+static void
+gdk_win32_surface_set_group (GdkSurface *window,
+ GdkSurface *leader)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (leader == NULL || GDK_IS_SURFACE (leader));
+
+ if (GDK_SURFACE_DESTROYED (window) || GDK_SURFACE_DESTROYED (leader))
+ return;
+
+ g_warning ("gdk_surface_set_group not implemented");
+}
+
+static void
+update_single_bit (LONG *style,
+ gboolean all,
+ int gdk_bit,
+ int style_bit)
+{
+ /* all controls the interpretation of gdk_bit -- if all is TRUE,
+ * gdk_bit indicates whether style_bit is off; if all is FALSE, gdk
+ * bit indicate whether style_bit is on
+ */
+ if ((!all && gdk_bit) || (all && !gdk_bit))
+ *style |= style_bit;
+ else
+ *style &= ~style_bit;
+}
+
+/*
+ * Returns TRUE if window has no decorations.
+ * Usually it means CSD windows, because GTK
+ * calls gdk_surface_set_decorations (window, 0);
+ * This is used to decide whether a toplevel should
+ * be made layered, thus it
+ * only returns TRUE for toplevels (until GTK minimal
+ * system requirements are lifted to Windows 8 or newer,
+ * because only toplevels can be layered).
+ */
+gboolean
+_gdk_win32_surface_lacks_wm_decorations (GdkSurface *window)
+{
+ GdkSurfaceImplWin32 *impl;
+ LONG style;
+ gboolean has_any_decorations;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return FALSE;
+
+ /* only toplevels can be layered */
+ if (!WINDOW_IS_TOPLEVEL (window))
+ return FALSE;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ /* This is because GTK calls gdk_surface_set_decorations (window, 0),
+ * even though GdkWMDecoration docs indicate that 0 does NOT mean
+ * "no decorations".
+ */
+ if (impl->decorations &&
+ *impl->decorations == 0)
+ return TRUE;
+
+ if (GDK_SURFACE_HWND (window) == 0)
+ return FALSE;
+
+ style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
+
+ if (style == 0)
+ {
+ DWORD w32_error = GetLastError ();
+
+ GDK_NOTE (MISC, g_print ("Failed to get style of window %p (handle %p): %lu\n",
+ window, GDK_SURFACE_HWND (window), w32_error));
+ return FALSE;
+ }
+
+ /* Keep this in sync with _gdk_win32_surface_update_style_bits() */
+ /* We don't check what get_effective_window_decorations()
+ * has to say, because it gives suggestions based on
+ * various hints, while we want *actual* decorations,
+ * or their absence.
+ */
+ has_any_decorations = FALSE;
+
+ if (style & (WS_BORDER | WS_THICKFRAME | WS_CAPTION |
+ WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX))
+ has_any_decorations = TRUE;
+ else
+ GDK_NOTE (MISC, g_print ("Window %p (handle %p): has no decorations (style %lx)\n",
+ window, GDK_SURFACE_HWND (window), style));
+
+ return !has_any_decorations;
+}
+
+void
+_gdk_win32_surface_update_style_bits (GdkSurface *window)
+{
+ GdkSurfaceImplWin32 *impl = (GdkSurfaceImplWin32 *)window->impl;
+ GdkWMDecoration decorations;
+ LONG old_style, new_style, old_exstyle, new_exstyle;
+ gboolean all;
+ RECT rect, before, after;
+ gboolean was_topmost;
+ gboolean will_be_topmost;
+ HWND insert_after;
+ UINT flags;
+
+ if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
+ return;
+
+ old_style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
+ old_exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
+
+ GetClientRect (GDK_SURFACE_HWND (window), &before);
+ after = before;
+ AdjustWindowRectEx (&before, old_style, FALSE, old_exstyle);
+
+ was_topmost = (old_exstyle & WS_EX_TOPMOST) ? TRUE : FALSE;
+ will_be_topmost = was_topmost;
+
+ old_exstyle &= ~WS_EX_TOPMOST;
+
+ new_style = old_style;
+ new_exstyle = old_exstyle;
+
+ if (window->window_type == GDK_SURFACE_TEMP)
+ {
+ new_exstyle |= WS_EX_TOOLWINDOW;
+ will_be_topmost = TRUE;
+ }
+ else if (impl->type_hint == GDK_SURFACE_TYPE_HINT_UTILITY)
+ {
+ new_exstyle |= WS_EX_TOOLWINDOW;
+ }
+ else
+ {
+ new_exstyle &= ~WS_EX_TOOLWINDOW;
+ }
+
+ /* We can get away with using layered windows
+ * only when no decorations are needed. It can mean
+ * CSD or borderless non-CSD windows (tooltips?).
+ *
+ * If this window cannot use layered windows, disable it always.
+ * This currently applies to windows using OpenGL, which
+ * does not work with layered windows.
+ */
+ if (impl->suppress_layered == 0)
+ {
+ if (_gdk_win32_surface_lacks_wm_decorations (window))
+ impl->layered = g_strcmp0 (g_getenv ("GDK_WIN32_LAYERED"), "0") != 0;
+ }
+ else
+ impl->layered = FALSE;
+
+ if (impl->layered)
+ new_exstyle |= WS_EX_LAYERED;
+ else
+ new_exstyle &= ~WS_EX_LAYERED;
+
+ if (get_effective_window_decorations (window, &decorations))
+ {
+ all = (decorations & GDK_DECOR_ALL);
+ /* Keep this in sync with the test in _gdk_win32_surface_lacks_wm_decorations() */
+ update_single_bit (&new_style, all, decorations & GDK_DECOR_BORDER, WS_BORDER);
+ update_single_bit (&new_style, all, decorations & GDK_DECOR_RESIZEH, WS_THICKFRAME);
+ update_single_bit (&new_style, all, decorations & GDK_DECOR_TITLE, WS_CAPTION);
+ update_single_bit (&new_style, all, decorations & GDK_DECOR_MENU, WS_SYSMENU);
+ update_single_bit (&new_style, all, decorations & GDK_DECOR_MINIMIZE, WS_MINIMIZEBOX);
+ update_single_bit (&new_style, all, decorations & GDK_DECOR_MAXIMIZE, WS_MAXIMIZEBOX);
+ }
+
+ if (old_style == new_style && old_exstyle == new_exstyle )
+ {
+ GDK_NOTE (MISC, g_print ("_gdk_win32_surface_update_style_bits: %p: no change\n",
+ GDK_SURFACE_HWND (window)));
+ return;
+ }
+
+ if (old_style != new_style)
+ {
+ GDK_NOTE (MISC, g_print ("_gdk_win32_surface_update_style_bits: %p: STYLE: %s => %s\n",
+ GDK_SURFACE_HWND (window),
+ _gdk_win32_surface_style_to_string (old_style),
+ _gdk_win32_surface_style_to_string (new_style)));
+
+ SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE, new_style);
+ }
+
+ if (old_exstyle != new_exstyle)
+ {
+ GDK_NOTE (MISC, g_print ("_gdk_win32_surface_update_style_bits: %p: EXSTYLE: %s => %s\n",
+ GDK_SURFACE_HWND (window),
+ _gdk_win32_surface_exstyle_to_string (old_exstyle),
+ _gdk_win32_surface_exstyle_to_string (new_exstyle)));
+
+ SetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE, new_exstyle);
+ }
+
+ AdjustWindowRectEx (&after, new_style, FALSE, new_exstyle);
+
+ GetWindowRect (GDK_SURFACE_HWND (window), &rect);
+ rect.left += after.left - before.left;
+ rect.top += after.top - before.top;
+ rect.right += after.right - before.right;
+ rect.bottom += after.bottom - before.bottom;
+
+ flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOREPOSITION;
+
+ if (will_be_topmost && !was_topmost)
+ {
+ insert_after = HWND_TOPMOST;
+ }
+ else if (was_topmost && !will_be_topmost)
+ {
+ insert_after = HWND_NOTOPMOST;
+ }
+ else
+ {
+ flags |= SWP_NOZORDER;
+ insert_after = SWP_NOZORDER_SPECIFIED;
+ }
+
+ SetWindowPos (GDK_SURFACE_HWND (window), insert_after,
+ rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ flags);
+}
+
+static void
+update_single_system_menu_entry (HMENU hmenu,
+ gboolean all,
+ int gdk_bit,
+ int menu_entry)
+{
+ /* all controls the interpretation of gdk_bit -- if all is TRUE,
+ * gdk_bit indicates whether menu entry is disabled; if all is
+ * FALSE, gdk bit indicate whether menu entry is enabled
+ */
+ if ((!all && gdk_bit) || (all && !gdk_bit))
+ EnableMenuItem (hmenu, menu_entry, MF_BYCOMMAND | MF_ENABLED);
+ else
+ EnableMenuItem (hmenu, menu_entry, MF_BYCOMMAND | MF_GRAYED);
+}
+
+static void
+update_system_menu (GdkSurface *window)
+{
+ GdkWMFunction functions;
+ BOOL all;
+
+ if (_gdk_surface_get_functions (window, &functions))
+ {
+ HMENU hmenu = GetSystemMenu (GDK_SURFACE_HWND (window), FALSE);
+
+ all = (functions & GDK_FUNC_ALL);
+ update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_RESIZE, SC_SIZE);
+ update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MOVE, SC_MOVE);
+ update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MINIMIZE, SC_MINIMIZE);
+ update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MAXIMIZE, SC_MAXIMIZE);
+ update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_CLOSE, SC_CLOSE);
+ }
+}
+
+static void
+gdk_win32_surface_set_decorations (GdkSurface *window,
+ GdkWMDecoration decorations)
+{
+ GdkSurfaceImplWin32 *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_set_decorations: %p: %s %s%s%s%s%s%s\n",
+ GDK_SURFACE_HWND (window),
+ (decorations & GDK_DECOR_ALL ? "clearing" : "setting"),
+ (decorations & GDK_DECOR_BORDER ? "BORDER " : ""),
+ (decorations & GDK_DECOR_RESIZEH ? "RESIZEH " : ""),
+ (decorations & GDK_DECOR_TITLE ? "TITLE " : ""),
+ (decorations & GDK_DECOR_MENU ? "MENU " : ""),
+ (decorations & GDK_DECOR_MINIMIZE ? "MINIMIZE " : ""),
+ (decorations & GDK_DECOR_MAXIMIZE ? "MAXIMIZE " : "")));
+
+ if (!impl->decorations)
+ impl->decorations = g_malloc (sizeof (GdkWMDecoration));
+
+ *impl->decorations = decorations;
+
+ _gdk_win32_surface_update_style_bits (window);
+}
+
+static gboolean
+gdk_win32_surface_get_decorations (GdkSurface *window,
+ GdkWMDecoration *decorations)
+{
+ GdkSurfaceImplWin32 *impl;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ if (impl->decorations == NULL)
+ return FALSE;
+
+ *decorations = *impl->decorations;
+
+ return TRUE;
+}
+
+static GQuark
+get_functions_quark ()
+{
+ static GQuark quark = 0;
+
+ if (!quark)
+ quark = g_quark_from_static_string ("gdk-window-functions");
+
+ return quark;
+}
+
+static void
+gdk_win32_surface_set_functions (GdkSurface *window,
+ GdkWMFunction functions)
+{
+ GdkWMFunction* functions_copy;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_set_functions: %p: %s %s%s%s%s%s\n",
+ GDK_SURFACE_HWND (window),
+ (functions & GDK_FUNC_ALL ? "clearing" : "setting"),
+ (functions & GDK_FUNC_RESIZE ? "RESIZE " : ""),
+ (functions & GDK_FUNC_MOVE ? "MOVE " : ""),
+ (functions & GDK_FUNC_MINIMIZE ? "MINIMIZE " : ""),
+ (functions & GDK_FUNC_MAXIMIZE ? "MAXIMIZE " : ""),
+ (functions & GDK_FUNC_CLOSE ? "CLOSE " : "")));
+
+ functions_copy = g_malloc (sizeof (GdkWMFunction));
+ *functions_copy = functions;
+ g_object_set_qdata_full (G_OBJECT (window), get_functions_quark (), functions_copy, g_free);
+
+ update_system_menu (window);
+}
+
+gboolean
+_gdk_surface_get_functions (GdkSurface *window,
+ GdkWMFunction *functions)
+{
+ GdkWMFunction* functions_set;
+
+ functions_set = g_object_get_qdata (G_OBJECT (window), get_functions_quark ());
+ if (functions_set)
+ *functions = *functions_set;
+
+ return (functions_set != NULL);
+}
+
+#if defined(MORE_AEROSNAP_DEBUGGING)
+static void
+log_region (gchar *prefix, AeroSnapEdgeRegion *region)
+{
+ GDK_NOTE (MISC, g_print ("Region %s:\n"
+ "edge %d x %d @ %d x %d\n"
+ "trig %d x %d @ %d x %d\n",
+ prefix,
+ region->edge.width,
+ region->edge.height,
+ region->edge.x,
+ region->edge.y,
+ region->trigger.width,
+ region->trigger.height,
+ region->trigger.x,
+ region->trigger.y));
+}
+#endif
+
+static void
+calculate_aerosnap_regions (GdkW32DragMoveResizeContext *context)
+{
+ GdkDisplay *display;
+ gint n_monitors, monitor_idx, other_monitor_idx;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (context->window->impl);
+#if defined(MORE_AEROSNAP_DEBUGGING)
+ gint i;
+#endif
+
+ display = gdk_display_get_default ();
+ n_monitors = gdk_display_get_n_monitors (display);
+
+#define _M_UP 0
+#define _M_DOWN 1
+#define _M_LEFT 2
+#define _M_RIGHT 3
+
+ for (monitor_idx = 0; monitor_idx < n_monitors; monitor_idx++)
+ {
+ GdkRectangle wa;
+ GdkRectangle geometry;
+ AeroSnapEdgeRegion snap_region;
+ gboolean move_edge[4] = { TRUE, FALSE, TRUE, TRUE };
+ gboolean resize_edge[2] = { TRUE, TRUE };
+ gint diff;
+ gint thickness, trigger_thickness;
+ GdkMonitor *monitor;
+
+ monitor = gdk_display_get_monitor (display, monitor_idx);
+ gdk_monitor_get_workarea (monitor, &wa);
+ gdk_monitor_get_geometry (monitor, &geometry);
+
+ for (other_monitor_idx = 0;
+ other_monitor_idx < n_monitors &&
+ (move_edge[_M_UP] || move_edge[_M_LEFT] ||
+ move_edge[_M_RIGHT] || resize_edge[_M_DOWN]);
+ other_monitor_idx++)
+ {
+ GdkRectangle other_wa;
+ GdkMonitor *other_monitor;
+
+ if (other_monitor_idx == monitor_idx)
+ continue;
+
+ other_monitor = gdk_display_get_monitor (display, other_monitor_idx);
+ gdk_monitor_get_workarea (other_monitor, &other_wa);
+
+ /* An edge triggers AeroSnap only if there are no
+ * monitors beyond that edge.
+ * Even if there's another monitor, but it does not cover
+ * the whole edge (it's smaller or is not aligned to
+ * the corner of current monitor), that edge is still
+ * removed from the trigger list.
+ */
+ if (other_wa.x >= wa.x + wa.width)
+ move_edge[_M_RIGHT] = FALSE;
+
+ if (other_wa.x + other_wa.width <= wa.x)
+ move_edge[_M_LEFT] = FALSE;
+
+ if (other_wa.y + other_wa.height <= wa.y)
+ {
+ move_edge[_M_UP] = FALSE;
+ resize_edge[_M_UP] = FALSE;
+ }
+
+ if (other_wa.y >= wa.y + wa.height)
+ {
+ /* no move_edge for the bottom edge, just resize_edge */
+ resize_edge[_M_DOWN] = FALSE;
+ }
+ }
+
+ thickness = AEROSNAP_REGION_THICKNESS * impl->window_scale;
+ trigger_thickness = AEROSNAP_REGION_TRIGGER_THICKNESS * impl->window_scale;
+
+ snap_region.edge = wa;
+ snap_region.trigger = wa;
+ snap_region.edge.height = thickness;
+ snap_region.trigger.height = trigger_thickness;
+
+ /* Extend both regions into toolbar space.
+ * When there's no toolbar, diff == 0.
+ */
+ diff = wa.y - geometry.y;
+ snap_region.edge.height += diff;
+ snap_region.edge.y -= diff;
+ snap_region.trigger.height += diff;
+ snap_region.trigger.y -= diff;
+
+ if (move_edge[_M_UP])
+ g_array_append_val (context->maximize_regions, snap_region);
+
+ if (resize_edge[_M_UP])
+ g_array_append_val (context->fullup_regions, snap_region);
+
+ snap_region.edge = wa;
+ snap_region.trigger = wa;
+ snap_region.edge.width = thickness;
+ snap_region.trigger.width = trigger_thickness;
+
+ diff = wa.x - geometry.x;
+ snap_region.edge.width += diff;
+ snap_region.edge.x -= diff;
+ snap_region.trigger.width += diff;
+ snap_region.trigger.x -= diff;
+
+ if (move_edge[_M_LEFT])
+ g_array_append_val (context->halfleft_regions, snap_region);
+
+ snap_region.edge = wa;
+ snap_region.trigger = wa;
+ snap_region.edge.x += wa.width - thickness;
+ snap_region.edge.width = thickness;
+ snap_region.trigger.x += wa.width - trigger_thickness;
+ snap_region.trigger.width = trigger_thickness;
+
+ diff = (geometry.x + geometry.width) - (wa.x + wa.width);
+ snap_region.edge.width += diff;
+ snap_region.trigger.width += diff;
+
+ if (move_edge[_M_RIGHT])
+ g_array_append_val (context->halfright_regions, snap_region);
+
+ snap_region.edge = wa;
+ snap_region.trigger = wa;
+ snap_region.edge.y += wa.height - thickness;
+ snap_region.edge.height = thickness;
+ snap_region.trigger.y += wa.height - trigger_thickness;
+ snap_region.trigger.height = trigger_thickness;
+
+ diff = (geometry.y + geometry.height) - (wa.y + wa.height);
+ snap_region.edge.height += diff;
+ snap_region.trigger.height += diff;
+
+ if (resize_edge[_M_DOWN])
+ g_array_append_val (context->fullup_regions, snap_region);
+ }
+
+#undef _M_UP
+#undef _M_DOWN
+#undef _M_LEFT
+#undef _M_RIGHT
+
+#if defined(MORE_AEROSNAP_DEBUGGING)
+ for (i = 0; i < context->maximize_regions->len; i++)
+ log_region ("maximize", &g_array_index (context->maximize_regions, AeroSnapEdgeRegion, i));
+
+ for (i = 0; i < context->halfleft_regions->len; i++)
+ log_region ("halfleft", &g_array_index (context->halfleft_regions, AeroSnapEdgeRegion, i));
+
+ for (i = 0; i < context->halfright_regions->len; i++)
+ log_region ("halfright", &g_array_index (context->halfright_regions, AeroSnapEdgeRegion, i));
+
+ for (i = 0; i < context->fullup_regions->len; i++)
+ log_region ("fullup", &g_array_index (context->fullup_regions, AeroSnapEdgeRegion, i));
+#endif
+}
+
+static void
+discard_snapinfo (GdkSurface *window)
+{
+ GdkSurfaceImplWin32 *impl;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ impl->snap_state = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
+
+ if (impl->snap_stash == NULL)
+ return;
+
+ g_clear_pointer (&impl->snap_stash, g_free);
+ g_clear_pointer (&impl->snap_stash_int, g_free);
+}
+
+static void
+unsnap (GdkSurface *window,
+ GdkMonitor *monitor)
+{
+ GdkSurfaceImplWin32 *impl;
+ GdkRectangle rect;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ impl->snap_state = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
+
+ if (impl->snap_stash == NULL)
+ return;
+
+ gdk_monitor_get_workarea (monitor, &rect);
+
+ GDK_NOTE (MISC, g_print ("Monitor work area %d x %d @ %d : %d\n", rect.width, rect.height, rect.x, rect.y));
+
+ if (rect.width >= impl->snap_stash_int->width &&
+ rect.height >= impl->snap_stash_int->height)
+ {
+ /* If the window fits into new work area without resizing it,
+ * place it into new work area without resizing it.
+ */
+ gdouble left, right, up, down, hratio, vratio;
+ gdouble hscale, vscale;
+ gdouble new_left, new_up;
+
+ left = impl->snap_stash->x;
+ right = 1.0 - (impl->snap_stash->x + impl->snap_stash->width);
+ up = impl->snap_stash->y;
+ down = 1.0 - (impl->snap_stash->y + impl->snap_stash->height);
+ hscale = 1.0;
+
+ if (right > 0.001)
+ {
+ hratio = left / right;
+ hscale = hratio / (1.0 + hratio);
+ }
+
+ new_left = (gdouble) (rect.width - impl->snap_stash_int->width) * hscale;
+
+ vscale = 1.0;
+
+ if (down > 0.001)
+ {
+ vratio = up / down;
+ vscale = vratio / (1.0 + vratio);
+ }
+
+ new_up = (gdouble) (rect.height - impl->snap_stash_int->height) * vscale;
+
+ rect.x = round (rect.x + new_left);
+ rect.y = round (rect.y + new_up);
+ rect.width = impl->snap_stash_int->width;
+ rect.height = impl->snap_stash_int->height;
+ }
+ else
+ {
+ /* Calculate actual unsnapped window size based on its
+ * old relative size. Same for position.
+ */
+ rect.x += round (rect.width * impl->snap_stash->x);
+ rect.y += round (rect.height * impl->snap_stash->y);
+ rect.width = round (rect.width * impl->snap_stash->width);
+ rect.height = round (rect.height * impl->snap_stash->height);
+ }
+
+ GDK_NOTE (MISC, g_print ("Unsnapped window size %d x %d @ %d : %d\n", rect.width, rect.height, rect.x, rect.y));
+
+ gdk_surface_move_resize (window, rect.x, rect.y,
+ rect.width, rect.height);
+
+ g_clear_pointer (&impl->snap_stash, g_free);
+ g_clear_pointer (&impl->snap_stash_int, g_free);
+}
+
+static void
+stash_window (GdkSurface *window,
+ GdkSurfaceImplWin32 *impl)
+{
+ gint x, y;
+ gint width, wwidth;
+ gint height, wheight;
+ WINDOWPLACEMENT placement;
+ HMONITOR hmonitor;
+ MONITORINFO hmonitor_info;
+
+ placement.length = sizeof(WINDOWPLACEMENT);
+
+ /* Use W32 API to get unmaximized window size, which GDK doesn't remember */
+ if (!GetWindowPlacement (GDK_SURFACE_HWND (window), &placement))
+ return;
+
+ /* MSDN is very vague, but in practice rcNormalPosition is the same as GetWindowRect(),
+ * only with adjustments for toolbars (which creates rather weird coodinate space issues).
+ * We need to get monitor info and apply workarea vs monitorarea diff to turn
+ * these into screen coordinates proper.
+ */
+ hmonitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
+ hmonitor_info.cbSize = sizeof (hmonitor_info);
+
+ if (!GetMonitorInfoA (hmonitor, &hmonitor_info))
+ return;
+
+ if (impl->snap_stash == NULL)
+ impl->snap_stash = g_new0 (GdkRectangleDouble, 1);
+
+ if (impl->snap_stash_int == NULL)
+ impl->snap_stash_int = g_new0 (GdkRectangle, 1);
+
+ GDK_NOTE (MISC, g_print ("monitor work area %ld x %ld @ %ld : %ld\n",
+ (hmonitor_info.rcWork.right - hmonitor_info.rcWork.left) / impl->window_scale,
+ (hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top) / impl->window_scale,
+ hmonitor_info.rcWork.left,
+ hmonitor_info.rcWork.top));
+ GDK_NOTE (MISC, g_print ("monitor area %ld x %ld @ %ld : %ld\n",
+ (hmonitor_info.rcMonitor.right - hmonitor_info.rcMonitor.left) / impl->window_scale,
+ (hmonitor_info.rcMonitor.bottom - hmonitor_info.rcMonitor.top) / impl->window_scale,
+ hmonitor_info.rcMonitor.left,
+ hmonitor_info.rcMonitor.top));
+ GDK_NOTE (MISC, g_print ("window work place %ld x %ld @ %ld : %ld\n",
+ (placement.rcNormalPosition.right - placement.rcNormalPosition.left) / impl->window_scale,
+ (placement.rcNormalPosition.bottom - placement.rcNormalPosition.top) / impl->window_scale,
+ placement.rcNormalPosition.left,
+ placement.rcNormalPosition.top));
+
+ width = (placement.rcNormalPosition.right - placement.rcNormalPosition.left) / impl->window_scale;
+ height = (placement.rcNormalPosition.bottom - placement.rcNormalPosition.top) / impl->window_scale;
+ x = (placement.rcNormalPosition.left - hmonitor_info.rcMonitor.left) / impl->window_scale;
+ y = (placement.rcNormalPosition.top - hmonitor_info.rcMonitor.top) / impl->window_scale;
+
+ wwidth = (hmonitor_info.rcWork.right - hmonitor_info.rcWork.left) / impl->window_scale;
+ wheight = (hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top) / impl->window_scale;
+
+ impl->snap_stash->x = (gdouble) (x) / (gdouble) (wwidth);
+ impl->snap_stash->y = (gdouble) (y) / (gdouble) (wheight);
+ impl->snap_stash->width = (gdouble) width / (gdouble) (wwidth);
+ impl->snap_stash->height = (gdouble) height / (gdouble) (wheight);
+
+ impl->snap_stash_int->x = x;
+ impl->snap_stash_int->y = y;
+ impl->snap_stash_int->width = width;
+ impl->snap_stash_int->height = height;
+
+ GDK_NOTE (MISC, g_print ("Stashed window %d x %d @ %d : %d as %f x %f @ %f : %f\n",
+ width, height, x, y,
+ impl->snap_stash->width, impl->snap_stash->height, impl->snap_stash->x, impl->snap_stash->y));
+}
+
+static void
+snap_up (GdkSurface *window)
+{
+ SHORT maxysize;
+ gint x, y;
+ gint width, height;
+ GdkSurfaceImplWin32 *impl;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ impl->snap_state = GDK_WIN32_AEROSNAP_STATE_FULLUP;
+
+ stash_window (window, impl);
+
+ maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN) / impl->window_scale;
+ gdk_surface_get_position (window, &x, &y);
+ width = gdk_surface_get_width (window);
+
+ y = 0;
+ height = maxysize;
+
+ x = x - impl->margins.left;
+ y = y - impl->margins.top;
+ width += impl->margins_x;
+ height += impl->margins_y;
+
+ gdk_surface_move_resize (window, x, y, width, height);
+}
+
+static void
+snap_left (GdkSurface *window,
+ GdkMonitor *monitor,
+ GdkMonitor *snap_monitor)
+{
+ GdkRectangle rect;
+ GdkSurfaceImplWin32 *impl;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
+
+ gdk_monitor_get_workarea (snap_monitor, &rect);
+
+ stash_window (window, impl);
+
+ rect.width = rect.width / 2;
+
+ rect.x = rect.x - impl->margins.left;
+ rect.y = rect.y - impl->margins.top;
+ rect.width = rect.width + impl->margins_x;
+ rect.height = rect.height + impl->margins_y;
+
+ gdk_surface_move_resize (window, rect.x, rect.y, rect.width, rect.height);
+}
+
+static void
+snap_right (GdkSurface *window,
+ GdkMonitor *monitor,
+ GdkMonitor *snap_monitor)
+{
+ GdkRectangle rect;
+ GdkSurfaceImplWin32 *impl;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
+
+ gdk_monitor_get_workarea (snap_monitor, &rect);
+
+ stash_window (window, impl);
+
+ rect.width = rect.width / 2;
+ rect.x += rect.width;
+
+ rect.x = rect.x - impl->margins.left;
+ rect.y = rect.y - impl->margins.top;
+ rect.width = rect.width + impl->margins_x;
+ rect.height = rect.height + impl->margins_y;
+
+ gdk_surface_move_resize (window, rect.x, rect.y, rect.width, rect.height);
+}
+
+void
+_gdk_win32_surface_handle_aerosnap (GdkSurface *window,
+ GdkWin32AeroSnapCombo combo)
+{
+ GdkSurfaceImplWin32 *impl;
+ GdkDisplay *display;
+ gint n_monitors;
+ GdkSurfaceState window_state = gdk_surface_get_state (window);
+ gboolean minimized = window_state & GDK_SURFACE_STATE_ICONIFIED;
+ gboolean maximized = window_state & GDK_SURFACE_STATE_MAXIMIZED;
+ gboolean halfsnapped;
+ GdkMonitor *monitor;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ display = gdk_surface_get_display (window);
+ n_monitors = gdk_display_get_n_monitors (display);
+ monitor = gdk_display_get_monitor_at_window (display, window);
+
+ if (minimized && maximized)
+ minimized = FALSE;
+
+ halfsnapped = (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT ||
+ impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT ||
+ impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP);
+
+ switch (combo)
+ {
+ case GDK_WIN32_AEROSNAP_COMBO_NOTHING:
+ /* Do nothing */
+ break;
+ case GDK_WIN32_AEROSNAP_COMBO_UP:
+ if (!maximized)
+ {
+ unsnap (window, monitor);
+ gdk_surface_maximize (window);
+ }
+ break;
+ case GDK_WIN32_AEROSNAP_COMBO_DOWN:
+ case GDK_WIN32_AEROSNAP_COMBO_SHIFTDOWN:
+ if (maximized)
+ {
+ gdk_surface_unmaximize (window);
+ unsnap (window, monitor);
+ }
+ else if (halfsnapped)
+ unsnap (window, monitor);
+ else if (!minimized)
+ gdk_surface_iconify (window);
+ break;
+ case GDK_WIN32_AEROSNAP_COMBO_LEFT:
+ if (maximized)
+ gdk_surface_unmaximize (window);
+
+ if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED ||
+ impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP)
+ {
+ unsnap (window, monitor);
+ snap_left (window, monitor, monitor);
+ }
+ else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT)
+ {
+ unsnap (window, monitor);
+ snap_right (window,
+ monitor,
+ gdk_monitor_is_primary (monitor) ? monitor : gdk_display_get_monitor (display, n_monitors - 1));
+ }
+ else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT)
+ {
+ unsnap (window, monitor);
+ }
+ break;
+ case GDK_WIN32_AEROSNAP_COMBO_RIGHT:
+ if (maximized)
+ gdk_surface_unmaximize (window);
+
+ if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED ||
+ impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP)
+ {
+ unsnap (window, monitor);
+ snap_right (window, monitor, monitor);
+ }
+ else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT)
+ {
+ unsnap (window, monitor);
+ }
+ else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT)
+ {
+ gint i;
+
+ unsnap (window, monitor);
+ if (n_monitors == 1 ||
+ monitor == gdk_display_get_monitor (display, n_monitors - 1))
+ {
+ snap_left (window, monitor, monitor);
+ }
+ else
+ {
+ for (i = 0; i < n_monitors; i++)
+ {
+ if (monitor == gdk_display_get_monitor (display, i))
+ break;
+ }
+
+ snap_left (window, monitor, gdk_display_get_monitor (display, i + 1));
+ }
+ }
+ break;
+ case GDK_WIN32_AEROSNAP_COMBO_SHIFTUP:
+ if (!maximized &&
+ impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED)
+ {
+ snap_up (window);
+ }
+ break;
+ case GDK_WIN32_AEROSNAP_COMBO_SHIFTLEFT:
+ case GDK_WIN32_AEROSNAP_COMBO_SHIFTRIGHT:
+ /* No implementation needed at the moment */
+ break;
+ }
+}
+
+static void
+apply_snap (GdkSurface *window,
+ GdkWin32AeroSnapState snap)
+{
+ GdkMonitor *monitor;
+ GdkDisplay *display;
+
+ display = gdk_surface_get_display (window);
+ monitor = gdk_display_get_monitor_at_window (display, window);
+
+ switch (snap)
+ {
+ case GDK_WIN32_AEROSNAP_STATE_UNDETERMINED:
+ break;
+ case GDK_WIN32_AEROSNAP_STATE_MAXIMIZE:
+ unsnap (window, monitor);
+ gdk_surface_maximize (window);
+ break;
+ case GDK_WIN32_AEROSNAP_STATE_HALFLEFT:
+ unsnap (window, monitor);
+ snap_left (window, monitor, monitor);
+ break;
+ case GDK_WIN32_AEROSNAP_STATE_HALFRIGHT:
+ unsnap (window, monitor);
+ snap_right (window, monitor, monitor);
+ break;
+ case GDK_WIN32_AEROSNAP_STATE_FULLUP:
+ snap_up (window);
+ break;
+ }
+}
+
+/* Registers a dumb window class. This window
+ * has DefWindowProc() for a window procedure and
+ * does not do anything that GdkSurface-bound HWNDs do.
+ */
+static ATOM
+RegisterGdkDumbClass ()
+{
+ static ATOM klassDUMB = 0;
+ static WNDCLASSEXW wcl;
+ ATOM klass = 0;
+
+ wcl.cbSize = sizeof (WNDCLASSEX);
+ wcl.style = 0; /* DON'T set CS_<H,V>REDRAW. It causes total redraw
+ * on WM_SIZE and WM_MOVE. Flicker, Performance!
+ */
+ wcl.lpfnWndProc = DefWindowProcW;
+ wcl.cbClsExtra = 0;
+ wcl.cbWndExtra = 0;
+ wcl.hInstance = _gdk_app_hmodule;
+ wcl.hIcon = 0;
+ wcl.hIconSm = 0;
+ wcl.lpszMenuName = NULL;
+ wcl.hbrBackground = NULL;
+ wcl.hCursor = LoadCursor (NULL, IDC_ARROW);
+ wcl.style |= CS_OWNDC;
+ wcl.lpszClassName = L"gdkWindowDumb";
+
+ if (klassDUMB == 0)
+ klassDUMB = RegisterClassExW (&wcl);
+
+ klass = klassDUMB;
+
+ if (klass == 0)
+ {
+ WIN32_API_FAILED ("RegisterClassExW");
+ g_error ("That is a fatal error");
+ }
+
+ return klass;
+}
+
+static gboolean
+ensure_snap_indicator_exists (GdkW32DragMoveResizeContext *context)
+{
+ if (context->shape_indicator == NULL)
+ {
+ HWND handle;
+ ATOM klass;
+ klass = RegisterGdkDumbClass ();
+
+ handle = CreateWindowExW (WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOACTIVATE,
+ MAKEINTRESOURCEW (klass),
+ L"",
+ WS_POPUP,
+ 0,
+ 0,
+ 0, 0,
+ NULL,
+ NULL,
+ _gdk_app_hmodule,
+ NULL);
+
+ context->shape_indicator = handle;
+ }
+
+ return context->shape_indicator != NULL;
+}
+
+static gboolean
+ensure_snap_indicator_surface (GdkW32DragMoveResizeContext *context,
+ gint width,
+ gint height,
+ guint scale)
+{
+ if (context->indicator_surface != NULL &&
+ (context->indicator_surface_width < width ||
+ context->indicator_surface_height < height))
+ {
+ cairo_surface_destroy (context->indicator_surface);
+ context->indicator_surface = NULL;
+ }
+
+ if (context->indicator_surface == NULL)
+ context->indicator_surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
+ width * scale,
+ height * scale);
+
+ if (cairo_surface_status (context->indicator_surface) != CAIRO_STATUS_SUCCESS)
+ {
+ cairo_surface_destroy (context->indicator_surface);
+ context->indicator_surface = NULL;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Indicator is drawn with some inward offset, so that it does
+ * not hug screen edges.
+ */
+static void
+adjust_indicator_rectangle (GdkRectangle *rect,
+ gboolean inward)
+{
+ gdouble inverter;
+ const gint gap = AEROSNAP_INDICATOR_EDGE_GAP;
+#if defined(MORE_AEROSNAP_DEBUGGING)
+ GdkRectangle cache = *rect;
+#endif
+
+ if (inward)
+ inverter = 1.0;
+ else
+ inverter = -1.0;
+
+ rect->x += (gap * inverter);
+ rect->y += (gap * inverter);
+ rect->width -= (gap * 2 * inverter);
+ rect->height -= (gap * 2 * inverter);
+
+#if defined(MORE_AEROSNAP_DEBUGGING)
+ GDK_NOTE (MISC, g_print ("Adjusted %d x %d @ %d : %d -> %d x %d @ %d : %d\n",
+ cache.width, cache.height, cache.x, cache.y,
+ rect->width, rect->height, rect->x, rect->y));
+#endif
+}
+
+static void
+rounded_rectangle (cairo_t *cr,
+ gint x,
+ gint y,
+ gint width,
+ gint height,
+ gdouble radius,
+ gdouble line_width,
+ GdkRGBA *fill,
+ GdkRGBA *outline)
+{
+ gdouble degrees = M_PI / 180.0;
+
+ if (fill == NULL && outline == NULL)
+ return;
+
+ cairo_save (cr);
+ cairo_new_sub_path (cr);
+ cairo_arc (cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
+ cairo_arc (cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
+ cairo_arc (cr, (x + radius), y + height - radius, radius, 90 * degrees, 180 * degrees);
+ cairo_arc (cr, (x + radius), (y + radius), radius, 180 * degrees, 270 * degrees);
+ cairo_close_path (cr);
+
+ if (fill)
+ {
+ cairo_set_source_rgba (cr, fill->red, fill->green, fill->blue, fill->alpha);
+
+ if (outline)
+ cairo_fill_preserve (cr);
+ else
+ cairo_fill (cr);
+ }
+
+ if (outline)
+ {
+ cairo_set_source_rgba (cr, outline->red, outline->green, outline->blue, outline->alpha);
+ cairo_set_line_width (cr, line_width);
+ cairo_stroke (cr);
+ }
+
+ cairo_restore (cr);
+}
+
+/* Translates linear animation scale into some kind of curve */
+static gdouble
+curve (gdouble val)
+{
+ /* TODO: try different curves. For now it's just linear */
+ return val;
+}
+
+static gboolean
+draw_indicator (GdkW32DragMoveResizeContext *context,
+ gint64 timestamp)
+{
+ cairo_t *cr;
+ GdkRGBA outline = {0, 0, 1.0, 1.0};
+ GdkRGBA fill = {0, 0, 1.0, 0.8};
+ GdkRectangle current_rect;
+ gint64 current_time = g_get_monotonic_time ();
+ gdouble animation_progress;
+ gboolean last_draw;
+ gdouble line_width;
+ gdouble corner_radius;
+ gint64 animation_duration;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (context->window->impl);
+
+ line_width = AEROSNAP_INDICATOR_LINE_WIDTH * impl->window_scale;
+ corner_radius = AEROSNAP_INDICATOR_CORNER_RADIUS;
+ animation_duration = AEROSNAP_INDICATOR_ANIMATION_DURATION;
+ last_draw = FALSE;
+
+ if (timestamp == 0 &&
+ current_time - context->indicator_start_time > animation_duration)
+ {
+ timestamp = context->indicator_start_time + animation_duration;
+ last_draw = TRUE;
+ }
+
+ if (timestamp != 0)
+ current_time = timestamp;
+
+ animation_progress = (gdouble) (current_time - context->indicator_start_time) / animation_duration;
+
+ if (animation_progress > 1.0)
+ animation_progress = 1.0;
+
+ if (animation_progress < 0)
+ animation_progress = 0;
+
+ animation_progress = curve (animation_progress);
+
+ current_rect = context->indicator_start;
+ current_rect.x += (context->indicator_target.x - context->indicator_start.x) * animation_progress;
+ current_rect.y += (context->indicator_target.y - context->indicator_start.y) * animation_progress;
+ current_rect.width += (context->indicator_target.width - context->indicator_start.width) * animation_progress;
+ current_rect.height += (context->indicator_target.height - context->indicator_start.height) * animation_progress;
+
+ if (context->op == GDK_WIN32_DRAGOP_RESIZE && last_draw)
+ {
+ switch (context->edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ current_rect.x = context->indicator_target.x + (context->indicator_target.width - current_rect.width);
+ current_rect.y = context->indicator_target.y + (context->indicator_target.height - current_rect.height);
+ break;
+ case GDK_SURFACE_EDGE_NORTH:
+ current_rect.y = context->indicator_target.y + (context->indicator_target.height - current_rect.height);
+ break;
+ case GDK_SURFACE_EDGE_WEST:
+ current_rect.x = context->indicator_target.x + (context->indicator_target.width - current_rect.width);
+ break;
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ current_rect.x = context->indicator_target.x + (context->indicator_target.width - current_rect.width);
+ current_rect.y = context->indicator_target.y;
+ break;
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ current_rect.x = context->indicator_target.x;
+ current_rect.y = context->indicator_target.y + (context->indicator_target.height - current_rect.height);
+ break;
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ current_rect.x = context->indicator_target.x;
+ current_rect.y = context->indicator_target.y;
+ break;
+ case GDK_SURFACE_EDGE_SOUTH:
+ current_rect.y = context->indicator_target.y;
+ break;
+ case GDK_SURFACE_EDGE_EAST:
+ current_rect.x = context->indicator_target.x;
+ break;
+ }
+ }
+
+ cr = cairo_create (context->indicator_surface);
+ rounded_rectangle (cr,
+ (current_rect.x - context->indicator_window_rect.x) * impl->window_scale,
+ (current_rect.y - context->indicator_window_rect.y) * impl->window_scale,
+ current_rect.width * impl->window_scale,
+ current_rect.height * impl->window_scale,
+ corner_radius,
+ line_width,
+ &fill, &outline);
+ cairo_destroy (cr);
+
+#if defined(MORE_AEROSNAP_DEBUGGING)
+ GDK_NOTE (MISC, g_print ("Indicator is %d x %d @ %d : %d; current time is %" G_GINT64_FORMAT "\n",
+ current_rect.width, current_rect.height,
+ current_rect.x - context->indicator_window_rect.x,
+ current_rect.y - context->indicator_window_rect.y,
+ current_time));
+#endif
+
+ return last_draw;
+}
+
+static gboolean
+redraw_indicator (gpointer user_data)
+{
+ GdkW32DragMoveResizeContext *context = user_data;
+ POINT window_position;
+ SIZE window_size;
+ BLENDFUNCTION blender;
+ HDC hdc;
+ POINT source_point = { 0, 0 };
+ gboolean last_draw;
+ gdouble indicator_opacity;
+ GdkSurfaceImplWin32 *impl;
+ gboolean do_source_remove = FALSE;
+
+ indicator_opacity = AEROSNAP_INDICATOR_OPACITY;
+
+ if (GDK_SURFACE_DESTROYED (context->window) ||
+ !ensure_snap_indicator_exists (context))
+ {
+ do_source_remove = TRUE;
+ }
+
+ impl = GDK_SURFACE_IMPL_WIN32 (context->window->impl);
+
+ if (!ensure_snap_indicator_surface (context,
+ context->indicator_window_rect.width,
+ context->indicator_window_rect.height,
+ impl->window_scale))
+ {
+ do_source_remove = TRUE;
+ }
+
+ if (do_source_remove)
+ {
+ context->timer = 0;
+ return G_SOURCE_REMOVE;
+ }
+
+ last_draw = draw_indicator (context, context->draw_timestamp);
+
+ window_position.x = (context->indicator_window_rect.x - _gdk_offset_x) * impl->window_scale;
+ window_position.y = (context->indicator_window_rect.y - _gdk_offset_y) * impl->window_scale;
+ window_size.cx = context->indicator_window_rect.width * impl->window_scale;
+ window_size.cy = context->indicator_window_rect.height * impl->window_scale;
+
+ blender.BlendOp = AC_SRC_OVER;
+ blender.BlendFlags = 0;
+ blender.AlphaFormat = AC_SRC_ALPHA;
+ blender.SourceConstantAlpha = 255 * indicator_opacity;
+
+ hdc = cairo_win32_surface_get_dc (context->indicator_surface);
+
+ API_CALL (SetWindowPos, (context->shape_indicator,
+ GDK_SURFACE_HWND (context->window),
+ 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_NOACTIVATE));
+
+#if defined(MORE_AEROSNAP_DEBUGGING)
+ GDK_NOTE (MISC, g_print ("Indicator window position is %ld x %ld @ %ld : %ld\n",
+ window_size.cx, window_size.cy,
+ window_position.x, window_position.y));
+#endif
+
+ API_CALL (UpdateLayeredWindow, (context->shape_indicator, NULL,
+ &window_position, &window_size,
+ hdc, &source_point,
+ 0, &blender, ULW_ALPHA));
+
+ if (last_draw)
+ context->timer = 0;
+
+ return last_draw ? G_SOURCE_REMOVE : G_SOURCE_CONTINUE;
+}
+
+static GdkRectangle
+unity_of_rects (GdkRectangle a,
+ GdkRectangle b)
+{
+ GdkRectangle u = b;
+
+ if (a.x < u.x)
+ {
+ u.width += u.x - a.x;
+ u.x = a.x;
+ }
+
+ if (a.y < u.y)
+ {
+ u.height += (u.y - a.y);
+ u.y = a.y;
+ }
+
+ if (a.x + a.width > u.x + u.width)
+ u.width += (a.x + a.width) - (u.x + u.width);
+
+ if (a.y + a.height > u.y + u.height)
+ u.height += (a.y + a.height) - (u.y + u.height);
+
+#if defined(MORE_AEROSNAP_DEBUGGING)
+ GDK_NOTE (MISC, g_print ("Unified 2 rects into %d x %d @ %d : %d\n",
+ u.width, u.height, u.x, u.y));
+#endif
+
+ return u;
+}
+
+static void
+start_indicator_drawing (GdkW32DragMoveResizeContext *context,
+ GdkRectangle from,
+ GdkRectangle to,
+ guint scale)
+{
+ GdkRectangle to_adjusted, from_adjusted, from_or_to;
+ gint64 indicator_animation_tick = AEROSNAP_INDICATOR_ANIMATION_TICK;
+
+ GDK_NOTE (MISC, g_print ("Start drawing snap indicator %d x %d @ %d : %d -> %d x %d @ %d : %d\n",
+ from.width * scale, from.height * scale, from.x, from.y, to.width * scale, to.height * scale, to.x, to.y));
+
+ if (GDK_SURFACE_DESTROYED (context->window))
+ return;
+
+ if (!ensure_snap_indicator_exists (context))
+ return;
+
+ from_or_to = unity_of_rects (from, to);
+
+ if (!ensure_snap_indicator_surface (context, from_or_to.width, from_or_to.height, scale))
+ return;
+
+ to_adjusted = to;
+ adjust_indicator_rectangle (&to_adjusted, TRUE);
+
+ from_adjusted = from;
+ adjust_indicator_rectangle (&from_adjusted, TRUE);
+
+ context->draw_timestamp = 0;
+ context->indicator_start = from_adjusted;
+ context->indicator_target = to_adjusted;
+ context->indicator_window_rect = from_or_to;
+ context->indicator_start_time = g_get_monotonic_time ();
+
+ if (context->timer)
+ {
+ g_source_remove (context->timer);
+ context->timer = 0;
+ }
+
+ context->timer = g_timeout_add_full (G_PRIORITY_DEFAULT,
+ indicator_animation_tick,
+ redraw_indicator,
+ context,
+ NULL);
+}
+
+static void
+update_fullup_indicator (GdkSurface *window,
+ GdkW32DragMoveResizeContext *context)
+{
+ SHORT maxysize;
+ GdkRectangle from, to;
+ GdkRectangle to_adjusted, from_adjusted, from_or_to;
+ GdkSurfaceImplWin32 *impl;
+
+ GDK_NOTE (MISC, g_print ("Update fullup indicator\n"));
+
+ if (GDK_SURFACE_DESTROYED (context->window))
+ return;
+
+ if (context->shape_indicator == NULL)
+ return;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN);
+ gdk_surface_get_position (window, &to.x, &to.y);
+ to.width = gdk_surface_get_width (window);
+ to.height = gdk_surface_get_height (window);
+
+ to.y = 0;
+ to.height = maxysize;
+ from = context->indicator_target;
+
+ if (context->timer == 0)
+ {
+ from_adjusted = from;
+ adjust_indicator_rectangle (&from_adjusted, FALSE);
+
+ GDK_NOTE (MISC, g_print ("Restart fullup animation from %d x %d @ %d : %d -> %d x %d @ %d x %d\n",
+ context->indicator_target.width, context->indicator_target.height,
+ context->indicator_target.x, context->indicator_target.y,
+ to.width, to.height, to.x, to.y));
+ start_indicator_drawing (context, from_adjusted, to, impl->window_scale);
+
+ return;
+ }
+
+ from_or_to = unity_of_rects (from, to);
+
+ to_adjusted = to;
+ adjust_indicator_rectangle (&to_adjusted, TRUE);
+
+ GDK_NOTE (MISC, g_print ("Retarget fullup animation %d x %d @ %d : %d -> %d x %d @ %d x %d\n",
+ context->indicator_target.width, context->indicator_target.height,
+ context->indicator_target.x, context->indicator_target.y,
+ to_adjusted.width, to_adjusted.height, to_adjusted.x, to_adjusted.y));
+
+ context->indicator_target = to_adjusted;
+ context->indicator_window_rect = from_or_to;
+
+ ensure_snap_indicator_surface (context, from_or_to.width, from_or_to.height, impl->window_scale);
+}
+
+static void
+start_indicator (GdkSurface *window,
+ GdkW32DragMoveResizeContext *context,
+ gint x,
+ gint y,
+ GdkWin32AeroSnapState state)
+{
+ GdkMonitor *monitor;
+ GdkRectangle workarea;
+ SHORT maxysize;
+ GdkRectangle start_size, end_size;
+ GdkDisplay *display;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ display = gdk_surface_get_display (window);
+ monitor = gdk_display_get_monitor_at_point (display, x, y);
+ gdk_monitor_get_workarea (monitor, &workarea);
+
+ maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN) / impl->window_scale;
+ gdk_surface_get_position (window, &start_size.x, &start_size.y);
+ start_size.width = gdk_surface_get_width (window);
+ start_size.height = gdk_surface_get_height (window);
+
+ end_size = start_size;
+
+ switch (state)
+ {
+ case GDK_WIN32_AEROSNAP_STATE_UNDETERMINED:
+ return;
+ case GDK_WIN32_AEROSNAP_STATE_MAXIMIZE:
+ end_size.x = workarea.x;
+ end_size.y = workarea.y;
+ end_size.width = workarea.width;
+ end_size.height = workarea.height;
+ break;
+ case GDK_WIN32_AEROSNAP_STATE_HALFLEFT:
+ end_size.x = workarea.x;
+ end_size.y = workarea.y;
+ end_size.width = workarea.width / 2;
+ end_size.height = workarea.height;
+ break;
+ case GDK_WIN32_AEROSNAP_STATE_HALFRIGHT:
+ end_size.x = (workarea.x + workarea.width / 2);
+ end_size.y = workarea.y;
+ end_size.width = workarea.width / 2;
+ end_size.height = workarea.height;
+ break;
+ case GDK_WIN32_AEROSNAP_STATE_FULLUP:
+ end_size.y = 0;
+ end_size.height = maxysize;
+ break;
+ }
+
+ start_indicator_drawing (context, start_size, end_size, impl->window_scale);
+}
+
+static void
+stop_indicator (GdkSurface *window,
+ GdkW32DragMoveResizeContext *context)
+{
+ GDK_NOTE (MISC, g_print ("Stop drawing snap indicator\n"));
+
+ if (context->timer)
+ {
+ g_source_remove (context->timer);
+ context->timer = 0;
+ }
+
+ API_CALL (SetWindowPos, (context->shape_indicator,
+ SWP_NOZORDER_SPECIFIED,
+ 0, 0, 0, 0,
+ SWP_NOZORDER | SWP_NOMOVE |
+ SWP_NOSIZE | SWP_NOREDRAW | SWP_HIDEWINDOW | SWP_NOACTIVATE));
+}
+
+static gint
+point_in_aerosnap_region (gint x,
+ gint y,
+ AeroSnapEdgeRegion *region)
+{
+ gint edge, trigger;
+
+ edge = (x >= region->edge.x &&
+ y >= region->edge.y &&
+ x <= region->edge.x + region->edge.width &&
+ y <= region->edge.y + region->edge.height) ? 1 : 0;
+ trigger = (x >= region->trigger.x &&
+ y >= region->trigger.y &&
+ x <= region->trigger.x + region->trigger.width &&
+ y <= region->trigger.y + region->trigger.height) ? 1 : 0;
+ return edge + trigger;
+}
+
+static void
+handle_aerosnap_move_resize (GdkSurface *window,
+ GdkW32DragMoveResizeContext *context,
+ gint x,
+ gint y)
+{
+ gint i;
+ AeroSnapEdgeRegion *reg;
+ gint maximize = 0;
+ gint halfleft = 0;
+ gint halfright = 0;
+ gint fullup = 0;
+ gboolean fullup_edge = FALSE;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ if (context->op == GDK_WIN32_DRAGOP_RESIZE)
+ switch (context->edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ case GDK_SURFACE_EDGE_WEST:
+ case GDK_SURFACE_EDGE_EAST:
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ break;
+ case GDK_SURFACE_EDGE_SOUTH:
+ case GDK_SURFACE_EDGE_NORTH:
+ fullup_edge = TRUE;
+ break;
+ }
+
+ for (i = 0; i < context->maximize_regions->len && maximize == 0; i++)
+ {
+ reg = &g_array_index (context->maximize_regions, AeroSnapEdgeRegion, i);
+ maximize = point_in_aerosnap_region (x, y, reg);
+ }
+
+ for (i = 0; i < context->halfleft_regions->len && halfleft == 0; i++)
+ {
+ reg = &g_array_index (context->halfleft_regions, AeroSnapEdgeRegion, i);
+ halfleft = point_in_aerosnap_region (x, y, reg);
+ }
+
+ for (i = 0; i < context->halfright_regions->len && halfright == 0; i++)
+ {
+ reg = &g_array_index (context->halfright_regions, AeroSnapEdgeRegion, i);
+ halfright = point_in_aerosnap_region (x, y, reg);
+ }
+
+ for (i = 0; i < context->fullup_regions->len && fullup == 0; i++)
+ {
+ reg = &g_array_index (context->fullup_regions, AeroSnapEdgeRegion, i);
+ fullup = point_in_aerosnap_region (x, y, reg);
+ }
+
+#if defined(MORE_AEROSNAP_DEBUGGING)
+ GDK_NOTE (MISC, g_print ("AeroSnap: point %d : %d - max: %d, left %d, right %d, up %d\n",
+ x, y, maximize, halfleft, halfright, fullup));
+#endif
+
+ if (!context->revealed)
+ {
+ if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize == 2)
+ {
+ context->revealed = TRUE;
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_MAXIMIZE;
+ start_indicator (window, context, x, y, context->current_snap);
+ }
+ else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft == 2)
+ {
+ context->revealed = TRUE;
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
+ start_indicator (window, context, x, y, context->current_snap);
+ }
+ else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright == 2)
+ {
+ context->revealed = TRUE;
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
+ start_indicator (window, context, x, y, context->current_snap);
+ }
+ else if (context->op == GDK_WIN32_DRAGOP_RESIZE && fullup == 2 && fullup_edge)
+ {
+ context->revealed = TRUE;
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_FULLUP;
+ start_indicator (window, context, x, y, context->current_snap);
+ }
+
+ return;
+ }
+
+ switch (context->current_snap)
+ {
+ case GDK_WIN32_AEROSNAP_STATE_UNDETERMINED:
+ if (context->op == GDK_WIN32_DRAGOP_RESIZE && fullup > 0)
+ {
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_FULLUP;
+ start_indicator (window, context, x, y, context->current_snap);
+ }
+ break;
+ case GDK_WIN32_AEROSNAP_STATE_MAXIMIZE:
+ if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize > 0)
+ break;
+ if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft > 0)
+ {
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
+ start_indicator (window, context, x, y, context->current_snap);
+ }
+ else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright > 0)
+ {
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
+ start_indicator (window, context, x, y, context->current_snap);
+ }
+ else
+ {
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
+ stop_indicator (window, context);
+ context->revealed = FALSE;
+ }
+ break;
+ case GDK_WIN32_AEROSNAP_STATE_HALFLEFT:
+ if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft > 0)
+ break;
+ if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize > 0)
+ {
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_MAXIMIZE;
+ start_indicator (window, context, x, y, context->current_snap);
+ }
+ else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright > 0)
+ {
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
+ start_indicator (window, context, x, y, context->current_snap);
+ }
+ else
+ {
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
+ stop_indicator (window, context);
+ context->revealed = FALSE;
+ }
+ break;
+ case GDK_WIN32_AEROSNAP_STATE_HALFRIGHT:
+ if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright > 0)
+ break;
+ if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize > 0)
+ {
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_MAXIMIZE;
+ start_indicator (window, context, x, y, context->current_snap);
+ }
+ else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft > 0)
+ {
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
+ start_indicator (window, context, x, y, context->current_snap);
+ }
+ else
+ {
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
+ stop_indicator (window, context);
+ context->revealed = FALSE;
+ }
+ break;
+ case GDK_WIN32_AEROSNAP_STATE_FULLUP:
+ if (context->op == GDK_WIN32_DRAGOP_RESIZE && fullup > 0 && fullup_edge)
+ {
+ update_fullup_indicator (window, context);
+ break;
+ }
+
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
+ stop_indicator (window, context);
+ break;
+ }
+}
+
+
+static const gchar *
+get_cursor_name_from_op (GdkW32WindowDragOp op,
+ GdkSurfaceEdge edge)
+{
+ switch (op)
+ {
+ case GDK_WIN32_DRAGOP_MOVE:
+ return "move";
+ case GDK_WIN32_DRAGOP_RESIZE:
+ switch (edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ return "nw-resize";
+ case GDK_SURFACE_EDGE_NORTH:
+ return "n-resize";
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ return "ne-resize";
+ case GDK_SURFACE_EDGE_WEST:
+ return "w-resize";
+ case GDK_SURFACE_EDGE_EAST:
+ return "e-resize";
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ return "sw-resize";
+ case GDK_SURFACE_EDGE_SOUTH:
+ return "s-resize";
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ return "se-resize";
+ }
+ /* default: warn about unhandled enum values,
+ * fallthrough to GDK_WIN32_DRAGOP_NONE case
+ */
+ case GDK_WIN32_DRAGOP_COUNT:
+ g_assert_not_reached ();
+ case GDK_WIN32_DRAGOP_NONE:
+ return "default";
+ /* default: warn about unhandled enum values */
+ }
+
+ g_assert_not_reached ();
+
+ return NULL;
+}
+
+static gboolean
+point_in_window (GdkSurface *window,
+ gdouble x,
+ gdouble y)
+{
+ return x >= 0 && x < window->width &&
+ y >= 0 && y < window->height &&
+ (window->shape == NULL ||
+ cairo_region_contains_point (window->shape, x, y)) &&
+ (window->input_shape == NULL ||
+ cairo_region_contains_point (window->input_shape, x, y));
+}
+
+static GdkSurface *
+child_window_at_coordinates (GdkSurface *window,
+ gint root_x,
+ gint root_y)
+{
+ gint x, y;
+ GList *l;
+ GList *children;
+
+ children = gdk_surface_peek_children (window);
+ gdk_surface_get_root_origin (window, &x, &y);
+ x = root_x - x;
+ y = root_y - y;
+
+ for (l = children; l; l = g_list_next (l))
+ {
+ GdkSurface *child = GDK_SURFACE (l->data);
+
+ if (point_in_window (child, x, y))
+ return child;
+ }
+
+ return window;
+}
+
+static void
+setup_drag_move_resize_context (GdkSurface *window,
+ GdkW32DragMoveResizeContext *context,
+ GdkW32WindowDragOp op,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ RECT rect;
+ const gchar *cursor_name;
+ GdkSurface *pointer_window;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ GdkDisplay *display = gdk_device_get_display (device);
+ gboolean maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
+
+ /* Before we drag, we need to undo any maximization or snapping.
+ * AeroSnap behaviour:
+ * If snapped halfleft/halfright:
+ * horizontal resize:
+ * resize
+ * don't unsnap
+ * keep stashed unsnapped size intact
+ * vertical resize:
+ * resize
+ * unsnap to new size (merge cached unsnapped state with current
+ * snapped state in such a way that the gripped edge
+ * does not move)
+ * diagonal resize:
+ * difficult to test (first move is usually either purely
+ * horizontal or purely vertical, in which
+ * case the above behaviour applies)
+ * If snapped up:
+ * horizontal resize:
+ * resize
+ * don't unsnap
+ * apply new width and x position to unsnapped cache,
+ * so that unsnapped window only regains its height
+ * and y position, but inherits x and width from
+ * the fullup snapped state
+ * vertical resize:
+ * unsnap to new size (merge cached unsnapped state with current
+ * snapped state in such a way that the gripped edge
+ * does not move)
+ *
+ * This implementation behaviour:
+ * If snapped halfleft/halfright/fullup:
+ * any resize:
+ * unsnap to current size, discard cached pre-snap state
+ *
+ * TODO: make this implementation behave as AeroSnap on resizes?
+ * There's also the case where
+ * a halfleft/halfright window isn't unsnapped when it's
+ * being moved horizontally, but it's more difficult to implement.
+ */
+ if (op == GDK_WIN32_DRAGOP_RESIZE &&
+ (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT ||
+ impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT ||
+ impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP))
+ {
+ discard_snapinfo (window);
+ }
+ else if (maximized ||
+ (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT ||
+ impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT ||
+ impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP))
+ {
+ GdkMonitor *monitor;
+ gint wx, wy, wwidth, wheight;
+ gint swx, swy, swwidth, swheight;
+ gboolean pointer_outside_of_window;
+ gint offsetx, offsety;
+ gboolean left_half;
+ GdkDisplay *display;
+
+ display = gdk_surface_get_display (window);
+ monitor = gdk_display_get_monitor_at_window (display, window);
+ gdk_surface_get_geometry (window, &wx, &wy, &wwidth, &wheight);
+
+ swx = wx;
+ swy = wy;
+ swwidth = wwidth;
+ swheight = wheight;
+
+ /* Subtract window shadow. We don't want pointer to go outside of
+ * the visible window during drag-move. For drag-resize it's OK.
+ * Don't take shadow into account if the window is maximized -
+ * maximized windows don't have shadows.
+ */
+ if (op == GDK_WIN32_DRAGOP_MOVE && !maximized)
+ {
+ swx += impl->margins.left / impl->window_scale;
+ swy += impl->margins.top / impl->window_scale;
+ swwidth -= impl->margins_x;
+ swheight -= impl->margins_y;
+ }
+
+ pointer_outside_of_window = root_x < swx || root_x > swx + swwidth ||
+ root_y < swy || root_y > swy + swheight;
+ /* Calculate the offset of the pointer relative to the window */
+ offsetx = root_x - swx;
+ offsety = root_y - swy;
+
+ /* Figure out in which half of the window the pointer is.
+ * The code currently only concerns itself with horizontal
+ * dimension (left/right halves).
+ * There's no upper/lower half, because usually window
+ * is dragged by its upper half anyway. If that changes, adjust
+ * accordingly.
+ */
+ left_half = (offsetx < swwidth / 2);
+
+ /* Inverse the offset for it to be from the right edge */
+ if (!left_half)
+ offsetx = swwidth - offsetx;
+
+ GDK_NOTE (MISC, g_print ("Pointer at %d : %d, this is %d : %d relative to the window's %s\n",
+ root_x, root_y, offsetx, offsety,
+ left_half ? "left half" : "right half"));
+
+ /* Move window in such a way that on unmaximization/unsnapping the pointer
+ * is still pointing at the appropriate half of the window,
+ * with the same offset from the left or right edge. If the new
+ * window size is too small, and adding that offset puts the pointer
+ * into the other half or even beyond, move the pointer to the middle.
+ */
+ if (!pointer_outside_of_window && maximized)
+ {
+ WINDOWPLACEMENT placement;
+ gint unmax_width, unmax_height;
+ gint shadow_unmax_width, shadow_unmax_height;
+
+ placement.length = sizeof (placement);
+ API_CALL (GetWindowPlacement, (GDK_SURFACE_HWND (window), &placement));
+
+ GDK_NOTE (MISC, g_print ("W32 WM unmaximized window placement is %ld x %ld @ %ld : %ld\n",
+ placement.rcNormalPosition.right - placement.rcNormalPosition.left,
+ placement.rcNormalPosition.bottom - placement.rcNormalPosition.top,
+ placement.rcNormalPosition.left + _gdk_offset_x * impl->window_scale,
+ placement.rcNormalPosition.top + _gdk_offset_y * impl->window_scale));
+
+ unmax_width = placement.rcNormalPosition.right - placement.rcNormalPosition.left;
+ unmax_height = placement.rcNormalPosition.bottom - placement.rcNormalPosition.top;
+
+ shadow_unmax_width = unmax_width - impl->margins_x * impl->window_scale;
+ shadow_unmax_height = unmax_height - impl->margins_y * impl->window_scale;
+
+ if (offsetx * impl->window_scale < (shadow_unmax_width / 2) &&
+ offsety * impl->window_scale < (shadow_unmax_height / 2))
+ {
+ placement.rcNormalPosition.top = (root_y - offsety + impl->margins.top - _gdk_offset_y) * impl->window_scale;
+ placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + unmax_height;
+
+ if (left_half)
+ {
+ placement.rcNormalPosition.left = (root_x - offsetx + impl->margins.left - _gdk_offset_x) * impl->window_scale;
+ placement.rcNormalPosition.right = placement.rcNormalPosition.left + unmax_width;
+ }
+ else
+ {
+ placement.rcNormalPosition.right = (root_x + offsetx + impl->margins.right - _gdk_offset_x) * impl->window_scale;
+ placement.rcNormalPosition.left = placement.rcNormalPosition.right - unmax_width;
+ }
+ }
+ else
+ {
+ placement.rcNormalPosition.left = (root_x * impl->window_scale) -
+ (unmax_width / 2) -
+ (_gdk_offset_x * impl->window_scale);
+
+ if (offsety * impl->window_scale < shadow_unmax_height / 2)
+ placement.rcNormalPosition.top = (root_y - offsety + impl->margins.top - _gdk_offset_y) * impl->window_scale;
+ else
+ placement.rcNormalPosition.top = (root_y * impl->window_scale) -
+ (unmax_height / 2) -
+ (_gdk_offset_y * impl->window_scale);
+
+ placement.rcNormalPosition.right = placement.rcNormalPosition.left + unmax_width;
+ placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + unmax_height;
+ }
+
+ GDK_NOTE (MISC, g_print ("Unmaximized window will be at %ld : %ld\n",
+ placement.rcNormalPosition.left + _gdk_offset_x * impl->window_scale,
+ placement.rcNormalPosition.top + _gdk_offset_y * impl->window_scale));
+
+ API_CALL (SetWindowPlacement, (GDK_SURFACE_HWND (window), &placement));
+ }
+ else if (!pointer_outside_of_window && impl->snap_stash_int)
+ {
+ GdkRectangle new_pos;
+ GdkRectangle snew_pos;
+
+ new_pos.width = impl->snap_stash_int->width;
+ new_pos.height = impl->snap_stash_int->height;
+ snew_pos = new_pos;
+
+ if (op == GDK_WIN32_DRAGOP_MOVE)
+ {
+ snew_pos.width -= impl->margins_x;
+ snew_pos.height -= impl->margins_y;
+ }
+
+ if (offsetx < snew_pos.width / 2 && offsety < snew_pos.height / 2)
+ {
+ new_pos.y = root_y - offsety + impl->margins.top / impl->window_scale;
+
+ if (left_half)
+ new_pos.x = root_x - offsetx + impl->margins.left / impl->window_scale;
+ else
+ new_pos.x = root_x + offsetx + impl->margins.left / impl->window_scale - new_pos.width;
+ }
+ else
+ {
+ new_pos.x = root_x - new_pos.width / 2;
+ new_pos.y = root_y - new_pos.height / 2;
+ }
+
+ GDK_NOTE (MISC, g_print ("Unsnapped window to %d : %d\n",
+ new_pos.x, new_pos.y));
+ discard_snapinfo (window);
+ gdk_surface_move_resize (window, new_pos.x, new_pos.y,
+ new_pos.width, new_pos.height);
+ }
+
+
+ if (maximized)
+ gdk_surface_unmaximize (window);
+ else
+ unsnap (window, monitor);
+
+ if (pointer_outside_of_window)
+ {
+ /* Pointer outside of the window, move pointer into window */
+ GDK_NOTE (MISC, g_print ("Pointer at %d : %d is outside of %d x %d @ %d : %d, move it to %d : %d\n",
+ root_x, root_y, wwidth, wheight, wx, wy, wx + wwidth / 2, wy + wheight / 2));
+ root_x = wx + wwidth / 2;
+ /* This is Gnome behaviour. Windows WM would put the pointer
+ * in the middle of the titlebar, but GDK doesn't know where
+ * the titlebar is, if any.
+ */
+ root_y = wy + wheight / 2;
+ gdk_device_warp (device, root_x, root_y);
+ }
+ }
+
+ _gdk_win32_get_window_rect (window, &rect);
+
+ cursor_name = get_cursor_name_from_op (op, edge);
+
+ context->cursor = gdk_cursor_new_from_name (cursor_name, NULL);
+
+ pointer_window = child_window_at_coordinates (window, root_x, root_y);
+
+ /* Note: This triggers a WM_CAPTURECHANGED, which will trigger
+ * gdk_win32_surface_end_move_resize_drag(), which will end
+ * our op before it even begins, but only if context->op is not NONE.
+ * This is why we first do the grab, *then* set the op.
+ */
+ gdk_device_grab (device, pointer_window,
+ GDK_OWNERSHIP_NONE, FALSE,
+ GDK_ALL_EVENTS_MASK,
+ context->cursor,
+ timestamp);
+
+ context->window = g_object_ref (window);
+ context->op = op;
+ context->edge = edge;
+ context->device = device;
+ context->button = button;
+ context->start_root_x = root_x;
+ context->start_root_y = root_y;
+ context->timestamp = timestamp;
+ context->start_rect = rect;
+
+ context->shape_indicator = NULL;
+ context->revealed = FALSE;
+ context->halfleft_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
+ context->halfright_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
+ context->maximize_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
+ context->fullup_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
+
+ calculate_aerosnap_regions (context);
+
+ GDK_NOTE (EVENTS,
+ g_print ("begin drag moveresize: window %p, toplevel %p, "
+ "op %u, edge %d, device %p, "
+ "button %d, coord %d:%d, time %u\n",
+ pointer_window, gdk_surface_get_toplevel (window),
+ context->op, context->edge, context->device,
+ context->button, context->start_root_x,
+ context->start_root_y, context->timestamp));
+}
+
+void
+gdk_win32_surface_end_move_resize_drag (GdkSurface *window)
+{
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ GdkW32DragMoveResizeContext *context = &impl->drag_move_resize_context;
+
+ context->op = GDK_WIN32_DRAGOP_NONE;
+
+ gdk_device_ungrab (context->device, GDK_CURRENT_TIME);
+
+ g_clear_object (&context->cursor);
+
+ context->revealed = FALSE;
+
+ if (context->timer)
+ {
+ g_source_remove (context->timer);
+ context->timer = 0;
+ }
+
+ g_clear_object (&context->window);
+
+ if (context->indicator_surface)
+ {
+ cairo_surface_destroy (context->indicator_surface);
+ context->indicator_surface = NULL;
+ }
+
+ if (context->shape_indicator)
+ {
+ stop_indicator (window, context);
+ DestroyWindow (context->shape_indicator);
+ context->shape_indicator = NULL;
+ }
+
+ g_clear_pointer (&context->halfleft_regions, g_array_unref);
+ g_clear_pointer (&context->halfright_regions, g_array_unref);
+ g_clear_pointer (&context->maximize_regions, g_array_unref);
+ g_clear_pointer (&context->fullup_regions, g_array_unref);
+
+ GDK_NOTE (EVENTS,
+ g_print ("end drag moveresize: window %p, toplevel %p,"
+ "op %u, edge %d, device %p, "
+ "button %d, coord %d:%d, time %u\n",
+ window, gdk_surface_get_toplevel (window),
+ context->op, context->edge, context->device,
+ context->button, context->start_root_x,
+ context->start_root_y, context->timestamp));
+
+ if (context->current_snap != GDK_WIN32_AEROSNAP_STATE_UNDETERMINED)
+ apply_snap (window, context->current_snap);
+
+ context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
+}
+
+static void
+gdk_win32_get_window_size_and_position_from_client_rect (GdkSurface *window,
+ RECT *window_rect,
+ SIZE *window_size,
+ POINT *window_position)
+{
+ GdkSurfaceImplWin32 *impl;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ /* Turn client area into window area */
+ _gdk_win32_adjust_client_rect (window, window_rect);
+
+ /* Convert GDK screen coordinates to W32 desktop coordinates */
+ window_rect->left -= _gdk_offset_x * impl->window_scale;
+ window_rect->right -= _gdk_offset_x * impl->window_scale;
+ window_rect->top -= _gdk_offset_y * impl->window_scale;
+ window_rect->bottom -= _gdk_offset_y * impl->window_scale;
+
+ window_position->x = window_rect->left;
+ window_position->y = window_rect->top;
+ window_size->cx = window_rect->right - window_rect->left;
+ window_size->cy = window_rect->bottom - window_rect->top;
+}
+
+static void
+gdk_win32_update_layered_window_from_cache (GdkSurface *window,
+ RECT *client_rect)
+{
+ POINT window_position;
+ SIZE window_size;
+ BLENDFUNCTION blender;
+ HDC hdc;
+ SIZE *window_size_ptr;
+ POINT source_point = { 0, 0 };
+ POINT *source_point_ptr;
+ GdkSurfaceImplWin32 *impl;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ gdk_win32_get_window_size_and_position_from_client_rect (window,
+ client_rect,
+ &window_size,
+ &window_position);
+
+ blender.BlendOp = AC_SRC_OVER;
+ blender.BlendFlags = 0;
+ blender.AlphaFormat = AC_SRC_ALPHA;
+ blender.SourceConstantAlpha = impl->layered_opacity * 255;
+
+ /* Size didn't change, so move immediately, no need to wait for redraw */
+ /* Strictly speaking, we don't need to supply hdc, source_point and
+ * window_size here. However, without these arguments
+ * the window moves but does not update its contents on Windows 7 when
+ * desktop composition is off. This forces us to provide hdc and
+ * source_point. window_size is here to avoid the function
+ * inexplicably failing with error 317.
+ */
+ if (gdk_display_is_composited (gdk_surface_get_display (window)))
+ {
+ hdc = NULL;
+ window_size_ptr = NULL;
+ source_point_ptr = NULL;
+ }
+ else
+ {
+ hdc = cairo_win32_surface_get_dc (impl->cache_surface);
+ window_size_ptr = &window_size;
+ source_point_ptr = &source_point;
+ }
+
+ API_CALL (UpdateLayeredWindow, (GDK_SURFACE_HWND (window), NULL,
+ &window_position, window_size_ptr,
+ hdc, source_point_ptr,
+ 0, &blender, ULW_ALPHA));
+}
+
+void
+gdk_win32_surface_do_move_resize_drag (GdkSurface *window,
+ gint x,
+ gint y)
+{
+ RECT rect;
+ RECT new_rect;
+ gint diffy, diffx;
+ MINMAXINFO mmi;
+ GdkSurfaceImplWin32 *impl;
+ GdkW32DragMoveResizeContext *context;
+ gint width;
+ gint height;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+ context = &impl->drag_move_resize_context;
+
+ if (!_gdk_win32_get_window_rect (window, &rect))
+ return;
+
+ new_rect = context->start_rect;
+ diffx = (x - context->start_root_x) * impl->window_scale;
+ diffy = (y - context->start_root_y) * impl->window_scale;
+
+ switch (context->op)
+ {
+ case GDK_WIN32_DRAGOP_RESIZE:
+
+ switch (context->edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ new_rect.left += diffx;
+ new_rect.top += diffy;
+ break;
+
+ case GDK_SURFACE_EDGE_NORTH:
+ new_rect.top += diffy;
+ break;
+
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ new_rect.right += diffx;
+ new_rect.top += diffy;
+ break;
+
+ case GDK_SURFACE_EDGE_WEST:
+ new_rect.left += diffx;
+ break;
+
+ case GDK_SURFACE_EDGE_EAST:
+ new_rect.right += diffx;
+ break;
+
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ new_rect.left += diffx;
+ new_rect.bottom += diffy;
+ break;
+
+ case GDK_SURFACE_EDGE_SOUTH:
+ new_rect.bottom += diffy;
+ break;
+
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ default:
+ new_rect.right += diffx;
+ new_rect.bottom += diffy;
+ break;
+ }
+
+ /* When handling WM_GETMINMAXINFO, mmi is already populated
+ * by W32 WM and we apply our stuff on top of that.
+ * Here it isn't, so we should at least clear it.
+ */
+ memset (&mmi, 0, sizeof (mmi));
+
+ if (!_gdk_win32_surface_fill_min_max_info (window, &mmi))
+ break;
+
+ width = new_rect.right - new_rect.left;
+ height = new_rect.bottom - new_rect.top;
+
+ if (width > mmi.ptMaxTrackSize.x)
+ {
+ switch (context->edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ case GDK_SURFACE_EDGE_WEST:
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ new_rect.left = new_rect.right - mmi.ptMaxTrackSize.x;
+ break;
+
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ case GDK_SURFACE_EDGE_EAST:
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ default:
+ new_rect.right = new_rect.left + mmi.ptMaxTrackSize.x;
+ break;
+ }
+ }
+ else if (width < mmi.ptMinTrackSize.x)
+ {
+ switch (context->edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ case GDK_SURFACE_EDGE_WEST:
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ new_rect.left = new_rect.right - mmi.ptMinTrackSize.x;
+ break;
+
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ case GDK_SURFACE_EDGE_EAST:
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ default:
+ new_rect.right = new_rect.left + mmi.ptMinTrackSize.x;
+ break;
+ }
+ }
+
+ if (height > mmi.ptMaxTrackSize.y)
+ {
+ switch (context->edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ case GDK_SURFACE_EDGE_NORTH:
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ new_rect.top = new_rect.bottom - mmi.ptMaxTrackSize.y;
+
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ case GDK_SURFACE_EDGE_SOUTH:
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ default:
+ new_rect.bottom = new_rect.top + mmi.ptMaxTrackSize.y;
+ break;
+ }
+ }
+ else if (height < mmi.ptMinTrackSize.y)
+ {
+ switch (context->edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ case GDK_SURFACE_EDGE_NORTH:
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ new_rect.top = new_rect.bottom - mmi.ptMinTrackSize.y;
+
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ case GDK_SURFACE_EDGE_SOUTH:
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ default:
+ new_rect.bottom = new_rect.top + mmi.ptMinTrackSize.y;
+ break;
+ }
+ }
+
+ break;
+ case GDK_WIN32_DRAGOP_MOVE:
+ new_rect.left += diffx;
+ new_rect.top += diffy;
+ new_rect.right += diffx;
+ new_rect.bottom += diffy;
+ break;
+ default:
+ break;
+ }
+
+ if (context->op == GDK_WIN32_DRAGOP_RESIZE &&
+ (rect.left != new_rect.left ||
+ rect.right != new_rect.right ||
+ rect.top != new_rect.top ||
+ rect.bottom != new_rect.bottom))
+ {
+ context->native_move_resize_pending = TRUE;
+ _gdk_win32_do_emit_configure_event (window, new_rect);
+ }
+ else if (context->op == GDK_WIN32_DRAGOP_MOVE &&
+ (rect.left != new_rect.left ||
+ rect.top != new_rect.top))
+ {
+ context->native_move_resize_pending = FALSE;
+
+ _gdk_win32_do_emit_configure_event (window, new_rect);
+
+ if (impl->layered)
+ {
+ gdk_win32_update_layered_window_from_cache (window, &new_rect);
+ }
+ else
+ {
+ SIZE window_size;
+ POINT window_position;
+
+ gdk_win32_get_window_size_and_position_from_client_rect (window,
+ &new_rect,
+ &window_size,
+ &window_position);
+
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ SWP_NOZORDER_SPECIFIED,
+ window_position.x, window_position.y,
+ 0, 0,
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE));
+ }
+ }
+
+ if (context->op == GDK_WIN32_DRAGOP_RESIZE ||
+ context->op == GDK_WIN32_DRAGOP_MOVE)
+ handle_aerosnap_move_resize (window, context, x, y);
+}
+
+static void
+gdk_win32_surface_begin_resize_drag (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GdkSurfaceImplWin32 *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ IsIconic (GDK_SURFACE_HWND (window)))
+ return;
+
+ /* Tell Windows to start interactively resizing the window by pretending that
+ * the left pointer button was clicked in the suitable edge or corner. This
+ * will only work if the button is down when this function is called, and
+ * will only work with button 1 (left), since Windows only allows window
+ * dragging using the left mouse button.
+ */
+
+ if (button != 1)
+ return;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
+ gdk_win32_surface_end_move_resize_drag (window);
+
+ setup_drag_move_resize_context (window, &impl->drag_move_resize_context,
+ GDK_WIN32_DRAGOP_RESIZE, edge, device,
+ button, root_x, root_y, timestamp);
+}
+
+static void
+gdk_win32_surface_begin_move_drag (GdkSurface *window,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GdkSurfaceImplWin32 *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ IsIconic (GDK_SURFACE_HWND (window)))
+ return;
+
+ /* Tell Windows to start interactively moving the window by pretending that
+ * the left pointer button was clicked in the titlebar. This will only work
+ * if the button is down when this function is called, and will only work
+ * with button 1 (left), since Windows only allows window dragging using the
+ * left mouse button.
+ */
+ if (button != 1)
+ return;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
+ gdk_win32_surface_end_move_resize_drag (window);
+
+ setup_drag_move_resize_context (window, &impl->drag_move_resize_context,
+ GDK_WIN32_DRAGOP_MOVE, GDK_SURFACE_EDGE_NORTH_WEST,
+ device, button, root_x, root_y, timestamp);
+}
+
+
+/*
+ * Setting window states
+ */
+static void
+gdk_win32_surface_iconify (GdkSurface *window)
+{
+ HWND old_active_window;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_iconify: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ _gdk_win32_surface_state_to_string (window->state)));
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ old_active_window = GetActiveWindow ();
+ GtkShowWindow (window, SW_MINIMIZE);
+ if (old_active_window != GDK_SURFACE_HWND (window))
+ SetActiveWindow (old_active_window);
+ }
+ else
+ {
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_SURFACE_STATE_ICONIFIED);
+ }
+}
+
+static void
+gdk_win32_surface_deiconify (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_deiconify: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ _gdk_win32_surface_state_to_string (window->state)));
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ show_window_internal (window, GDK_SURFACE_IS_MAPPED (window), TRUE);
+ }
+ else
+ {
+ gdk_synthesize_window_state (window,
+ GDK_SURFACE_STATE_ICONIFIED,
+ 0);
+ }
+}
+
+static void
+gdk_win32_surface_stick (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ /* FIXME: Do something? */
+}
+
+static void
+gdk_win32_surface_unstick (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ /* FIXME: Do something? */
+}
+
+static void
+gdk_win32_surface_maximize (GdkSurface *window)
+{
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_maximize: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ _gdk_win32_surface_state_to_string (window->state)));
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ GtkShowWindow (window, SW_MAXIMIZE);
+ else
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_SURFACE_STATE_MAXIMIZED);
+}
+
+static void
+gdk_win32_surface_unmaximize (GdkSurface *window)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_unmaximize: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ _gdk_win32_surface_state_to_string (window->state)));
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ GtkShowWindow (window, SW_RESTORE);
+ else
+ gdk_synthesize_window_state (window,
+ GDK_SURFACE_STATE_MAXIMIZED,
+ 0);
+}
+
+static void
+gdk_win32_surface_fullscreen (GdkSurface *window)
+{
+ gint x, y, width, height;
+ FullscreenInfo *fi;
+ HMONITOR monitor;
+ MONITORINFO mi;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ fi = g_new (FullscreenInfo, 1);
+
+ if (!GetWindowRect (GDK_SURFACE_HWND (window), &(fi->r)))
+ g_free (fi);
+ else
+ {
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ monitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
+ mi.cbSize = sizeof (mi);
+ if (monitor && GetMonitorInfo (monitor, &mi))
+ {
+ x = mi.rcMonitor.left;
+ y = mi.rcMonitor.top;
+ width = mi.rcMonitor.right - x;
+ height = mi.rcMonitor.bottom - y;
+ }
+ else
+ {
+ x = y = 0;
+ width = GetSystemMetrics (SM_CXSCREEN);
+ height = GetSystemMetrics (SM_CYSCREEN);
+ }
+
+ /* remember for restoring */
+ fi->hint_flags = impl->hint_flags;
+ impl->hint_flags &= ~GDK_HINT_MAX_SIZE;
+ g_object_set_data (G_OBJECT (window), "fullscreen-info", fi);
+ fi->style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
+
+ /* Send state change before configure event */
+ gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
+
+ SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE,
+ (fi->style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP);
+
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOP,
+ x, y, width, height,
+ SWP_NOCOPYBITS | SWP_SHOWWINDOW));
+ }
+}
+
+static void
+gdk_win32_surface_unfullscreen (GdkSurface *window)
+{
+ FullscreenInfo *fi;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ fi = g_object_get_data (G_OBJECT (window), "fullscreen-info");
+ if (fi)
+ {
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ gdk_synthesize_window_state (window, GDK_SURFACE_STATE_FULLSCREEN, 0);
+
+ impl->hint_flags = fi->hint_flags;
+ SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE, fi->style);
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_NOTOPMOST,
+ fi->r.left, fi->r.top,
+ fi->r.right - fi->r.left, fi->r.bottom - fi->r.top,
+ SWP_NOCOPYBITS | SWP_SHOWWINDOW));
+
+ g_object_set_data (G_OBJECT (window), "fullscreen-info", NULL);
+ g_free (fi);
+ _gdk_win32_surface_update_style_bits (window);
+ }
+}
+
+static void
+gdk_win32_surface_set_keep_above (GdkSurface *window,
+ gboolean setting)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_set_keep_above: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ setting ? "YES" : "NO"));
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ setting ? HWND_TOPMOST : HWND_NOTOPMOST,
+ 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
+ }
+
+ gdk_synthesize_window_state (window,
+ setting ? GDK_SURFACE_STATE_BELOW : GDK_SURFACE_STATE_ABOVE,
+ setting ? GDK_SURFACE_STATE_ABOVE : 0);
+}
+
+static void
+gdk_win32_surface_set_keep_below (GdkSurface *window,
+ gboolean setting)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_set_keep_below: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ setting ? "YES" : "NO"));
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ setting ? HWND_BOTTOM : HWND_NOTOPMOST,
+ 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
+ }
+
+ gdk_synthesize_window_state (window,
+ setting ? GDK_SURFACE_STATE_ABOVE : GDK_SURFACE_STATE_BELOW,
+ setting ? GDK_SURFACE_STATE_BELOW : 0);
+}
+
+static void
+gdk_win32_surface_focus (GdkSurface *window,
+ guint32 timestamp)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_focus: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ _gdk_win32_surface_state_to_string (window->state)));
+
+ if (window->state & GDK_SURFACE_STATE_MAXIMIZED)
+ GtkShowWindow (window, SW_SHOWMAXIMIZED);
+ else if (window->state & GDK_SURFACE_STATE_ICONIFIED)
+ GtkShowWindow (window, SW_RESTORE);
+ else if (!IsWindowVisible (GDK_SURFACE_HWND (window)))
+ GtkShowWindow (window, SW_SHOWNORMAL);
+ else
+ GtkShowWindow (window, SW_SHOW);
+
+ SetFocus (GDK_SURFACE_HWND (window));
+}
+
+static void
+gdk_win32_surface_set_modal_hint (GdkSurface *window,
+ gboolean modal)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_set_modal_hint: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ modal ? "YES" : "NO"));
+
+ if (modal == window->modal_hint)
+ return;
+
+ window->modal_hint = modal;
+
+#if 0
+ /* Not sure about this one.. -- Cody */
+ if (GDK_SURFACE_IS_MAPPED (window))
+ API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
+ modal ? HWND_TOPMOST : HWND_NOTOPMOST,
+ 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE));
+#else
+
+ if (modal)
+ {
+ _gdk_push_modal_window (window);
+ gdk_surface_raise (window);
+ }
+ else
+ {
+ _gdk_remove_modal_window (window);
+ }
+
+#endif
+}
+
+static void
+gdk_win32_surface_set_skip_taskbar_hint (GdkSurface *window,
+ gboolean skips_taskbar)
+{
+ static GdkSurface *owner = NULL;
+ //GdkSurfaceAttr wa;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_set_skip_taskbar_hint: %p: %s, doing nothing\n",
+ GDK_SURFACE_HWND (window),
+ skips_taskbar ? "YES" : "NO"));
+
+ // ### TODO: Need to figure out what to do here.
+ return;
+
+ if (skips_taskbar)
+ {
+#if 0
+ if (owner == NULL)
+ {
+ wa.window_type = GDK_SURFACE_TEMP;
+ wa.wclass = GDK_INPUT_OUTPUT;
+ wa.width = wa.height = 1;
+ wa.event_mask = 0;
+ owner = gdk_surface_new_internal (NULL, &wa, 0, TRUE);
+ }
+#endif
+
+ SetWindowLongPtr (GDK_SURFACE_HWND (window), GWLP_HWNDPARENT, (LONG_PTR) GDK_SURFACE_HWND (owner));
+
+#if 0 /* Should we also turn off the minimize and maximize buttons? */
+ SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE,
+ GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE) & ~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_SYSMENU));
+
+ SetWindowPos (GDK_SURFACE_HWND (window), SWP_NOZORDER_SPECIFIED,
+ 0, 0, 0, 0,
+ SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE |
+ SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
+#endif
+ }
+ else
+ {
+ SetWindowLongPtr (GDK_SURFACE_HWND (window), GWLP_HWNDPARENT, 0);
+ }
+}
+
+static void
+gdk_win32_surface_set_skip_pager_hint (GdkSurface *window,
+ gboolean skips_pager)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ GDK_NOTE (MISC, g_print ("gdk_surface_set_skip_pager_hint: %p: %s, doing nothing\n",
+ GDK_SURFACE_HWND (window),
+ skips_pager ? "YES" : "NO"));
+}
+
+static void
+gdk_win32_surface_set_type_hint (GdkSurface *window,
+ GdkSurfaceTypeHint hint)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC,
+ G_STMT_START{
+ static GEnumClass *class = NULL;
+ if (!class)
+ class = g_type_class_ref (GDK_TYPE_SURFACE_TYPE_HINT);
+ g_print ("gdk_surface_set_type_hint: %p: %s\n",
+ GDK_SURFACE_HWND (window),
+ g_enum_get_value (class, hint)->value_name);
+ }G_STMT_END);
+
+ ((GdkSurfaceImplWin32 *)window->impl)->type_hint = hint;
+
+ _gdk_win32_surface_update_style_bits (window);
+}
+
+static GdkSurfaceTypeHint
+gdk_win32_surface_get_type_hint (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), GDK_SURFACE_TYPE_HINT_NORMAL);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return GDK_SURFACE_TYPE_HINT_NORMAL;
+
+ return GDK_SURFACE_IMPL_WIN32 (window->impl)->type_hint;
+}
+
+static HRGN
+cairo_region_to_hrgn (const cairo_region_t *region,
+ gint x_origin,
+ gint y_origin,
+ guint scale)
+{
+ HRGN hrgn;
+ RGNDATA *rgndata;
+ RECT *rect;
+ cairo_rectangle_int_t r;
+ const int nrects = cairo_region_num_rectangles (region);
+ guint nbytes =
+ sizeof (RGNDATAHEADER) + (sizeof (RECT) * nrects);
+ int i;
+
+ rgndata = g_malloc (nbytes);
+ rgndata->rdh.dwSize = sizeof (RGNDATAHEADER);
+ rgndata->rdh.iType = RDH_RECTANGLES;
+ rgndata->rdh.nCount = rgndata->rdh.nRgnSize = 0;
+ SetRect (&rgndata->rdh.rcBound,
+ G_MAXLONG, G_MAXLONG, G_MINLONG, G_MINLONG);
+
+ for (i = 0; i < nrects; i++)
+ {
+ rect = ((RECT *) rgndata->Buffer) + rgndata->rdh.nCount++;
+
+ cairo_region_get_rectangle (region, i, &r);
+ rect->left = (r.x + x_origin) * scale;
+ rect->right = (rect->left + r.width) * scale;
+ rect->top = (r.y + y_origin) * scale;
+ rect->bottom = (rect->top + r.height) * scale;
+
+ if (rect->left < rgndata->rdh.rcBound.left)
+ rgndata->rdh.rcBound.left = rect->left;
+ if (rect->right > rgndata->rdh.rcBound.right)
+ rgndata->rdh.rcBound.right = rect->right;
+ if (rect->top < rgndata->rdh.rcBound.top)
+ rgndata->rdh.rcBound.top = rect->top;
+ if (rect->bottom > rgndata->rdh.rcBound.bottom)
+ rgndata->rdh.rcBound.bottom = rect->bottom;
+ }
+ if ((hrgn = ExtCreateRegion (NULL, nbytes, rgndata)) == NULL)
+ WIN32_API_FAILED ("ExtCreateRegion");
+
+ g_free (rgndata);
+
+ return (hrgn);
+}
+
+static void
+gdk_win32_surface_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+ GdkSurfaceImplWin32 *impl;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (!shape_region)
+ {
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_shape_combine_region: %p: none\n",
+ GDK_SURFACE_HWND (window)));
+ SetWindowRgn (GDK_SURFACE_HWND (window), NULL, TRUE);
+ }
+ else
+ {
+ HRGN hrgn;
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ hrgn = cairo_region_to_hrgn (shape_region, 0, 0, impl->window_scale);
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_shape_combine_region: %p: %p\n",
+ GDK_SURFACE_HWND (window),
+ hrgn));
+
+ do_shape_combine_region (window, hrgn, offset_x, offset_y);
+ }
+}
+
+GdkSurface *
+gdk_win32_surface_lookup_for_display (GdkDisplay *display,
+ HWND anid)
+{
+ g_return_val_if_fail (display == gdk_display_get_default (), NULL);
+
+ return (GdkSurface*) gdk_win32_handle_table_lookup (anid);
+}
+
+static void
+gdk_win32_surface_set_opacity (GdkSurface *window,
+ gdouble opacity)
+{
+ LONG exstyle;
+ typedef BOOL (WINAPI *PFN_SetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
+ PFN_SetLayeredWindowAttributes setLayeredWindowAttributes = NULL;
+ GdkSurfaceImplWin32 *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (!WINDOW_IS_TOPLEVEL (window) || GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (opacity < 0)
+ opacity = 0;
+ else if (opacity > 1)
+ opacity = 1;
+
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ if (impl->layered)
+ {
+ if (impl->layered_opacity != opacity)
+ {
+ RECT window_rect;
+
+ impl->layered_opacity = opacity;
+
+ gdk_win32_get_window_client_area_rect (window, impl->window_scale, &window_rect);
+ gdk_win32_update_layered_window_from_cache (window, &window_rect);
+ }
+
+ return;
+ }
+
+ exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
+
+ if (!(exstyle & WS_EX_LAYERED))
+ SetWindowLong (GDK_SURFACE_HWND (window),
+ GWL_EXSTYLE,
+ exstyle | WS_EX_LAYERED);
+
+ setLayeredWindowAttributes =
+ (PFN_SetLayeredWindowAttributes)GetProcAddress (GetModuleHandle ("user32.dll"), "SetLayeredWindowAttributes");
+
+ if (setLayeredWindowAttributes)
+ {
+ API_CALL (setLayeredWindowAttributes, (GDK_SURFACE_HWND (window),
+ 0,
+ opacity * 0xff,
+ LWA_ALPHA));
+ }
+}
+
+gboolean
+gdk_win32_surface_is_win32 (GdkSurface *window)
+{
+ return GDK_SURFACE_IS_WIN32 (window);
+}
+
+static gboolean
+gdk_win32_surface_show_window_menu (GdkSurface *window,
+ GdkEvent *event)
+{
+ double event_x, event_y;
+ gint x, y;
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ switch (event->type)
+ {
+ case GDK_BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_TOUCH_BEGIN:
+ case GDK_TOUCH_END:
+ break;
+ default:
+ return FALSE;
+ }
+
+ gdk_event_get_root_coords (event, &event_x, &event_y);
+ x = event_x - _gdk_offset_x;
+ y = event_y - _gdk_offset_y;
+
+ SendMessage (GDK_SURFACE_HWND (window),
+ WM_SYSMENU,
+ 0,
+ MAKELPARAM (x * impl->window_scale, y * impl->window_scale));
+
+ return TRUE;
+}
+
+/**
+ * _gdk_win32_acquire_dc
+ * @impl: a Win32 #GdkSurfaceImplWin32 implementation
+ *
+ * Gets a DC with the given drawable selected into it.
+ *
+ * Returns: The DC, on success. Otherwise
+ * %NULL. If this function succeeded
+ * _gdk_win32_impl_release_dc() must be called
+ * release the DC when you are done using it.
+ **/
+static HDC
+_gdk_win32_impl_acquire_dc (GdkSurfaceImplWin32 *impl)
+{
+ if (GDK_IS_SURFACE_IMPL_WIN32 (impl) &&
+ GDK_SURFACE_DESTROYED (impl->wrapper))
+ return NULL;
+
+ /* We don't call this function for layered windows, but
+ * in case we do...
+ */
+ if (impl->layered)
+ return NULL;
+
+ if (!impl->hdc)
+ {
+ impl->hdc = GetDC (impl->handle);
+ if (!impl->hdc)
+ WIN32_GDI_FAILED ("GetDC");
+ }
+
+ if (impl->hdc)
+ {
+ impl->hdc_count++;
+ return impl->hdc;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/**
+ * _gdk_win32_impl_release_dc
+ * @impl: a Win32 #GdkSurfaceImplWin32 implementation
+ *
+ * Releases the reference count for the DC
+ * from _gdk_win32_impl_acquire_dc()
+ **/
+static void
+_gdk_win32_impl_release_dc (GdkSurfaceImplWin32 *impl)
+{
+ if (impl->layered)
+ return;
+
+ g_return_if_fail (impl->hdc_count > 0);
+
+ impl->hdc_count--;
+ if (impl->hdc_count == 0)
+ {
+ if (impl->saved_dc_bitmap)
+ {
+ GDI_CALL (SelectObject, (impl->hdc, impl->saved_dc_bitmap));
+ impl->saved_dc_bitmap = NULL;
+ }
+
+ if (impl->hdc)
+ {
+ GDI_CALL (ReleaseDC, (impl->handle, impl->hdc));
+ impl->hdc = NULL;
+ }
+ }
+}
+
+HWND
+gdk_win32_surface_get_impl_hwnd (GdkSurface *window)
+{
+ if (GDK_SURFACE_IS_WIN32 (window))
+ return GDK_SURFACE_HWND (window);
+ return NULL;
+}
+
+static void
+gdk_win32_cairo_surface_destroy (void *data)
+{
+ GdkSurfaceImplWin32 *impl = data;
+
+ _gdk_win32_impl_release_dc (impl);
+ impl->cairo_surface = NULL;
+}
+
+static cairo_surface_t *
+gdk_win32_ref_cairo_surface_layered (GdkSurface *window,
+ GdkSurfaceImplWin32 *impl)
+{
+ gint width, height;
+ RECT window_rect;
+
+ gdk_win32_get_window_client_area_rect (window, impl->window_scale, &window_rect);
+
+ /* Turn client area into window area */
+ _gdk_win32_adjust_client_rect (window, &window_rect);
+
+ width = window_rect.right - window_rect.left;
+ height = window_rect.bottom - window_rect.top;
+
+ if (width > impl->dib_width ||
+ height > impl->dib_height)
+ {
+ cairo_surface_t *new_cache;
+ cairo_t *cr;
+
+ /* Create larger cache surface, copy old cache surface over it */
+ new_cache = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
+ width,
+ height);
+
+ if (impl->cache_surface)
+ {
+ cr = cairo_create (new_cache);
+ cairo_set_source_surface (cr, impl->cache_surface, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+ cairo_surface_flush (new_cache);
+
+ cairo_surface_destroy (impl->cache_surface);
+ }
+
+ impl->cache_surface = new_cache;
+
+ cairo_surface_set_device_scale (impl->cache_surface,
+ impl->window_scale,
+ impl->window_scale);
+
+ if (impl->cairo_surface)
+ cairo_surface_destroy (impl->cairo_surface);
+
+ impl->cairo_surface = NULL;
+ }
+
+ /* This is separate, because cairo_surface gets killed
+ * off frequently by outside code, whereas cache_surface
+ * is only killed by us, above.
+ */
+ if (!impl->cairo_surface)
+ {
+ impl->cairo_surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
+ width,
+ height);
+ impl->dib_width = width;
+ impl->dib_height = height;
+
+ cairo_surface_set_device_scale (impl->cairo_surface,
+ impl->window_scale,
+ impl->window_scale);
+
+ cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
+ impl, gdk_win32_cairo_surface_destroy);
+ }
+ else
+ {
+ cairo_surface_reference (impl->cairo_surface);
+ }
+
+ return impl->cairo_surface;
+}
+
+static cairo_surface_t *
+gdk_win32_ref_cairo_surface (GdkSurface *window)
+{
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ if (GDK_IS_SURFACE_IMPL_WIN32 (impl) &&
+ GDK_SURFACE_DESTROYED (impl->wrapper))
+ return NULL;
+
+ if (impl->layered)
+ return gdk_win32_ref_cairo_surface_layered (window, impl);
+
+ if (!impl->cairo_surface)
+ {
+ HDC hdc = _gdk_win32_impl_acquire_dc (impl);
+ if (!hdc)
+ return NULL;
+
+ impl->cairo_surface = cairo_win32_surface_create_with_format (hdc, CAIRO_FORMAT_ARGB32);
+ cairo_surface_set_device_scale (impl->cairo_surface,
+ impl->window_scale,
+ impl->window_scale);
+
+ cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
+ impl, gdk_win32_cairo_surface_destroy);
+ }
+ else
+ cairo_surface_reference (impl->cairo_surface);
+
+ return impl->cairo_surface;
+}
+
+BOOL WINAPI
+GtkShowWindow (GdkSurface *window,
+ int cmd_show)
+{
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ RECT window_rect;
+ HDC hdc;
+ POINT window_position;
+ SIZE window_size;
+ POINT source_point;
+ BLENDFUNCTION blender;
+
+ HWND hwnd = GDK_SURFACE_HWND (window);
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ switch (cmd_show)
+ {
+ case SW_FORCEMINIMIZE:
+ case SW_HIDE:
+ case SW_MINIMIZE:
+ break;
+ case SW_MAXIMIZE:
+ case SW_RESTORE:
+ case SW_SHOW:
+ case SW_SHOWDEFAULT:
+ case SW_SHOWMINIMIZED:
+ case SW_SHOWMINNOACTIVE:
+ case SW_SHOWNA:
+ case SW_SHOWNOACTIVATE:
+ case SW_SHOWNORMAL:
+ if (IsWindowVisible (hwnd))
+ break;
+
+ if ((WS_EX_LAYERED & GetWindowLongPtr (hwnd, GWL_EXSTYLE)) != WS_EX_LAYERED)
+ break;
+
+ /* Window was hidden, will be shown. Erase it, GDK will repaint soon,
+ * but not soon enough, so it's possible to see old content before
+ * the next redraw, unless we erase the window first.
+ */
+ GetWindowRect (hwnd, &window_rect);
+ source_point.x = source_point.y = 0;
+
+ window_position.x = window_rect.left;
+ window_position.y = window_rect.top;
+ window_size.cx = window_rect.right - window_rect.left;
+ window_size.cy = window_rect.bottom - window_rect.top;
+
+ blender.BlendOp = AC_SRC_OVER;
+ blender.BlendFlags = 0;
+ blender.AlphaFormat = AC_SRC_ALPHA;
+ blender.SourceConstantAlpha = 255;
+
+ /* Create a surface of appropriate size and clear it */
+ surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
+ window_size.cx,
+ window_size.cy);
+ cairo_surface_set_device_scale (surface, impl->window_scale, impl->window_scale);
+ cr = cairo_create (surface);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+ cairo_surface_flush (surface);
+ hdc = cairo_win32_surface_get_dc (surface);
+
+ /* No API_CALL() wrapper, don't check for errors */
+ UpdateLayeredWindow (hwnd, NULL,
+ &window_position, &window_size,
+ hdc, &source_point,
+ 0, &blender, ULW_ALPHA);
+
+ cairo_surface_destroy (surface);
+
+ break;
+ }
+
+ /* Ensure that maximized window size is corrected later on */
+ if (cmd_show == SW_MAXIMIZE)
+ impl->maximizing = TRUE;
+
+ return ShowWindow (hwnd, cmd_show);
+}
+
+static void
+gdk_win32_surface_set_shadow_width (GdkSurface *window,
+ gint left,
+ gint right,
+ gint top,
+ gint bottom)
+{
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ GDK_NOTE (MISC, g_print ("gdk_win32_surface_set_shadow_width: window %p, "
+ "left %d, top %d, right %d, bottom %d\n",
+ window, left, top, right, bottom));
+
+ impl->zero_margins = left == 0 && right == 0 && top == 0 && bottom == 0;
+
+ if (impl->zero_margins)
+ return;
+
+ impl->margins.left = left;
+ impl->margins.right = right * impl->window_scale;
+ impl->margins.top = top;
+ impl->margins.bottom = bottom * impl->window_scale;
+ impl->margins_x = left + right;
+ impl->margins_y = top + bottom;
+}
+
+
+gint
+_gdk_win32_surface_get_scale_factor (GdkSurface *window)
+{
+ GdkDisplay *display;
+ GdkSurfaceImplWin32 *impl;
+
+ GdkWin32Display *win32_display;
+ UINT dpix, dpiy;
+ gboolean is_scale_acquired;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return 1;
+
+ g_return_val_if_fail (window != NULL, 1);
+
+ display = gdk_surface_get_display (window);
+ impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ win32_display = GDK_WIN32_DISPLAY (display);
+
+ if (win32_display->dpi_aware_type != PROCESS_DPI_UNAWARE)
+ {
+ if (win32_display->has_fixed_scale)
+ impl->window_scale = win32_display->window_scale;
+ else
+ impl->window_scale = _gdk_win32_display_get_monitor_scale_factor (win32_display,
+ NULL,
+ GDK_SURFACE_HWND (window),
+ NULL);
+
+ return impl->window_scale;
+ }
+ else
+ {
+ if (win32_display->has_fixed_scale)
+ {
+ static gsize hidpi_msg_displayed = 0;
+
+ if (g_once_init_enter (&hidpi_msg_displayed))
+ {
+ g_message ("Note: GDK_SCALE is ignored as HiDPI awareness is disabled.");
+ g_once_init_leave (&hidpi_msg_displayed, 1);
+ }
+ }
+
+ /* Application is not DPI aware, don't bother */
+ return 1;
+ }
+}
+
+void
+_gdk_win32_surface_get_unscaled_size (GdkSurface *window,
+ gint *unscaled_width,
+ gint *unscaled_height)
+{
+ GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
+
+ if (unscaled_width)
+ *unscaled_width = impl->unscaled_width;
+ if (unscaled_height)
+ *unscaled_height = impl->unscaled_height;
+}
+
+static void
+gdk_win32_input_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+ /* Partial input shape support is implemented by handling the
+ * NC_NCHITTEST message
+ */
+}
+
+static void
+gdk_surface_impl_win32_class_init (GdkSurfaceImplWin32Class *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = gdk_surface_impl_win32_finalize;
+
+ impl_class->ref_cairo_surface = gdk_win32_ref_cairo_surface;
+
+ impl_class->show = gdk_win32_surface_show;
+ impl_class->hide = gdk_win32_surface_hide;
+ impl_class->withdraw = gdk_win32_surface_withdraw;
+ impl_class->set_events = gdk_win32_surface_set_events;
+ impl_class->get_events = gdk_win32_surface_get_events;
+ impl_class->raise = gdk_win32_surface_raise;
+ impl_class->lower = gdk_win32_surface_lower;
+ impl_class->restack_toplevel = gdk_win32_surface_restack_toplevel;
+ impl_class->move_resize = gdk_win32_surface_move_resize;
+ impl_class->get_geometry = gdk_win32_surface_get_geometry;
+ impl_class->get_device_state = gdk_surface_win32_get_device_state;
+ impl_class->get_root_coords = gdk_win32_surface_get_root_coords;
+
+ impl_class->shape_combine_region = gdk_win32_surface_shape_combine_region;
+ impl_class->input_shape_combine_region = gdk_win32_input_shape_combine_region;
+ impl_class->destroy = gdk_win32_surface_destroy;
+ impl_class->begin_paint = gdk_win32_surface_begin_paint;
+ impl_class->end_paint = gdk_win32_surface_end_paint;
+
+ //impl_class->beep = gdk_x11_surface_beep;
+
+
+ impl_class->show_window_menu = gdk_win32_surface_show_window_menu;
+ impl_class->focus = gdk_win32_surface_focus;
+ impl_class->set_type_hint = gdk_win32_surface_set_type_hint;
+ impl_class->get_type_hint = gdk_win32_surface_get_type_hint;
+ impl_class->set_modal_hint = gdk_win32_surface_set_modal_hint;
+ impl_class->set_skip_taskbar_hint = gdk_win32_surface_set_skip_taskbar_hint;
+ impl_class->set_skip_pager_hint = gdk_win32_surface_set_skip_pager_hint;
+ impl_class->set_urgency_hint = gdk_win32_surface_set_urgency_hint;
+ impl_class->set_geometry_hints = gdk_win32_surface_set_geometry_hints;
+ impl_class->set_title = gdk_win32_surface_set_title;
+ impl_class->set_role = gdk_win32_surface_set_role;
+ //impl_class->set_startup_id = gdk_x11_surface_set_startup_id;
+ impl_class->set_transient_for = gdk_win32_surface_set_transient_for;
+ impl_class->get_frame_extents = gdk_win32_surface_get_frame_extents;
+ impl_class->set_accept_focus = gdk_win32_surface_set_accept_focus;
+ impl_class->set_focus_on_map = gdk_win32_surface_set_focus_on_map;
+ impl_class->set_icon_list = gdk_win32_surface_set_icon_list;
+ impl_class->set_icon_name = gdk_win32_surface_set_icon_name;
+ impl_class->iconify = gdk_win32_surface_iconify;
+ impl_class->deiconify = gdk_win32_surface_deiconify;
+ impl_class->stick = gdk_win32_surface_stick;
+ impl_class->unstick = gdk_win32_surface_unstick;
+ impl_class->maximize = gdk_win32_surface_maximize;
+ impl_class->unmaximize = gdk_win32_surface_unmaximize;
+ impl_class->fullscreen = gdk_win32_surface_fullscreen;
+ impl_class->unfullscreen = gdk_win32_surface_unfullscreen;
+ impl_class->set_keep_above = gdk_win32_surface_set_keep_above;
+ impl_class->set_keep_below = gdk_win32_surface_set_keep_below;
+ impl_class->get_group = gdk_win32_surface_get_group;
+ impl_class->set_group = gdk_win32_surface_set_group;
+ impl_class->set_decorations = gdk_win32_surface_set_decorations;
+ impl_class->get_decorations = gdk_win32_surface_get_decorations;
+ impl_class->set_functions = gdk_win32_surface_set_functions;
+
+ impl_class->set_shadow_width = gdk_win32_surface_set_shadow_width;
+ impl_class->begin_resize_drag = gdk_win32_surface_begin_resize_drag;
+ impl_class->begin_move_drag = gdk_win32_surface_begin_move_drag;
+ impl_class->set_opacity = gdk_win32_surface_set_opacity;
+ impl_class->destroy_notify = gdk_win32_surface_destroy_notify;
+ impl_class->register_dnd = _gdk_win32_surface_register_dnd;
+ impl_class->drag_begin = _gdk_win32_surface_drag_begin;
+ impl_class->create_gl_context = _gdk_win32_surface_create_gl_context;
+ impl_class->get_scale_factor = _gdk_win32_surface_get_scale_factor;
+ impl_class->get_unscaled_size = _gdk_win32_surface_get_unscaled_size;
+}
+
+HGDIOBJ
+gdk_win32_surface_get_handle (GdkSurface *window)
+{
+ if (!GDK_SURFACE_IS_WIN32 (window))
+ {
+ g_warning (G_STRLOC " window is not a native Win32 window");
+ return NULL;
+ }
+
+ return GDK_SURFACE_HWND (window);
+}
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GDK_SURFACE_WIN32_H__
+#define __GDK_SURFACE_WIN32_H__
+
+#include "gdk/win32/gdkprivate-win32.h"
+#include "gdk/gdksurfaceimpl.h"
+#include "gdk/gdkcursor.h"
+
+#include <windows.h>
+
+G_BEGIN_DECLS
+
+/* Window implementation for Win32
+ */
+
+typedef struct _GdkSurfaceImplWin32 GdkSurfaceImplWin32;
+typedef struct _GdkSurfaceImplWin32Class GdkSurfaceImplWin32Class;
+
+#define GDK_TYPE_SURFACE_IMPL_WIN32 (_gdk_surface_impl_win32_get_type ())
+#define GDK_SURFACE_IMPL_WIN32(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL_WIN32, GdkSurfaceImplWin32))
+#define GDK_SURFACE_IMPL_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL_WIN32, GdkSurfaceImplWin32Class))
+#define GDK_IS_SURFACE_IMPL_WIN32(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL_WIN32))
+#define GDK_IS_SURFACE_IMPL_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL_WIN32))
+#define GDK_SURFACE_IMPL_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL_WIN32, GdkSurfaceImplWin32Class))
+
+enum _GdkWin32AeroSnapCombo
+{
+ GDK_WIN32_AEROSNAP_COMBO_NOTHING = 0,
+ GDK_WIN32_AEROSNAP_COMBO_UP,
+ GDK_WIN32_AEROSNAP_COMBO_DOWN,
+ GDK_WIN32_AEROSNAP_COMBO_LEFT,
+ GDK_WIN32_AEROSNAP_COMBO_RIGHT,
+ /* Same order as non-shift variants. We use it to do things like:
+ * AEROSNAP_UP + 4 = AEROSNAP_SHIFTUP
+ */
+ GDK_WIN32_AEROSNAP_COMBO_SHIFTUP,
+ GDK_WIN32_AEROSNAP_COMBO_SHIFTDOWN,
+ GDK_WIN32_AEROSNAP_COMBO_SHIFTLEFT,
+ GDK_WIN32_AEROSNAP_COMBO_SHIFTRIGHT
+};
+
+typedef enum _GdkWin32AeroSnapCombo GdkWin32AeroSnapCombo;
+
+enum _GdkWin32AeroSnapState
+{
+ GDK_WIN32_AEROSNAP_STATE_UNDETERMINED = 0,
+ GDK_WIN32_AEROSNAP_STATE_HALFLEFT,
+ GDK_WIN32_AEROSNAP_STATE_HALFRIGHT,
+ GDK_WIN32_AEROSNAP_STATE_FULLUP,
+ /* Maximize state is only used by edge-snap */
+ GDK_WIN32_AEROSNAP_STATE_MAXIMIZE
+};
+
+typedef enum _GdkWin32AeroSnapState GdkWin32AeroSnapState;
+
+struct _GdkRectangleDouble
+{
+ gdouble x;
+ gdouble y;
+ gdouble width;
+ gdouble height;
+};
+
+typedef struct _GdkRectangleDouble GdkRectangleDouble;
+
+enum _GdkW32WindowDragOp
+{
+ GDK_WIN32_DRAGOP_NONE = 0,
+ GDK_WIN32_DRAGOP_RESIZE,
+ GDK_WIN32_DRAGOP_MOVE,
+ GDK_WIN32_DRAGOP_COUNT
+};
+
+typedef enum _GdkW32WindowDragOp GdkW32WindowDragOp;
+
+typedef enum _GdkWin32MonitorDpiType
+{
+ MDT_EFFECTIVE_DPI = 0,
+ MDT_ANGULAR_DPI = 1,
+ MDT_RAW_DPI = 2,
+ MDT_DEFAULT = MDT_EFFECTIVE_DPI
+} GdkWin32MonitorDpiType;
+
+struct _GdkW32DragMoveResizeContext
+{
+ /* The window that is being moved/resized */
+ GdkSurface *window;
+
+ /* The kind of drag-operation going on. */
+ GdkW32WindowDragOp op;
+
+ /* The edge that was grabbed for resizing. Not used for moving. */
+ GdkSurfaceEdge edge;
+
+ /* The device used to initiate the op.
+ * We grab it at the beginning and ungrab it at the end.
+ */
+ GdkDevice *device;
+
+ /* The button pressed down to initiate the op.
+ * The op will be canceled only when *this* button
+ * is released.
+ */
+ gint button;
+
+ /* Initial cursor position when the operation began.
+ * Current cursor position is subtracted from it to find how far
+ * to move window border(s).
+ */
+ gint start_root_x;
+ gint start_root_y;
+
+ /* Initial window rectangle (position and size).
+ * The window is resized/moved relative to this (see start_root_*).
+ */
+ RECT start_rect;
+
+ /* Not used */
+ guint32 timestamp;
+
+ /* TRUE if during the next redraw we should call SetWindowPos() to push
+ * the window size and poistion to the native window.
+ */
+ gboolean native_move_resize_pending;
+
+ /* The cursor we should use while the operation is running. */
+ GdkCursor *cursor;
+
+ /* This window looks like an outline and is drawn under the window
+ * that is being dragged. It indicates the shape the dragged window
+ * will take if released at a particular point.
+ * Indicator window size always matches the target indicator shape,
+ * the the actual indicator drawn on it might not, depending on
+ * how much time elapsed since the animation started.
+ */
+ HWND shape_indicator;
+
+ /* Used to draw the indicator */
+ cairo_surface_t *indicator_surface;
+ gint indicator_surface_width;
+ gint indicator_surface_height;
+
+ /* Size/position of shape_indicator */
+ GdkRectangle indicator_window_rect;
+
+ /* Indicator will animate to occupy this rectangle */
+ GdkRectangle indicator_target;
+
+ /* Indicator will start animating from this rectangle */
+ GdkRectangle indicator_start;
+
+ /* Timestamp of the animation start */
+ gint64 indicator_start_time;
+
+ /* Timer that drives the animation */
+ guint timer;
+
+ /* A special timestamp, if we want to draw not how
+ * the animation should look *now*, but how it should
+ * look at arbitrary moment of time.
+ * Set to 0 to tell GDK to use current time.
+ */
+ gint64 draw_timestamp;
+
+ /* Indicates that a transformation was revealed:
+ *
+ * For drag-resize: If it's FALSE,
+ * then the pointer have not yet hit a trigger that triggers fullup.
+ * If TRUE, then the pointer did hit a trigger that triggers fullup
+ * at some point during this drag op.
+ * This is used to prevent drag-resize from triggering
+ * a transformation when first approaching a trigger of the work area -
+ * one must drag it all the way to the very trigger to trigger; afterwards
+ * a transformation will start triggering at some distance from the trigger
+ * for as long as the op is still running. This is how AeroSnap works.
+ *
+ * For drag-move: If it's FALSE,
+ * then the pointer have not yet hit a trigger, even if it is
+ * already within a edge region.
+ * If it's TRUE, then the pointer did hit a trigger within an
+ * edge region, and have not yet left an edge region
+ * (passing from one edge region into another doesn't count).
+ */
+ gboolean revealed;
+
+ /* Arrays of GdkRectangle pairs, describing the areas of the virtual
+ * desktop that trigger various AeroSnap window transofrmations
+ * Coordinates are GDK screen coordinates.
+ */
+ GArray *halfleft_regions;
+ GArray *halfright_regions;
+ GArray *maximize_regions;
+ GArray *fullup_regions;
+
+ /* Current pointer position will result in this kind of snapping,
+ * if the drag op is finished.
+ */
+ GdkWin32AeroSnapState current_snap;
+};
+
+typedef struct _GdkW32DragMoveResizeContext GdkW32DragMoveResizeContext;
+
+struct _GdkSurfaceImplWin32
+{
+ GdkSurfaceImpl parent_instance;
+
+ GdkSurface *wrapper;
+ HANDLE handle;
+
+ gint8 toplevel_window_type;
+
+ HICON hicon_big;
+ HICON hicon_small;
+
+ /* When VK_PACKET sends us a leading surrogate, it's stashed here.
+ * Later, when another VK_PACKET sends a tailing surrogate, we make up
+ * a full unicode character from them, or discard the leading surrogate,
+ * if the next key is not a tailing surrogate.
+ */
+ wchar_t leading_surrogate_keydown;
+ wchar_t leading_surrogate_keyup;
+
+ /* Window size hints */
+ gint hint_flags;
+ GdkGeometry hints;
+
+ GdkEventMask native_event_mask;
+
+ GdkSurfaceTypeHint type_hint;
+
+ GdkSurface *transient_owner;
+ GSList *transient_children;
+ gint num_transients;
+ gboolean changing_state;
+
+ gint initial_x;
+ gint initial_y;
+
+ /* left/right/top/bottom width of the shadow/resize-grip around the window */
+ RECT margins;
+
+ /* left+right and top+bottom from @margins */
+ gint margins_x;
+ gint margins_y;
+
+ /* Set to TRUE when GTK tells us that margins are 0 everywhere.
+ * We don't actually set margins to 0, we just set this bit.
+ */
+ guint zero_margins : 1;
+ guint no_bg : 1;
+ guint inhibit_configure : 1;
+
+ /* Set to TRUE if window is using true layered mode adjustments
+ * via UpdateLayeredWindow().
+ * Layered windows that get SetLayeredWindowAttributes() called
+ * on them are not true layered windows.
+ */
+ guint layered : 1;
+
+ /* If TRUE, the @temp_styles is set to the styles that were temporarily
+ * added to this window.
+ */
+ guint have_temp_styles : 1;
+
+ /* If TRUE, the window is in the process of being maximized.
+ * This is set by WM_SYSCOMMAND and by gdk_win32_surface_maximize (),
+ * and is unset when WM_WINDOWPOSCHANGING is handled.
+ */
+ guint maximizing : 1;
+
+ /* GDK does not keep window contents around, it just draws new
+ * stuff over the window where changes occurred.
+ * cache_surface retains old window contents, because
+ * UpdateLayeredWindow() doesn't do partial redraws.
+ */
+ cairo_surface_t *cache_surface;
+ cairo_surface_t *cairo_surface;
+
+ /* Unlike window-backed surfaces, DIB-backed surface
+ * does not provide a way to query its size,
+ * so we have to remember it ourselves.
+ */
+ gint dib_width;
+ gint dib_height;
+
+ /* If the client wants uniformly-transparent window,
+ * we remember the opacity value here and apply it
+ * during UpdateLayredWindow() call, for layered windows.
+ */
+ gdouble layered_opacity;
+
+ HDC hdc;
+ int hdc_count;
+ HBITMAP saved_dc_bitmap; /* Original bitmap for dc */
+
+ GdkW32DragMoveResizeContext drag_move_resize_context;
+
+ /* Remembers where the window was snapped.
+ * Some snap operations change their meaning if
+ * the window is already snapped.
+ */
+ GdkWin32AeroSnapState snap_state;
+
+ /* Remembers window position before it was snapped.
+ * This is used to unsnap it.
+ * Position and size are percentages of the workarea
+ * of the monitor on which the window was before it was snapped.
+ */
+ GdkRectangleDouble *snap_stash;
+
+ /* Also remember the same position, but in absolute form. */
+ GdkRectangle *snap_stash_int;
+
+ /* Decorations set by gdk_surface_set_decorations() or NULL if unset */
+ GdkWMDecoration* decorations;
+
+ /* No. of windows to force layered windows off */
+ guint suppress_layered;
+
+ /* Temporary styles that this window got for the purpose of
+ * handling WM_SYSMENU.
+ * They are removed at the first opportunity (usually WM_INITMENU).
+ */
+ LONG_PTR temp_styles;
+
+ /* scale of window on HiDPI */
+ gint window_scale;
+ gint unscaled_width;
+ gint unscaled_height;
+};
+
+struct _GdkSurfaceImplWin32Class
+{
+ GdkSurfaceImplClass parent_class;
+};
+
+GType _gdk_surface_impl_win32_get_type (void);
+
+void _gdk_win32_surface_tmp_unset_bg (GdkSurface *window,
+ gboolean recurse);
+void _gdk_win32_surface_tmp_reset_bg (GdkSurface *window,
+ gboolean recurse);
+
+void _gdk_win32_surface_tmp_unset_parent_bg (GdkSurface *window);
+void _gdk_win32_surface_tmp_reset_parent_bg (GdkSurface *window);
+
+void _gdk_win32_surface_update_style_bits (GdkSurface *window);
+
+gint _gdk_win32_surface_get_scale_factor (GdkSurface *window);
+
+G_END_DECLS
+
+#endif /* __GDK_SURFACE_WIN32_H__ */
#include <gdk/win32/gdkwin32dnd.h>
#include <gdk/win32/gdkwin32keys.h>
#include <gdk/win32/gdkwin32screen.h>
-#include <gdk/win32/gdkwin32window.h>
+#include <gdk/win32/gdkwin32surface.h>
#include <gdk/win32/gdkwin32misc.h>
#include <gdk/win32/gdkwin32monitor.h>
#include <gdk/win32/gdkwin32glcontext.h>
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GDK_WIN32_SURFACE_H__
+#define __GDK_WIN32_SURFACE_H__
+
+#if !defined (__GDKWIN32_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdkwin32.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_WIN32_SURFACE (gdk_win32_surface_get_type ())
+#define GDK_WIN32_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WIN32_SURFACE, GdkWin32Surface))
+#define GDK_WIN32_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WIN32_SURFACE, GdkWin32SurfaceClass))
+#define GDK_IS_WIN32_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WIN32_SURFACE))
+#define GDK_IS_WIN32_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WIN32_SURFACE))
+#define GDK_WIN32_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WIN32_SURFACE, GdkWin32SurfaceClass))
+
+#ifdef GDK_COMPILATION
+typedef struct _GdkWin32Surface GdkWin32Surface;
+#else
+typedef GdkSurface GdkWin32Surface;
+#endif
+typedef struct _GdkWin32SurfaceClass GdkWin32SurfaceClass;
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_win32_surface_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GDK_X11_SURFACE_H__ */
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#ifndef __GDK_WIN32_SURFACE_H__
-#define __GDK_WIN32_SURFACE_H__
-
-#if !defined (__GDKWIN32_H_INSIDE__) && !defined (GDK_COMPILATION)
-#error "Only <gdk/gdkwin32.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_WIN32_SURFACE (gdk_win32_surface_get_type ())
-#define GDK_WIN32_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WIN32_SURFACE, GdkWin32Surface))
-#define GDK_WIN32_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WIN32_SURFACE, GdkWin32SurfaceClass))
-#define GDK_IS_WIN32_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WIN32_SURFACE))
-#define GDK_IS_WIN32_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WIN32_SURFACE))
-#define GDK_WIN32_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WIN32_SURFACE, GdkWin32SurfaceClass))
-
-#ifdef GDK_COMPILATION
-typedef struct _GdkWin32Surface GdkWin32Surface;
-#else
-typedef GdkSurface GdkWin32Surface;
-#endif
-typedef struct _GdkWin32SurfaceClass GdkWin32SurfaceClass;
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_win32_surface_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GDK_X11_SURFACE_H__ */
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- * Copyright (C) 1998-2004 Tor Lillqvist
- * Copyright (C) 2001-2011 Hans Breuer
- * Copyright (C) 2007-2009 Cody Russell
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#include "config.h"
-#include <stdlib.h>
-
-#include "gdk.h"
-#include "gdkwindowimpl.h"
-#include "gdkprivate-win32.h"
-#include "gdkdeviceprivate.h"
-#include "gdkdevicemanager-win32.h"
-#include "gdkenumtypes.h"
-#include "gdkwin32.h"
-#include "gdkdisplayprivate.h"
-#include "gdkmonitorprivate.h"
-#include "gdkwin32window.h"
-#include "gdkglcontext-win32.h"
-#include "gdkdisplay-win32.h"
-
-#include <cairo-win32.h>
-#include <dwmapi.h>
-#include <math.h>
-#include "fallback-c89.c"
-
-static void gdk_surface_impl_win32_init (GdkSurfaceImplWin32 *window);
-static void gdk_surface_impl_win32_class_init (GdkSurfaceImplWin32Class *klass);
-static void gdk_surface_impl_win32_finalize (GObject *object);
-
-static gpointer parent_class = NULL;
-static GSList *modal_window_stack = NULL;
-
-static const cairo_user_data_key_t gdk_win32_cairo_key;
-typedef struct _FullscreenInfo FullscreenInfo;
-
-struct _FullscreenInfo
-{
- RECT r;
- guint hint_flags;
- LONG style;
-};
-
-struct _AeroSnapEdgeRegion
-{
- /* The rectangle along the edge of the desktop
- * that allows application of the snap transformation.
- */
- GdkRectangle edge;
-
- /* A subregion of the "edge". When the pointer hits
- * this region, the transformation is revealed.
- * Usually it is 1-pixel thick and is located at the
- * very edge of the screen. When there's a toolbar
- * at that edge, the "trigger" and the "edge" regions
- * are extended to cover that toolbar.
- */
- GdkRectangle trigger;
-};
-
-typedef struct _AeroSnapEdgeRegion AeroSnapEdgeRegion;
-
-/* Use this for hWndInsertAfter (2nd argument to SetWindowPos()) if
- * SWP_NOZORDER flag is used. Otherwise it's unobvious why a particular
- * argument is used. Using NULL is misleading, because
- * NULL is equivalent to HWND_TOP.
- */
-#define SWP_NOZORDER_SPECIFIED HWND_TOP
-
-/* Size of the regions at the edges of the desktop where
- * snapping can take place (in pixels)
- */
-#define AEROSNAP_REGION_THICKNESS (20)
-/* Size of the subregions that actually trigger the snapping prompt
- * (in pixels).
- */
-#define AEROSNAP_REGION_TRIGGER_THICKNESS (1)
-
-/* The gap between the snap indicator and the edge of the work area
- * (in pixels).
- */
-#define AEROSNAP_INDICATOR_EDGE_GAP (10)
-
-/* Width of the outline of the snap indicator
- * (in pixels).
- */
-#define AEROSNAP_INDICATOR_LINE_WIDTH (3.0)
-
-/* Corner radius of the snap indicator.
- */
-#define AEROSNAP_INDICATOR_CORNER_RADIUS (3.0)
-
-/* The time it takes for snap indicator to expand/shrink
- * from current window size to future position of the
- * snapped window (in microseconds).
- */
-#define AEROSNAP_INDICATOR_ANIMATION_DURATION (200 * 1000)
-
-/* Opacity if the snap indicator. */
-#define AEROSNAP_INDICATOR_OPACITY (0.5)
-
-/* The interval between snap indicator redraws (in milliseconds).
- * 16 is ~ 1/60 of a second, for ~60 FPS.
- */
-#define AEROSNAP_INDICATOR_ANIMATION_TICK (16)
-
-static gboolean _gdk_surface_get_functions (GdkSurface *window,
- GdkWMFunction *functions);
-static HDC _gdk_win32_impl_acquire_dc (GdkSurfaceImplWin32 *impl);
-static void _gdk_win32_impl_release_dc (GdkSurfaceImplWin32 *impl);
-
-#define WINDOW_IS_TOPLEVEL(window) \
- (GDK_SURFACE_TYPE (window) != GDK_SURFACE_FOREIGN)
-
-struct _GdkWin32Surface {
- GdkSurface parent;
-};
-
-struct _GdkWin32SurfaceClass {
- GdkSurfaceClass parent_class;
-};
-
-G_DEFINE_TYPE (GdkWin32Surface, gdk_win32_surface, GDK_TYPE_SURFACE)
-
-static void
-gdk_win32_surface_class_init (GdkWin32SurfaceClass *window_class)
-{
-}
-
-static void
-gdk_win32_surface_init (GdkWin32Surface *window)
-{
-}
-
-
-G_DEFINE_TYPE (GdkSurfaceImplWin32, gdk_surface_impl_win32, GDK_TYPE_SURFACE_IMPL)
-
-GType
-_gdk_surface_impl_win32_get_type (void)
-{
- static GType object_type = 0;
-
- if (!object_type)
- {
- const GTypeInfo object_info =
- {
- sizeof (GdkSurfaceImplWin32Class),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gdk_surface_impl_win32_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GdkSurfaceImplWin32),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gdk_surface_impl_win32_init,
- };
-
- object_type = g_type_register_static (GDK_TYPE_SURFACE_IMPL,
- "GdkSurfaceImplWin32",
- &object_info, 0);
- }
-
- return object_type;
-}
-
-static void
-gdk_surface_impl_win32_init (GdkSurfaceImplWin32 *impl)
-{
- GdkDisplay *display = gdk_display_get_default ();
-
- impl->toplevel_window_type = -1;
- impl->hicon_big = NULL;
- impl->hicon_small = NULL;
- impl->hint_flags = 0;
- impl->type_hint = GDK_SURFACE_TYPE_HINT_NORMAL;
- impl->transient_owner = NULL;
- impl->transient_children = NULL;
- impl->num_transients = 0;
- impl->changing_state = FALSE;
- impl->window_scale = 1;
-}
-
-static void
-gdk_surface_impl_win32_finalize (GObject *object)
-{
- GdkSurface *wrapper;
- GdkSurfaceImplWin32 *window_impl;
-
- g_return_if_fail (GDK_IS_SURFACE_IMPL_WIN32 (object));
-
- window_impl = GDK_SURFACE_IMPL_WIN32 (object);
-
- wrapper = window_impl->wrapper;
-
- if (!GDK_SURFACE_DESTROYED (wrapper))
- {
- gdk_win32_handle_table_remove (window_impl->handle);
- }
-
- g_clear_pointer (&window_impl->snap_stash, g_free);
- g_clear_pointer (&window_impl->snap_stash_int, g_free);
-
- if (window_impl->hicon_big != NULL)
- {
- GDI_CALL (DestroyIcon, (window_impl->hicon_big));
- window_impl->hicon_big = NULL;
- }
-
- if (window_impl->hicon_small != NULL)
- {
- GDI_CALL (DestroyIcon, (window_impl->hicon_small));
- window_impl->hicon_small = NULL;
- }
-
- g_free (window_impl->decorations);
-
- if (window_impl->cache_surface)
- {
- cairo_surface_destroy (window_impl->cache_surface);
- window_impl->cache_surface = NULL;
- }
-
- if (window_impl->cairo_surface)
- {
- cairo_surface_destroy (window_impl->cairo_surface);
- window_impl->cairo_surface = NULL;
- }
-
- g_assert (window_impl->transient_owner == NULL);
- g_assert (window_impl->transient_children == NULL);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gdk_win32_get_window_client_area_rect (GdkSurface *window,
- gint scale,
- RECT *rect)
-{
- gint x, y, width, height;
-
- gdk_surface_get_position (window, &x, &y);
- width = gdk_surface_get_width (window);
- height = gdk_surface_get_height (window);
- rect->left = x * scale;
- rect->top = y * scale;
- rect->right = rect->left + width * scale;
- rect->bottom = rect->top + height * scale;
-}
-
-static void
-gdk_win32_surface_get_queued_window_rect (GdkSurface *window,
- RECT *return_window_rect)
-{
- RECT window_rect;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- gdk_win32_get_window_client_area_rect (window, impl->window_scale, &window_rect);
-
- /* Turn client area into window area */
- _gdk_win32_adjust_client_rect (window, &window_rect);
-
- /* Convert GDK screen coordinates to W32 desktop coordinates */
- window_rect.left -= _gdk_offset_x * impl->window_scale;
- window_rect.right -= _gdk_offset_x * impl->window_scale;
- window_rect.top -= _gdk_offset_y * impl->window_scale;
- window_rect.bottom -= _gdk_offset_y * impl->window_scale;
-
- *return_window_rect = window_rect;
-}
-
-static void
-gdk_win32_surface_apply_queued_move_resize (GdkSurface *window,
- RECT window_rect)
-{
- if (!IsIconic (GDK_SURFACE_HWND (window)))
- {
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- GDK_NOTE (EVENTS, g_print ("Setting window position ... "));
-
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- SWP_NOZORDER_SPECIFIED,
- window_rect.left, window_rect.top,
- window_rect.right - window_rect.left,
- window_rect.bottom - window_rect.top,
- SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW));
-
- GDK_NOTE (EVENTS, g_print (" ... set window position\n"));
-
- return;
- }
-
- /* Don't move iconic windows */
- /* TODO: use SetWindowPlacement() to change non-minimized window position */
-}
-
-static gboolean
-gdk_win32_surface_begin_paint (GdkSurface *window)
-{
- GdkSurfaceImplWin32 *impl;
- RECT window_rect;
-
- if (window == NULL || GDK_SURFACE_DESTROYED (window))
- return TRUE;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- /* Layered windows are moved *after* repaint.
- * We supply our own surface, return FALSE to make GDK use it.
- */
- if (impl->layered)
- return FALSE;
-
- /* FIXME: Possibly remove the following lines when we transition to GL
- * drawing fully. This will probably mean that we won't
- * be able to use layered windows, as layered windows seem
- * to support only up to OpenGL 1.1, which is not enough for our
- * needs here.
- */
-
- /* Non-GL windows are moved *after* repaint.
- * We don't supply our own surface, return TRUE to make GDK create
- * one by itself.
- *//*
- if (!window->current_paint.use_gl)
- return TRUE;*/
-
- /* GL windows are moved *before* repaint (otherwise
- * repainting doesn't work), but if there's no move queued up,
- * return immediately. Doesn't matter what we return, GDK
- * will create a surface anyway, as if we returned TRUE.
- */
- if (!impl->drag_move_resize_context.native_move_resize_pending)
- return TRUE;
-
- impl->drag_move_resize_context.native_move_resize_pending = FALSE;
-
- /* Get the position/size of the window that GDK wants,
- * apply it.
- */
- gdk_win32_surface_get_queued_window_rect (window, &window_rect);
- gdk_win32_surface_apply_queued_move_resize (window, window_rect);
-
- return TRUE;
-}
-
-static void
-gdk_win32_surface_end_paint (GdkSurface *window)
-{
- /* FIXME: Possibly make gdk_win32_surface_end_paint() a
- * no-op stub, like what is done in Wayland, as
- * the items here rely on layered window usage,
- * when we transition to full GL drawing, as
- * layered windows do not support enough GL
- * for our needs here
- */
- GdkSurfaceImplWin32 *impl;
- RECT window_rect;
- HDC hdc;
- POINT window_position;
- SIZE window_size;
- POINT source_point;
- BLENDFUNCTION blender;
- cairo_t *cr;
-
- if (window == NULL || GDK_SURFACE_DESTROYED (window))
- return;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- /* GL windows are moved *before* repaint */
- /*if (window->current_paint.use_gl)
- return;*/
-
- /* No move/resize is queued up, and we don't need to update
- * the contents of a layered window, so return immediately.
- */
- if (!impl->layered &&
- !impl->drag_move_resize_context.native_move_resize_pending)
- return;
-
- impl->drag_move_resize_context.native_move_resize_pending = FALSE;
-
- /* Get the position/size of the window that GDK wants. */
- gdk_win32_surface_get_queued_window_rect (window, &window_rect);
-
- if (!impl->layered)
- {
- gdk_win32_surface_apply_queued_move_resize (window, window_rect);
-
- return;
- }
-
- window_position.x = window_rect.left;
- window_position.y = window_rect.top;
-
- window_size.cx = window_rect.right - window_rect.left;
- window_size.cy = window_rect.bottom - window_rect.top;
-
- cairo_surface_flush (impl->cairo_surface);
-
- /* we always draw in the top-left corner of the surface */
- source_point.x = source_point.y = 0;
-
- blender.BlendOp = AC_SRC_OVER;
- blender.BlendFlags = 0;
- blender.AlphaFormat = AC_SRC_ALPHA;
- blender.SourceConstantAlpha = impl->layered_opacity * 255;
-
- /* Update cache surface contents */
- cr = cairo_create (impl->cache_surface);
-
- cairo_set_source_surface (cr, window->current_paint.surface, 0, 0);
- gdk_cairo_region (cr, window->current_paint.region);
- cairo_clip (cr);
-
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint (cr);
-
- cairo_destroy (cr);
-
- cairo_surface_flush (impl->cache_surface);
- hdc = cairo_win32_surface_get_dc (impl->cache_surface);
-
- /* Don't use UpdateLayeredWindow on minimized windows */
- if (IsIconic (GDK_SURFACE_HWND (window)))
- {
- gdk_win32_surface_apply_queued_move_resize (window, window_rect);
-
- return;
- }
-
- /* Move, resize and redraw layered window in one call */
- API_CALL (UpdateLayeredWindow, (GDK_SURFACE_HWND (window), NULL,
- &window_position, &window_size,
- hdc, &source_point,
- 0, &blender, ULW_ALPHA));
-}
-
-void
-_gdk_win32_adjust_client_rect (GdkSurface *window,
- RECT *rect)
-{
- LONG style, exstyle;
-
- style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
- exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
- API_CALL (AdjustWindowRectEx, (rect, style, FALSE, exstyle));
-}
-
-gboolean
-_gdk_win32_surface_enable_transparency (GdkSurface *window)
-{
- GdkSurfaceImplWin32 *impl;
- DWM_BLURBEHIND blur_behind;
- HRGN empty_region;
- HRESULT call_result;
- HWND parent, thiswindow;
-
- if (window == NULL || GDK_SURFACE_HWND (window) == NULL)
- return FALSE;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- /* layered windows don't need blurbehind for transparency */
- if (impl->layered)
- return TRUE;
-
- if (!gdk_display_is_composited (gdk_surface_get_display (window)))
- return FALSE;
-
- thiswindow = GDK_SURFACE_HWND (window);
-
- /* Blurbehind only works on toplevel windows */
- parent = GetAncestor (thiswindow, GA_PARENT);
- if (!(GetWindowLong (thiswindow, GWL_STYLE) & WS_POPUP) &&
- (parent == NULL || parent != GetDesktopWindow ()))
- return FALSE;
-
- empty_region = CreateRectRgn (0, 0, -1, -1);
-
- if (empty_region == NULL)
- return FALSE;
-
- memset (&blur_behind, 0, sizeof (blur_behind));
- blur_behind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
- blur_behind.hRgnBlur = empty_region;
- blur_behind.fEnable = TRUE;
- call_result = DwmEnableBlurBehindWindow (thiswindow, &blur_behind);
-
- if (!SUCCEEDED (call_result))
- g_warning ("%s: %s (%p) failed: %" G_GINT32_MODIFIER "x",
- G_STRLOC, "DwmEnableBlurBehindWindow", thiswindow, (guint32) call_result);
-
- DeleteObject (empty_region);
-
- return SUCCEEDED (call_result);
-}
-
-static const gchar *
-get_default_title (void)
-{
- const char *title;
- title = g_get_application_name ();
- if (!title)
- title = g_get_prgname ();
-
- return title;
-}
-
-/* RegisterGdkClass
- * is a wrapper function for RegisterWindowClassEx.
- * It creates at least one unique class for every
- * GdkSurfaceType. If support for single window-specific icons
- * is ever needed (e.g Dialog specific), every such window should
- * get its own class
- */
-static ATOM
-RegisterGdkClass (GdkSurfaceType wtype, GdkSurfaceTypeHint wtype_hint)
-{
- static ATOM klassTOPLEVEL = 0;
- static ATOM klassCHILD = 0;
- static ATOM klassTEMP = 0;
- static ATOM klassTEMPSHADOW = 0;
- static HICON hAppIcon = NULL;
- static HICON hAppIconSm = NULL;
- static WNDCLASSEXW wcl;
- ATOM klass = 0;
-
- wcl.cbSize = sizeof (WNDCLASSEX);
- wcl.style = 0; /* DON'T set CS_<H,V>REDRAW. It causes total redraw
- * on WM_SIZE and WM_MOVE. Flicker, Performance!
- */
- wcl.lpfnWndProc = _gdk_win32_surface_procedure;
- wcl.cbClsExtra = 0;
- wcl.cbWndExtra = 0;
- wcl.hInstance = _gdk_app_hmodule;
- wcl.hIcon = 0;
- wcl.hIconSm = 0;
-
- /* initialize once! */
- if (0 == hAppIcon && 0 == hAppIconSm)
- {
- gchar sLoc [MAX_PATH+1];
-
- if (0 != GetModuleFileName (_gdk_app_hmodule, sLoc, MAX_PATH))
- {
- ExtractIconEx (sLoc, 0, &hAppIcon, &hAppIconSm, 1);
-
- if (0 == hAppIcon && 0 == hAppIconSm)
- {
- if (0 != GetModuleFileName (_gdk_dll_hinstance, sLoc, MAX_PATH))
- {
- ExtractIconEx (sLoc, 0, &hAppIcon, &hAppIconSm, 1);
- }
- }
- }
-
- if (0 == hAppIcon && 0 == hAppIconSm)
- {
- hAppIcon = LoadImage (NULL, IDI_APPLICATION, IMAGE_ICON,
- GetSystemMetrics (SM_CXICON),
- GetSystemMetrics (SM_CYICON), 0);
- hAppIconSm = LoadImage (NULL, IDI_APPLICATION, IMAGE_ICON,
- GetSystemMetrics (SM_CXSMICON),
- GetSystemMetrics (SM_CYSMICON), 0);
- }
- }
-
- if (0 == hAppIcon)
- hAppIcon = hAppIconSm;
- else if (0 == hAppIconSm)
- hAppIconSm = hAppIcon;
-
- wcl.lpszMenuName = NULL;
-
- /* initialize once per class */
- /*
- * HB: Setting the background brush leads to flicker, because we
- * don't get asked how to clear the background. This is not what
- * we want, at least not for input_only windows ...
- */
-#define ONCE_PER_CLASS() \
- wcl.hIcon = CopyIcon (hAppIcon); \
- wcl.hIconSm = CopyIcon (hAppIconSm); \
- wcl.hbrBackground = NULL; \
- wcl.hCursor = LoadCursor (NULL, IDC_ARROW);
-
- switch (wtype)
- {
- case GDK_SURFACE_TOPLEVEL:
- /* MSDN: CS_OWNDC is needed for OpenGL contexts */
- wcl.style |= CS_OWNDC;
- if (0 == klassTOPLEVEL)
- {
- wcl.lpszClassName = L"gdkWindowToplevel";
-
- ONCE_PER_CLASS ();
- klassTOPLEVEL = RegisterClassExW (&wcl);
- }
- klass = klassTOPLEVEL;
- break;
-
- case GDK_SURFACE_TEMP:
- if ((wtype_hint == GDK_SURFACE_TYPE_HINT_MENU) ||
- (wtype_hint == GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU) ||
- (wtype_hint == GDK_SURFACE_TYPE_HINT_POPUP_MENU))
- {
- if (klassTEMPSHADOW == 0)
- {
- wcl.lpszClassName = L"gdkWindowTempShadow";
- wcl.style |= CS_SAVEBITS;
- wcl.style |= 0x00020000; /* CS_DROPSHADOW */
-
- ONCE_PER_CLASS ();
- klassTEMPSHADOW = RegisterClassExW (&wcl);
- }
-
- klass = klassTEMPSHADOW;
- }
- else
- {
- if (klassTEMP == 0)
- {
- wcl.lpszClassName = L"gdkWindowTemp";
- wcl.style |= CS_SAVEBITS;
- ONCE_PER_CLASS ();
- klassTEMP = RegisterClassExW (&wcl);
- }
-
- klass = klassTEMP;
- }
- break;
-
- case GDK_SURFACE_CHILD:
- default:
- g_assert_not_reached ();
- break;
- }
-
- if (klass == 0)
- {
- WIN32_API_FAILED ("RegisterClassExW");
- g_error ("That is a fatal error");
- }
- return klass;
-}
-
-/*
- * Create native windows.
- *
- * With the default Gdk the created windows are mostly toplevel windows.
- *
- * Placement of the window is derived from the passed in window,
- * except for toplevel window where OS/Window Manager placement
- * is used.
- *
- * From attributes the only things used is: colormap, title,
- * wmclass and type_hint. [1]. We are checking redundant information
- * and complain if that changes, which would break this implementation
- * again.
- *
- * [1] http://mail.gnome.org/archives/gtk-devel-list/2010-August/msg00214.html
- */
-void
-_gdk_win32_display_create_window_impl (GdkDisplay *display,
- GdkSurface *window,
- GdkSurface *real_parent,
- GdkEventMask event_mask,
- GdkSurfaceAttr *attributes)
-{
- HWND hwndNew;
- HANDLE hparent;
- ATOM klass = 0;
- DWORD dwStyle = 0, dwExStyle;
- RECT rect;
- GdkSurfaceImplWin32 *impl;
- GdkWin32Display *display_win32;
- const gchar *title;
- wchar_t *wtitle;
- gint window_width, window_height;
- gint offset_x = 0, offset_y = 0;
- gint x, y, real_x = 0, real_y = 0;
-
- g_return_if_fail (display == _gdk_display);
-
- GDK_NOTE (MISC,
- g_print ("_gdk_surface_impl_new: %s %s\n", (window->window_type == GDK_SURFACE_TOPLEVEL ? "TOPLEVEL" :
- (window->window_type == GDK_SURFACE_TEMP ? "TEMP" : "???")),
- (attributes->wclass == GDK_INPUT_OUTPUT ? "" : "input-only")));
-
- hparent = (real_parent != NULL) ? GDK_SURFACE_HWND (real_parent) : NULL;
-
- impl = g_object_new (GDK_TYPE_SURFACE_IMPL_WIN32, NULL);
- impl->wrapper = GDK_SURFACE (window);
- window->impl = GDK_SURFACE_IMPL (impl);
-
- impl->layered = FALSE;
- impl->layered_opacity = 1.0;
-
- display_win32 = GDK_WIN32_DISPLAY (display);
- impl->window_scale = _gdk_win32_display_get_monitor_scale_factor (display_win32, NULL, NULL, NULL);
- impl->unscaled_width = window->width * impl->window_scale;
- impl->unscaled_height = window->height * impl->window_scale;
-
- if (!window->input_only)
- {
- dwExStyle = 0;
- }
- else
- {
- /* I very much doubt using WS_EX_TRANSPARENT actually
- * corresponds to how X11 InputOnly windows work, but it appears
- * to work well enough for the actual use cases in gtk.
- */
- dwExStyle = WS_EX_TRANSPARENT;
- GDK_NOTE (MISC, g_print ("... GDK_INPUT_ONLY\n"));
- }
-
- switch (window->window_type)
- {
- case GDK_SURFACE_TOPLEVEL:
- if (window->parent)
- {
- /* The common code warns for this case. */
- hparent = GetDesktopWindow ();
- }
- /* Children of foreign windows aren't toplevel windows */
- if (real_parent != NULL && GDK_SURFACE_TYPE (real_parent) == GDK_SURFACE_FOREIGN)
- {
- dwStyle = WS_CHILDWINDOW | WS_CLIPCHILDREN;
- }
- else
- {
- /* MSDN: We need WS_CLIPCHILDREN and WS_CLIPSIBLINGS for GL Context Creation */
- if (window->window_type == GDK_SURFACE_TOPLEVEL)
- dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
- else
- dwStyle = WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_CLIPCHILDREN;
-
- offset_x = _gdk_offset_x;
- offset_y = _gdk_offset_y;
- }
- break;
-
- case GDK_SURFACE_TEMP:
- /* A temp window is not necessarily a top level window */
- dwStyle = real_parent == NULL ? WS_POPUP : WS_CHILDWINDOW;
- dwStyle |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
- dwExStyle |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
- offset_x = _gdk_offset_x;
- offset_y = _gdk_offset_y;
- break;
-
-
- case GDK_SURFACE_CHILD:
- default:
- g_assert_not_reached ();
- }
-
- rect.left = window->x * impl->window_scale;
- rect.top = window->y * impl->window_scale;
- rect.right = rect.left + window->width * impl->window_scale;
- rect.bottom = rect.top + window->height * impl->window_scale;
-
- AdjustWindowRectEx (&rect, dwStyle, FALSE, dwExStyle);
-
- real_x = (window->x - offset_x) * impl->window_scale;
- real_y = (window->y - offset_y) * impl->window_scale;
-
- if (window->window_type == GDK_SURFACE_TOPLEVEL)
- {
- /* We initially place it at default so that we can get the
- default window positioning if we want */
- x = y = CW_USEDEFAULT;
- }
- else
- {
- /* TEMP, FOREIGN: Put these where requested */
- x = real_x;
- y = real_y;
- }
-
- window_width = rect.right - rect.left;
- window_height = rect.bottom - rect.top;
-
- title = get_default_title ();
- if (!title || !*title)
- title = "";
-
- impl->native_event_mask = GDK_STRUCTURE_MASK | event_mask;
-
- if (impl->type_hint == GDK_SURFACE_TYPE_HINT_UTILITY)
- dwExStyle |= WS_EX_TOOLWINDOW;
-
- /* WS_EX_TRANSPARENT means "try draw this window last, and ignore input".
- * It's the last part we're after. We don't want DND indicator to accept
- * input, because that will make it a potential drop target, and if it's
- * under the mouse cursor, this will kill any DND.
- */
- if (impl->type_hint == GDK_SURFACE_TYPE_HINT_DND)
- dwExStyle |= WS_EX_TRANSPARENT;
-
- klass = RegisterGdkClass (window->window_type, impl->type_hint);
-
- wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
-
- hwndNew = CreateWindowExW (dwExStyle,
- MAKEINTRESOURCEW (klass),
- wtitle,
- dwStyle,
- x,
- y,
- window_width, window_height,
- hparent,
- NULL,
- _gdk_app_hmodule,
- window);
- if (GDK_SURFACE_HWND (window) != hwndNew)
- {
- g_warning ("gdk_surface_new: gdk_event_translate::WM_CREATE (%p, %p) HWND mismatch.",
- GDK_SURFACE_HWND (window),
- hwndNew);
-
- /* HB: IHMO due to a race condition the handle was increased by
- * one, which causes much trouble. Because I can't find the
- * real bug, try to workaround it ...
- * To reproduce: compile with MSVC 5, DEBUG=1
- */
-# if 0
- gdk_win32_handle_table_remove (GDK_SURFACE_HWND (window));
- GDK_SURFACE_HWND (window) = hwndNew;
- gdk_win32_handle_table_insert (&GDK_SURFACE_HWND (window), window);
-# else
- /* the old behaviour, but with warning */
- impl->handle = hwndNew;
-# endif
-
- }
-
- GetWindowRect (GDK_SURFACE_HWND (window), &rect);
- impl->initial_x = rect.left;
- impl->initial_y = rect.top;
-
- /* Now we know the initial position, move to actually specified position */
- if (real_x != x || real_y != y)
- {
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- SWP_NOZORDER_SPECIFIED,
- real_x, real_y, 0, 0,
- SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
- }
-
- g_object_ref (window);
- gdk_win32_handle_table_insert (&GDK_SURFACE_HWND (window), window);
-
- GDK_NOTE (MISC, g_print ("... \"%s\" %dx%d@%+d%+d %p = %p\n",
- title,
- window_width, window_height,
- window->x - offset_x,
- window->y - offset_y,
- hparent,
- GDK_SURFACE_HWND (window)));
-
- /* Add window handle to title */
- GDK_NOTE (MISC_OR_EVENTS, gdk_surface_set_title (window, title));
-
- g_free (wtitle);
-
- if (impl->handle == NULL)
- {
- WIN32_API_FAILED ("CreateWindowExW");
- g_object_unref (window);
- return;
- }
-
-// if (!from_set_skip_taskbar_hint && window->window_type == GDK_SURFACE_TEMP)
-// gdk_surface_set_skip_taskbar_hint (window, TRUE);
-
- _gdk_win32_surface_enable_transparency (window);
-}
-
-GdkSurface *
-gdk_win32_surface_foreign_new_for_display (GdkDisplay *display,
- HWND anid)
-{
- GdkSurface *window;
- GdkSurfaceImplWin32 *impl;
-
- HANDLE parent;
- RECT rect;
- POINT point;
-
- if ((window = gdk_win32_surface_lookup_for_display (display, anid)) != NULL)
- return g_object_ref (window);
-
- window = _gdk_display_create_window (display);
- window->impl = g_object_new (GDK_TYPE_SURFACE_IMPL_WIN32, NULL);
- window->impl_window = window;
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- impl->wrapper = window;
- parent = GetParent (anid);
-
- /* Always treat foreigns as toplevels */
- window->parent = NULL;
-
- GetClientRect ((HWND) anid, &rect);
- point.x = rect.left;
- point.y = rect.right;
- ClientToScreen ((HWND) anid, &point);
- if (parent != GetDesktopWindow ())
- ScreenToClient (parent, &point);
- window->x = point.x / impl->window_scale;
- window->y = point.y / impl->window_scale;
- impl->unscaled_width = rect.right - rect.left;
- impl->unscaled_height = rect.bottom - rect.top;
- window->width = (impl->unscaled_width + impl->window_scale - 1) / impl->window_scale;
- window->height = (impl->unscaled_height + impl->window_scale - 1) / impl->window_scale;
- window->window_type = GDK_SURFACE_FOREIGN;
- window->destroyed = FALSE;
- window->event_mask = GDK_ALL_EVENTS_MASK; /* XXX */
- if (IsWindowVisible ((HWND) anid))
- window->state &= (~GDK_SURFACE_STATE_WITHDRAWN);
- else
- window->state |= GDK_SURFACE_STATE_WITHDRAWN;
- if (GetWindowLong ((HWND)anid, GWL_EXSTYLE) & WS_EX_TOPMOST)
- window->state |= GDK_SURFACE_STATE_ABOVE;
- else
- window->state &= (~GDK_SURFACE_STATE_ABOVE);
- window->state &= (~GDK_SURFACE_STATE_BELOW);
- window->viewable = TRUE;
-
- GDK_SURFACE_HWND (window) = anid;
-
- g_object_ref (window);
- gdk_win32_handle_table_insert (&GDK_SURFACE_HWND (window), window);
-
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_foreign_new_for_display: %p: %s@%+d%+d\n",
- (HWND) anid,
- _gdk_win32_surface_description (window),
- window->x, window->y));
-
- return window;
-}
-
-static void
-gdk_win32_surface_destroy (GdkSurface *window,
- gboolean recursing,
- gboolean foreign_destroy)
-{
- GdkSurfaceImplWin32 *window_impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- GSList *tmp;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_destroy: %p\n",
- GDK_SURFACE_HWND (window)));
-
- /* Remove ourself from the modal stack */
- _gdk_remove_modal_window (window);
-
- /* Remove all our transient children */
- tmp = window_impl->transient_children;
- while (tmp != NULL)
- {
- GdkSurface *child = tmp->data;
- GdkSurfaceImplWin32 *child_impl = GDK_SURFACE_IMPL_WIN32 (GDK_SURFACE (child)->impl);
-
- child_impl->transient_owner = NULL;
- tmp = tmp->next;
- }
- g_slist_free (window_impl->transient_children);
- window_impl->transient_children = NULL;
-
- /* Remove ourself from our transient owner */
- if (window_impl->transient_owner != NULL)
- {
- gdk_surface_set_transient_for (window, NULL);
- }
-
- if (!recursing && !foreign_destroy)
- {
- window->destroyed = TRUE;
- DestroyWindow (GDK_SURFACE_HWND (window));
- }
-}
-
-/* This function is called when the window really gone.
- */
-static void
-gdk_win32_surface_destroy_notify (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- GDK_NOTE (EVENTS,
- g_print ("gdk_surface_destroy_notify: %p%s\n",
- GDK_SURFACE_HWND (window),
- (GDK_SURFACE_DESTROYED (window) ? " (destroyed)" : "")));
-
- if (!GDK_SURFACE_DESTROYED (window))
- {
- if (GDK_SURFACE_TYPE (window) != GDK_SURFACE_FOREIGN)
- g_warning ("window %p unexpectedly destroyed",
- GDK_SURFACE_HWND (window));
-
- _gdk_surface_destroy (window, TRUE);
- }
-
- gdk_win32_handle_table_remove (GDK_SURFACE_HWND (window));
- g_object_unref (window);
-}
-
-static void
-get_outer_rect (GdkSurface *window,
- gint width,
- gint height,
- RECT *rect)
-{
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- rect->left = rect->top = 0;
- rect->right = width * impl->window_scale;
- rect->bottom = height * impl->window_scale;
-
- _gdk_win32_adjust_client_rect (window, rect);
-}
-
-static void
-adjust_for_gravity_hints (GdkSurface *window,
- RECT *outer_rect,
- gint *x,
- gint *y)
-{
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- if (impl->hint_flags & GDK_HINT_WIN_GRAVITY)
- {
-#ifdef G_ENABLE_DEBUG
- gint orig_x = *x, orig_y = *y;
-#endif
-
- switch (impl->hints.win_gravity)
- {
- case GDK_GRAVITY_NORTH:
- case GDK_GRAVITY_CENTER:
- case GDK_GRAVITY_SOUTH:
- *x -= (outer_rect->right - outer_rect->left / 2) / impl->window_scale;
- *x += window->width / 2;
- break;
-
- case GDK_GRAVITY_SOUTH_EAST:
- case GDK_GRAVITY_EAST:
- case GDK_GRAVITY_NORTH_EAST:
- *x -= (outer_rect->right - outer_rect->left) / impl->window_scale;
- *x += window->width;
- break;
-
- case GDK_GRAVITY_STATIC:
- *x += outer_rect->left / impl->window_scale;
- break;
-
- default:
- break;
- }
-
- switch (impl->hints.win_gravity)
- {
- case GDK_GRAVITY_WEST:
- case GDK_GRAVITY_CENTER:
- case GDK_GRAVITY_EAST:
- *y -= ((outer_rect->bottom - outer_rect->top) / 2) / impl->window_scale;
- *y += window->height / 2;
- break;
-
- case GDK_GRAVITY_SOUTH_WEST:
- case GDK_GRAVITY_SOUTH:
- case GDK_GRAVITY_SOUTH_EAST:
- *y -= (outer_rect->bottom - outer_rect->top) / impl->window_scale;
- *y += window->height;
- break;
-
- case GDK_GRAVITY_STATIC:
- *y += outer_rect->top * impl->window_scale;
- break;
-
- default:
- break;
- }
- GDK_NOTE (MISC,
- (orig_x != *x || orig_y != *y) ?
- g_print ("adjust_for_gravity_hints: x: %d->%d, y: %d->%d\n",
- orig_x, *x, orig_y, *y)
- : (void) 0);
- }
-}
-
-static void
-show_window_internal (GdkSurface *window,
- gboolean already_mapped,
- gboolean deiconify)
-{
- GdkSurfaceImplWin32 *window_impl;
- gboolean focus_on_map = FALSE;
- DWORD exstyle;
-
- if (window->destroyed)
- return;
-
- GDK_NOTE (MISC, g_print ("show_window_internal: %p: %s%s\n",
- GDK_SURFACE_HWND (window),
- _gdk_win32_surface_state_to_string (window->state),
- (deiconify ? " deiconify" : "")));
-
- /* If asked to show (not deiconify) an withdrawn and iconified
- * window, do that.
- */
- if (!deiconify &&
- !already_mapped &&
- (window->state & GDK_SURFACE_STATE_ICONIFIED))
- {
- GtkShowWindow (window, SW_SHOWMINNOACTIVE);
- return;
- }
-
- /* If asked to just show an iconified window, do nothing. */
- if (!deiconify && (window->state & GDK_SURFACE_STATE_ICONIFIED))
- return;
-
- /* If asked to deiconify an already noniconified window, do
- * nothing. (Especially, don't cause the window to rise and
- * activate. There are different calls for that.)
- */
- if (deiconify && !(window->state & GDK_SURFACE_STATE_ICONIFIED))
- return;
-
- /* If asked to show (but not raise) a window that is already
- * visible, do nothing.
- */
- if (!deiconify && !already_mapped && IsWindowVisible (GDK_SURFACE_HWND (window)))
- return;
-
- /* Other cases */
-
- if (!already_mapped)
- focus_on_map = window->focus_on_map;
-
- exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
-
- /* Use SetWindowPos to show transparent windows so automatic redraws
- * in other windows can be suppressed.
- */
- if (exstyle & WS_EX_TRANSPARENT)
- {
- UINT flags = SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
-
- if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP || !focus_on_map)
- flags |= SWP_NOACTIVATE;
-
- SetWindowPos (GDK_SURFACE_HWND (window),
- SWP_NOZORDER_SPECIFIED, 0, 0, 0, 0, flags);
-
- return;
- }
-
- /* For initial map of "normal" windows we want to emulate WM window
- * positioning behaviour, which means:
- * + Use user specified position if GDK_HINT_POS or GDK_HINT_USER_POS
- * otherwise:
- * + default to the initial CW_USEDEFAULT placement,
- * no matter if the user moved the window before showing it.
- * + Certain window types and hints have more elaborate positioning
- * schemes.
- */
- window_impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- if (!already_mapped &&
- GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL &&
- (window_impl->hint_flags & (GDK_HINT_POS | GDK_HINT_USER_POS)) == 0)
- {
- gboolean center = FALSE;
- RECT window_rect, center_on_rect;
- int x, y;
-
- x = window_impl->initial_x;
- y = window_impl->initial_y;
-
- if (window_impl->type_hint == GDK_SURFACE_TYPE_HINT_SPLASHSCREEN)
- {
- HMONITOR monitor;
- MONITORINFO mi;
-
- monitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
- mi.cbSize = sizeof (mi);
- if (monitor && GetMonitorInfo (monitor, &mi))
- center_on_rect = mi.rcMonitor;
- else
- {
- center_on_rect.left = 0;
- center_on_rect.top = 0;
- center_on_rect.right = GetSystemMetrics (SM_CXSCREEN);
- center_on_rect.bottom = GetSystemMetrics (SM_CYSCREEN);
- }
- center = TRUE;
- }
- else if (window_impl->transient_owner != NULL &&
- GDK_SURFACE_IS_MAPPED (window_impl->transient_owner))
- {
- GdkSurface *owner = window_impl->transient_owner;
- /* Center on transient parent */
- center_on_rect.left = (owner->x - _gdk_offset_x) * window_impl->window_scale;
- center_on_rect.top = (owner->y - _gdk_offset_y) * window_impl->window_scale;
- center_on_rect.right = center_on_rect.left + owner->width * window_impl->window_scale;
- center_on_rect.bottom = center_on_rect.top + owner->height * window_impl->window_scale;
-
- _gdk_win32_adjust_client_rect (GDK_SURFACE (owner), ¢er_on_rect);
- center = TRUE;
- }
-
- if (center)
- {
- window_rect.left = 0;
- window_rect.top = 0;
- window_rect.right = window->width * window_impl->window_scale;
- window_rect.bottom = window->height * window_impl->window_scale;
- _gdk_win32_adjust_client_rect (window, &window_rect);
-
- x = center_on_rect.left + ((center_on_rect.right - center_on_rect.left) - (window_rect.right - window_rect.left)) / 2;
- y = center_on_rect.top + ((center_on_rect.bottom - center_on_rect.top) - (window_rect.bottom - window_rect.top)) / 2;
- }
-
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- SWP_NOZORDER_SPECIFIED,
- x, y, 0, 0,
- SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
- }
-
- if (!already_mapped &&
- GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL)
- {
- /* Ensure new windows are fully onscreen */
- RECT window_rect;
- HMONITOR monitor;
- MONITORINFO mi;
- int x, y;
-
- GetWindowRect (GDK_SURFACE_HWND (window), &window_rect);
-
- monitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
- mi.cbSize = sizeof (mi);
- if (monitor && GetMonitorInfo (monitor, &mi))
- {
- x = window_rect.left;
- y = window_rect.top;
-
- if (window_rect.right > mi.rcWork.right)
- {
- window_rect.left -= (window_rect.right - mi.rcWork.right);
- window_rect.right -= (window_rect.right - mi.rcWork.right);
- }
-
- if (window_rect.bottom > mi.rcWork.bottom)
- {
- window_rect.top -= (window_rect.bottom - mi.rcWork.bottom);
- window_rect.bottom -= (window_rect.bottom - mi.rcWork.bottom);
- }
-
- if (window_rect.left < mi.rcWork.left)
- {
- window_rect.right += (mi.rcWork.left - window_rect.left);
- window_rect.left += (mi.rcWork.left - window_rect.left);
- }
-
- if (window_rect.top < mi.rcWork.top)
- {
- window_rect.bottom += (mi.rcWork.top - window_rect.top);
- window_rect.top += (mi.rcWork.top - window_rect.top);
- }
-
- if (x != window_rect.left || y != window_rect.top)
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- SWP_NOZORDER_SPECIFIED,
- window_rect.left, window_rect.top, 0, 0,
- SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
- }
- }
-
-
- if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
- {
- gdk_surface_fullscreen (window);
- }
- else if (window->state & GDK_SURFACE_STATE_MAXIMIZED)
- {
- GtkShowWindow (window, SW_MAXIMIZE);
- }
- else if (window->state & GDK_SURFACE_STATE_ICONIFIED)
- {
- if (focus_on_map)
- GtkShowWindow (window, SW_RESTORE);
- else
- GtkShowWindow (window, SW_SHOWNOACTIVATE);
- }
- else if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP || !focus_on_map)
- {
- if (!IsWindowVisible (GDK_SURFACE_HWND (window)))
- GtkShowWindow (window, SW_SHOWNOACTIVATE);
- else
- GtkShowWindow (window, SW_SHOWNA);
- }
- else if (!IsWindowVisible (GDK_SURFACE_HWND (window)))
- {
- GtkShowWindow (window, SW_SHOWNORMAL);
- }
- else
- {
- GtkShowWindow (window, SW_SHOW);
- }
-
- /* Sync STATE_ABOVE to TOPMOST */
- if (GDK_SURFACE_TYPE (window) != GDK_SURFACE_TEMP &&
- (((window->state & GDK_SURFACE_STATE_ABOVE) &&
- !(exstyle & WS_EX_TOPMOST)) ||
- (!(window->state & GDK_SURFACE_STATE_ABOVE) &&
- (exstyle & WS_EX_TOPMOST))))
- {
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- (window->state & GDK_SURFACE_STATE_ABOVE)?HWND_TOPMOST:HWND_NOTOPMOST,
- 0, 0, 0, 0,
- SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
- }
-}
-
-static void
-gdk_win32_surface_show (GdkSurface *window,
- gboolean already_mapped)
-{
- show_window_internal (window, FALSE, FALSE);
-}
-
-static void
-gdk_win32_surface_hide (GdkSurface *window)
-{
- if (window->destroyed)
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_hide: %p: %s\n",
- GDK_SURFACE_HWND (window),
- _gdk_win32_surface_state_to_string (window->state)));
-
- if (GDK_SURFACE_IS_MAPPED (window))
- gdk_synthesize_window_state (window,
- 0,
- GDK_SURFACE_STATE_WITHDRAWN);
-
- _gdk_surface_clear_update_area (window);
-
- if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL)
- ShowOwnedPopups (GDK_SURFACE_HWND (window), FALSE);
-
- /* Use SetWindowPos to hide transparent windows so automatic redraws
- * in other windows can be suppressed.
- */
- if (GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE) & WS_EX_TRANSPARENT)
- {
- SetWindowPos (GDK_SURFACE_HWND (window), SWP_NOZORDER_SPECIFIED,
- 0, 0, 0, 0,
- SWP_HIDEWINDOW | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
- }
- else
- {
- GtkShowWindow (window, SW_HIDE);
- }
-}
-
-static void
-gdk_win32_surface_withdraw (GdkSurface *window)
-{
- if (window->destroyed)
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_withdraw: %p: %s\n",
- GDK_SURFACE_HWND (window),
- _gdk_win32_surface_state_to_string (window->state)));
-
- gdk_surface_hide (window); /* ??? */
-}
-
-static void
-gdk_win32_surface_move (GdkSurface *window,
- gint x, gint y)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_move: %p: %+d%+d\n",
- GDK_SURFACE_HWND (window), x, y));
-
- if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
- return;
-
- /* Don't check GDK_SURFACE_TYPE (window) == GDK_SURFACE_CHILD.
- * Foreign windows (another app's windows) might be children of our
- * windows! Especially in the case of gtkplug/socket.
- */
- if (GetAncestor (GDK_SURFACE_HWND (window), GA_PARENT) != GetDesktopWindow ())
- {
- _gdk_surface_move_resize_child (window, x, y, window->width, window->height);
- }
- else
- {
- RECT outer_rect;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- get_outer_rect (window, window->width, window->height, &outer_rect);
-
- adjust_for_gravity_hints (window, &outer_rect, &x, &y);
-
- GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,0,0,"
- "NOACTIVATE|NOSIZE|NOZORDER)\n",
- GDK_SURFACE_HWND (window),
- (x - _gdk_offset_x) * impl->window_scale,
- (y - _gdk_offset_y) * impl->window_scale));
-
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- SWP_NOZORDER_SPECIFIED,
- (x - _gdk_offset_x) * impl->window_scale,
- (y - _gdk_offset_y) * impl->window_scale,
- 0, 0,
- SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER));
- }
-}
-
-static void
-gdk_win32_surface_resize (GdkSurface *window,
- gint width, gint height)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (width < 1)
- width = 1;
- if (height < 1)
- height = 1;
-
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_resize: %p: %dx%d\n",
- GDK_SURFACE_HWND (window), width, height));
-
- if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
- return;
-
- if (GetAncestor (GDK_SURFACE_HWND (window), GA_PARENT) != GetDesktopWindow ())
- {
- _gdk_surface_move_resize_child (window, window->x, window->y, width, height);
- }
- else
- {
- RECT outer_rect;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- get_outer_rect (window, width, height, &outer_rect);
-
- GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,0,0,%ld,%ld,"
- "NOACTIVATE|NOMOVE|NOZORDER)\n",
- GDK_SURFACE_HWND (window),
- outer_rect.right - outer_rect.left,
- outer_rect.bottom - outer_rect.top));
-
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- SWP_NOZORDER_SPECIFIED,
- 0, 0,
- outer_rect.right - outer_rect.left,
- outer_rect.bottom - outer_rect.top,
- SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER));
- window->resize_count += 1;
- }
-}
-
-static void
-gdk_win32_surface_move_resize_internal (GdkSurface *window,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (width < 1)
- width = 1;
- if (height < 1)
- height = 1;
-
- if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_move_resize: %p: %dx%d@%+d%+d\n",
- GDK_SURFACE_HWND (window),
- width, height, x, y));
-
- if (GetAncestor (GDK_SURFACE_HWND (window), GA_PARENT) != GetDesktopWindow ())
- {
- _gdk_surface_move_resize_child (window, x, y, width, height);
- }
- else
- {
- RECT outer_rect;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- get_outer_rect (window, width, height, &outer_rect);
-
- adjust_for_gravity_hints (window, &outer_rect, &x, &y);
-
- GDK_NOTE (MISC, g_print ("... SetWindowPos(%p,NULL,%d,%d,%ld,%ld,"
- "NOACTIVATE|NOZORDER)\n",
- GDK_SURFACE_HWND (window),
- (x - _gdk_offset_x) * impl->window_scale,
- (y - _gdk_offset_y) * impl->window_scale,
- outer_rect.right - outer_rect.left,
- outer_rect.bottom - outer_rect.top));
-
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- SWP_NOZORDER_SPECIFIED,
- (x - _gdk_offset_x) * impl->window_scale,
- (y - _gdk_offset_y) * impl->window_scale,
- outer_rect.right - outer_rect.left,
- outer_rect.bottom - outer_rect.top,
- SWP_NOACTIVATE | SWP_NOZORDER));
- }
-}
-
-static void
-gdk_win32_surface_move_resize (GdkSurface *window,
- gboolean with_move,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- GdkSurfaceImplWin32 *window_impl;
-
- window_impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- window_impl->inhibit_configure = TRUE;
-
- /* We ignore changes to the window being moved or resized by the
- user, as we don't want to fight the user */
- if (GDK_SURFACE_HWND (window) == _modal_move_resize_window)
- goto out;
-
- if (with_move && (width < 0 && height < 0))
- {
- gdk_win32_surface_move (window, x, y);
- }
- else
- {
- if (with_move)
- {
- gdk_win32_surface_move_resize_internal (window, x, y, width, height);
- }
- else
- {
- gdk_win32_surface_resize (window, width, height);
- }
- }
-
- out:
- window_impl->inhibit_configure = FALSE;
-
- if (WINDOW_IS_TOPLEVEL (window))
- _gdk_win32_emit_configure_event (window);
-}
-
-static void
-gdk_win32_surface_raise (GdkSurface *window)
-{
- if (!GDK_SURFACE_DESTROYED (window))
- {
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_raise: %p\n",
- GDK_SURFACE_HWND (window)));
-
- if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP)
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOPMOST,
- 0, 0, 0, 0,
- SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
- else if (window->accept_focus)
- /* Do not wrap this in an API_CALL macro as SetForegroundWindow might
- * fail when for example dragging a window belonging to a different
- * application at the time of a gtk_window_present() call due to focus
- * stealing prevention. */
- SetForegroundWindow (GDK_SURFACE_HWND (window));
- else
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOP,
- 0, 0, 0, 0,
- SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
- }
-}
-
-static void
-gdk_win32_surface_lower (GdkSurface *window)
-{
- if (!GDK_SURFACE_DESTROYED (window))
- {
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_lower: %p\n"
- "... SetWindowPos(%p,HWND_BOTTOM,0,0,0,0,"
- "NOACTIVATE|NOMOVE|NOSIZE)\n",
- GDK_SURFACE_HWND (window),
- GDK_SURFACE_HWND (window)));
-
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_BOTTOM,
- 0, 0, 0, 0,
- SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE));
- }
-}
-
-static void
-gdk_win32_surface_set_urgency_hint (GdkSurface *window,
- gboolean urgent)
-{
- FLASHWINFO flashwinfo;
- typedef BOOL (WINAPI *PFN_FlashWindowEx) (FLASHWINFO*);
- PFN_FlashWindowEx flashWindowEx = NULL;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- flashWindowEx = (PFN_FlashWindowEx) GetProcAddress (GetModuleHandle ("user32.dll"), "FlashWindowEx");
-
- if (flashWindowEx)
- {
- flashwinfo.cbSize = sizeof (flashwinfo);
- flashwinfo.hwnd = GDK_SURFACE_HWND (window);
- if (urgent)
- flashwinfo.dwFlags = FLASHW_ALL | FLASHW_TIMER;
- else
- flashwinfo.dwFlags = FLASHW_STOP;
- flashwinfo.uCount = 0;
- flashwinfo.dwTimeout = 0;
-
- flashWindowEx (&flashwinfo);
- }
- else
- {
- FlashWindow (GDK_SURFACE_HWND (window), urgent);
- }
-}
-
-static gboolean
-get_effective_window_decorations (GdkSurface *window,
- GdkWMDecoration *decoration)
-{
- GdkSurfaceImplWin32 *impl;
-
- impl = (GdkSurfaceImplWin32 *)window->impl;
-
- if (gdk_surface_get_decorations (window, decoration))
- return TRUE;
-
- if (window->window_type != GDK_SURFACE_TOPLEVEL)
- {
- return FALSE;
- }
-
- if ((impl->hint_flags & GDK_HINT_MIN_SIZE) &&
- (impl->hint_flags & GDK_HINT_MAX_SIZE) &&
- impl->hints.min_width == impl->hints.max_width &&
- impl->hints.min_height == impl->hints.max_height)
- {
- *decoration = GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MAXIMIZE;
-
- if (impl->type_hint == GDK_SURFACE_TYPE_HINT_DIALOG ||
- impl->type_hint == GDK_SURFACE_TYPE_HINT_MENU ||
- impl->type_hint == GDK_SURFACE_TYPE_HINT_TOOLBAR)
- {
- *decoration |= GDK_DECOR_MINIMIZE;
- }
- else if (impl->type_hint == GDK_SURFACE_TYPE_HINT_SPLASHSCREEN)
- {
- *decoration |= GDK_DECOR_MENU | GDK_DECOR_MINIMIZE;
- }
-
- return TRUE;
- }
- else if (impl->hint_flags & GDK_HINT_MAX_SIZE)
- {
- *decoration = GDK_DECOR_ALL | GDK_DECOR_MAXIMIZE;
- if (impl->type_hint == GDK_SURFACE_TYPE_HINT_DIALOG ||
- impl->type_hint == GDK_SURFACE_TYPE_HINT_MENU ||
- impl->type_hint == GDK_SURFACE_TYPE_HINT_TOOLBAR)
- {
- *decoration |= GDK_DECOR_MINIMIZE;
- }
-
- return TRUE;
- }
- else
- {
- switch (impl->type_hint)
- {
- case GDK_SURFACE_TYPE_HINT_DIALOG:
- *decoration = (GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
- return TRUE;
-
- case GDK_SURFACE_TYPE_HINT_MENU:
- *decoration = (GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
- return TRUE;
-
- case GDK_SURFACE_TYPE_HINT_TOOLBAR:
- case GDK_SURFACE_TYPE_HINT_UTILITY:
- gdk_surface_set_skip_taskbar_hint (window, TRUE);
- gdk_surface_set_skip_pager_hint (window, TRUE);
- *decoration = (GDK_DECOR_ALL | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
- return TRUE;
-
- case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
- *decoration = (GDK_DECOR_ALL | GDK_DECOR_RESIZEH | GDK_DECOR_MENU |
- GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE);
- return TRUE;
-
- case GDK_SURFACE_TYPE_HINT_DOCK:
- return FALSE;
-
- case GDK_SURFACE_TYPE_HINT_DESKTOP:
- return FALSE;
-
- default:
- /* Fall thru */
- case GDK_SURFACE_TYPE_HINT_NORMAL:
- *decoration = GDK_DECOR_ALL;
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-static void
-gdk_win32_surface_set_geometry_hints (GdkSurface *window,
- const GdkGeometry *geometry,
- GdkSurfaceHints geom_mask)
-{
- GdkSurfaceImplWin32 *impl;
- FullscreenInfo *fi;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_surface_set_geometry_hints: %p\n",
- GDK_SURFACE_HWND (window)));
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- fi = g_object_get_data (G_OBJECT (window), "fullscreen-info");
- if (fi)
- fi->hint_flags = geom_mask;
- else
- impl->hint_flags = geom_mask;
- impl->hints = *geometry;
-
- if (geom_mask & GDK_HINT_POS)
- {
- /* even the X11 mplementation doesn't care */
- }
-
- if (geom_mask & GDK_HINT_MIN_SIZE)
- {
- GDK_NOTE (MISC, g_print ("... MIN_SIZE: %dx%d\n",
- geometry->min_width, geometry->min_height));
- }
-
- if (geom_mask & GDK_HINT_MAX_SIZE)
- {
- GDK_NOTE (MISC, g_print ("... MAX_SIZE: %dx%d\n",
- geometry->max_width, geometry->max_height));
- }
-
- if (geom_mask & GDK_HINT_BASE_SIZE)
- {
- GDK_NOTE (MISC, g_print ("... BASE_SIZE: %dx%d\n",
- geometry->base_width, geometry->base_height));
- }
-
- if (geom_mask & GDK_HINT_RESIZE_INC)
- {
- GDK_NOTE (MISC, g_print ("... RESIZE_INC: (%d,%d)\n",
- geometry->width_inc, geometry->height_inc));
- }
-
- if (geom_mask & GDK_HINT_ASPECT)
- {
- GDK_NOTE (MISC, g_print ("... ASPECT: %g--%g\n",
- geometry->min_aspect, geometry->max_aspect));
- }
-
- if (geom_mask & GDK_HINT_WIN_GRAVITY)
- {
- GDK_NOTE (MISC, g_print ("... GRAVITY: %d\n", geometry->win_gravity));
- }
-
- _gdk_win32_surface_update_style_bits (window);
-}
-
-static void
-gdk_win32_surface_set_title (GdkSurface *window,
- const gchar *title)
-{
- wchar_t *wtitle;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (title != NULL);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- /* Empty window titles not allowed, so set it to just a period. */
- if (!title[0])
- title = ".";
-
- GDK_NOTE (MISC, g_print ("gdk_surface_set_title: %p: %s\n",
- GDK_SURFACE_HWND (window), title));
-
- GDK_NOTE (MISC_OR_EVENTS, title = g_strdup_printf ("%p %s", GDK_SURFACE_HWND (window), title));
-
- wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
- API_CALL (SetWindowTextW, (GDK_SURFACE_HWND (window), wtitle));
- g_free (wtitle);
-
- GDK_NOTE (MISC_OR_EVENTS, g_free ((char *) title));
-}
-
-static void
-gdk_win32_surface_set_role (GdkSurface *window,
- const gchar *role)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- GDK_NOTE (MISC, g_print ("gdk_surface_set_role: %p: %s\n",
- GDK_SURFACE_HWND (window),
- (role ? role : "NULL")));
- /* XXX */
-}
-
-static void
-gdk_win32_surface_set_transient_for (GdkSurface *window,
- GdkSurface *parent)
-{
- HWND window_id, parent_id;
- LONG_PTR old_ptr;
- DWORD w32_error;
- GdkSurfaceImplWin32 *window_impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- GdkSurfaceImplWin32 *parent_impl = NULL;
- GSList *item;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- window_id = GDK_SURFACE_HWND (window);
- parent_id = parent != NULL ? GDK_SURFACE_HWND (parent) : NULL;
-
- GDK_NOTE (MISC, g_print ("gdk_surface_set_transient_for: %p: %p\n", window_id, parent_id));
-
- if (GDK_SURFACE_DESTROYED (window) || (parent && GDK_SURFACE_DESTROYED (parent)))
- {
- if (GDK_SURFACE_DESTROYED (window))
- GDK_NOTE (MISC, g_print ("... destroyed!\n"));
- else
- GDK_NOTE (MISC, g_print ("... owner destroyed!\n"));
-
- return;
- }
-
- if (parent == NULL)
- {
- GdkSurfaceImplWin32 *trans_impl = GDK_SURFACE_IMPL_WIN32 (window_impl->transient_owner->impl);
- if (trans_impl->transient_children != NULL)
- {
- item = g_slist_find (trans_impl->transient_children, window);
- item->data = NULL;
- trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item);
- trans_impl->num_transients--;
-
- if (!trans_impl->num_transients)
- {
- trans_impl->transient_children = NULL;
- }
- }
- g_object_unref (G_OBJECT (window_impl->transient_owner));
- g_object_unref (G_OBJECT (window));
-
- window_impl->transient_owner = NULL;
- }
- else
- {
- parent_impl = GDK_SURFACE_IMPL_WIN32 (parent->impl);
-
- parent_impl->transient_children = g_slist_append (parent_impl->transient_children, window);
- g_object_ref (G_OBJECT (window));
- parent_impl->num_transients++;
- window_impl->transient_owner = parent;
- g_object_ref (G_OBJECT (parent));
- }
-
- SetLastError (0);
- old_ptr = GetWindowLongPtr (window_id, GWLP_HWNDPARENT);
- w32_error = GetLastError ();
-
- /* Don't re-set GWLP_HWNDPARENT to the same value */
- if ((HWND) old_ptr == parent_id && w32_error == NO_ERROR)
- return;
-
- /* Don't return if it failed, try SetWindowLongPtr() anyway */
- if (old_ptr == 0 && w32_error != NO_ERROR)
- WIN32_API_FAILED ("GetWindowLongPtr");
-
- /* This changes the *owner* of the window, despite the misleading
- * name. (Owner and parent are unrelated concepts.) At least that's
- * what people who seem to know what they talk about say on
- * USENET. Search on Google.
- */
- SetLastError (0);
- old_ptr = SetWindowLongPtr (window_id, GWLP_HWNDPARENT, (LONG_PTR) parent_id);
- w32_error = GetLastError ();
-
- if (old_ptr == 0 && w32_error != NO_ERROR)
- WIN32_API_FAILED ("SetWindowLongPtr");
-}
-
-void
-_gdk_push_modal_window (GdkSurface *window)
-{
- modal_window_stack = g_slist_prepend (modal_window_stack,
- window);
-}
-
-void
-_gdk_remove_modal_window (GdkSurface *window)
-{
- GSList *tmp;
-
- g_return_if_fail (window != NULL);
-
- /* It's possible to be NULL here if someone sets the modal hint of the window
- * to FALSE before a modal window stack has ever been created. */
- if (modal_window_stack == NULL)
- return;
-
- /* Find the requested window in the stack and remove it. Yeah, I realize this
- * means we're not a 'real stack', strictly speaking. Sue me. :) */
- tmp = g_slist_find (modal_window_stack, window);
- if (tmp != NULL)
- {
- modal_window_stack = g_slist_delete_link (modal_window_stack, tmp);
- }
-}
-
-gboolean
-_gdk_modal_blocked (GdkSurface *window)
-{
- GSList *l;
- gboolean found_any = FALSE;
-
- for (l = modal_window_stack; l != NULL; l = l->next)
- {
- GdkSurface *modal = l->data;
-
- if (modal == window)
- return FALSE;
-
- if (GDK_SURFACE_IS_MAPPED (modal))
- found_any = TRUE;
- }
-
- return found_any;
-}
-
-GdkSurface *
-_gdk_modal_current (void)
-{
- GSList *l;
-
- for (l = modal_window_stack; l != NULL; l = l->next)
- {
- GdkSurface *modal = l->data;
-
- if (GDK_SURFACE_IS_MAPPED (modal))
- return modal;
- }
-
- return NULL;
-}
-
-static void
-gdk_win32_surface_get_geometry (GdkSurface *window,
- gint *x,
- gint *y,
- gint *width,
- gint *height)
-{
- GdkDisplay *display;
- gboolean window_is_root;
-
- display = gdk_surface_get_display (window);
-
- if (!GDK_SURFACE_DESTROYED (window))
- {
- RECT rect;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- API_CALL (GetClientRect, (GDK_SURFACE_HWND (window), &rect));
-
- POINT pt;
- GdkSurface *parent = gdk_surface_get_parent (window);
-
- pt.x = rect.left;
- pt.y = rect.top;
- ClientToScreen (GDK_SURFACE_HWND (window), &pt);
- if (parent)
- ScreenToClient (GDK_SURFACE_HWND (parent), &pt);
- rect.left = pt.x;
- rect.top = pt.y;
-
- pt.x = rect.right;
- pt.y = rect.bottom;
- ClientToScreen (GDK_SURFACE_HWND (window), &pt);
- if (parent)
- ScreenToClient (GDK_SURFACE_HWND (parent), &pt);
- rect.right = pt.x;
- rect.bottom = pt.y;
-
- if (parent == NULL)
- {
- rect.left += _gdk_offset_x * impl->window_scale;
- rect.top += _gdk_offset_y * impl->window_scale;
- rect.right += _gdk_offset_x * impl->window_scale;
- rect.bottom += _gdk_offset_y * impl->window_scale;
- }
-
- if (x)
- *x = rect.left / impl->window_scale;
- if (y)
- *y = rect.top / impl->window_scale;
- if (width)
- *width = (rect.right - rect.left) / impl->window_scale;
- if (height)
- *height = (rect.bottom - rect.top) / impl->window_scale;
-
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_get_geometry: %p: %ldx%ld@%+ld%\n",
- GDK_SURFACE_HWND (window),
- (rect.right - rect.left) / impl->window_scale,
- (rect.bottom - rect.top) / impl->window_scale,
- rect.left, rect.top));
- }
-}
-
-static void
-gdk_win32_surface_get_root_coords (GdkSurface *window,
- gint x,
- gint y,
- gint *root_x,
- gint *root_y)
-{
- gint tx;
- gint ty;
- POINT pt;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- pt.x = x * impl->window_scale;
- pt.y = y * impl->window_scale;
- ClientToScreen (GDK_SURFACE_HWND (window), &pt);
- tx = pt.x;
- ty = pt.y;
-
- if (root_x)
- *root_x = (tx + _gdk_offset_x) / impl->window_scale;
- if (root_y)
- *root_y = (ty + _gdk_offset_y) / impl->window_scale;
-
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_get_root_coords: %p: %+d%+d %+d%+d\n",
- GDK_SURFACE_HWND (window),
- x * impl->window_scale,
- y * impl->window_scale,
- (tx + _gdk_offset_x) / impl->window_scale,
- (ty + _gdk_offset_y) / impl->window_scale));
-}
-
-static void
-gdk_win32_surface_restack_toplevel (GdkSurface *window,
- GdkSurface *sibling,
- gboolean above)
-{
- // ### TODO
-}
-
-static void
-gdk_win32_surface_get_frame_extents (GdkSurface *window,
- GdkRectangle *rect)
-{
- HWND hwnd;
- RECT r;
- GdkSurfaceImplWin32 *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (rect != NULL);
-
- rect->x = 0;
- rect->y = 0;
- rect->width = 1;
- rect->height = 1;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- /* FIXME: window is documented to be a toplevel GdkSurface, so is it really
- * necessary to walk its parent chain?
- */
- while (window->parent && window->parent->parent)
- window = window->parent;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- hwnd = GDK_SURFACE_HWND (window);
- API_CALL (GetWindowRect, (hwnd, &r));
-
- /* Initialize to real, unscaled size */
- rect->x = r.left + _gdk_offset_x * impl->window_scale;
- rect->y = r.top + _gdk_offset_y * impl->window_scale;
- rect->width = (r.right - r.left);
- rect->height = (r.bottom - r.top);
-
- /* Extend width and height to ensure that they cover the real size when de-scaled,
- * and replace everyting with scaled values
- */
- rect->width = (rect->width + rect->x % impl->window_scale + impl->window_scale - 1) / impl->window_scale;
- rect->height = (rect->height + rect->y % impl->window_scale + impl->window_scale - 1) / impl->window_scale;
- rect->x = r.left / impl->window_scale + _gdk_offset_x;
- rect->y = r.top / impl->window_scale + _gdk_offset_y;
-
- GDK_NOTE (MISC, g_print ("gdk_surface_get_frame_extents: %p: %ldx%ld@%+ld%+ld\n",
- GDK_SURFACE_HWND (window),
- rect->width,
- rect->height,
- rect->x, rect->y));
-}
-
-static gboolean
-gdk_surface_win32_get_device_state (GdkSurface *window,
- GdkDevice *device,
- gdouble *x,
- gdouble *y,
- GdkModifierType *mask)
-{
- GdkSurface *child;
-
- g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), FALSE);
-
- GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
- &child,
- NULL, NULL,
- x, y, mask);
- return (child != NULL);
-}
-
-void
-gdk_display_warp_device (GdkDisplay *display,
- GdkDevice *device,
- gint x,
- gint y)
-{
- g_return_if_fail (display == gdk_display_get_default ());
- g_return_if_fail (GDK_IS_DEVICE (device));
- g_return_if_fail (display == gdk_device_get_display (device));
-
- GDK_DEVICE_GET_CLASS (device)->warp (device, x, y);
-}
-
-static GdkEventMask
-gdk_win32_surface_get_events (GdkSurface *window)
-{
- GdkSurfaceImplWin32 *impl;
-
- if (GDK_SURFACE_DESTROYED (window))
- return 0;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- return impl->native_event_mask;
-}
-
-static void
-gdk_win32_surface_set_events (GdkSurface *window,
- GdkEventMask event_mask)
-{
- GdkSurfaceImplWin32 *impl;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- /* gdk_surface_new() always sets the GDK_STRUCTURE_MASK, so better
- * set it here, too. Not that I know or remember why it is
- * necessary, will have to test some day.
- */
- impl->native_event_mask = GDK_STRUCTURE_MASK | event_mask;
-}
-
-static void
-do_shape_combine_region (GdkSurface *window,
- HRGN hrgn,
- gint x, gint y)
-{
- RECT rect;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- GetClientRect (GDK_SURFACE_HWND (window), &rect);
-
- _gdk_win32_adjust_client_rect (window, &rect);
-
- OffsetRgn (hrgn, -rect.left, -rect.top);
- OffsetRgn (hrgn, x, y);
-
- /* If this is a top-level window, add the title bar to the region */
- if (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL)
- {
- HRGN tmp = CreateRectRgn (0, 0, rect.right - rect.left, -rect.top);
- CombineRgn (hrgn, hrgn, tmp, RGN_OR);
- DeleteObject (tmp);
- }
-
- SetWindowRgn (GDK_SURFACE_HWND (window), hrgn, TRUE);
-}
-
-static void
-gdk_win32_surface_set_accept_focus (GdkSurface *window,
- gboolean accept_focus)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- accept_focus = accept_focus != FALSE;
-
- if (window->accept_focus != accept_focus)
- window->accept_focus = accept_focus;
-}
-
-static void
-gdk_win32_surface_set_focus_on_map (GdkSurface *window,
- gboolean focus_on_map)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- focus_on_map = focus_on_map != FALSE;
-
- if (window->focus_on_map != focus_on_map)
- window->focus_on_map = focus_on_map;
-}
-
-static void
-gdk_win32_surface_set_icon_list (GdkSurface *window,
- GList *textures)
-{
- GdkTexture *big_texture, *small_texture;
- gint big_diff, small_diff;
- gint big_w, big_h, small_w, small_h;
- gint w, h;
- gint dw, dh, diff;
- HICON small_hicon, big_hicon;
- GdkSurfaceImplWin32 *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) || textures == NULL)
- return;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- /* ideal sizes for small and large icons */
- big_w = GetSystemMetrics (SM_CXICON);
- big_h = GetSystemMetrics (SM_CYICON);
- small_w = GetSystemMetrics (SM_CXSMICON);
- small_h = GetSystemMetrics (SM_CYSMICON);
-
- /* find closest sized icons in the list */
- big_texture = NULL;
- small_texture = NULL;
- big_diff = 0;
- small_diff = 0;
-
- for (GList *l = textures; l; l = l->next)
- {
- GdkTexture *texture = l->data;
- w = gdk_texture_get_width (texture);
- h = gdk_texture_get_height (texture);
-
- dw = ABS (w - big_w);
- dh = ABS (h - big_h);
- diff = dw*dw + dh*dh;
- if (big_texture == NULL || diff < big_diff)
- {
- big_texture = texture;
- big_diff = diff;
- }
-
- dw = ABS (w - small_w);
- dh = ABS (h - small_h);
- diff = dw*dw + dh*dh;
- if (small_texture == NULL || diff < small_diff)
- {
- small_texture = texture;
- small_diff = diff;
- }
-
- textures = textures->next;
- }
-
- /* Create the icons */
- big_hicon = _gdk_win32_texture_to_hicon (big_texture);
- g_object_unref (big_texture);
- small_hicon = _gdk_win32_texture_to_hicon (small_texture);
- g_object_unref (small_texture);
-
- /* Set the icons */
- SendMessageW (GDK_SURFACE_HWND (window), WM_SETICON, ICON_BIG,
- (LPARAM)big_hicon);
- SendMessageW (GDK_SURFACE_HWND (window), WM_SETICON, ICON_SMALL,
- (LPARAM)small_hicon);
-
- /* Store the icons, destroying any previous icons */
- if (impl->hicon_big)
- GDI_CALL (DestroyIcon, (impl->hicon_big));
- impl->hicon_big = big_hicon;
- if (impl->hicon_small)
- GDI_CALL (DestroyIcon, (impl->hicon_small));
- impl->hicon_small = small_hicon;
-}
-
-static void
-gdk_win32_surface_set_icon_name (GdkSurface *window,
- const gchar *name)
-{
- /* In case I manage to confuse this again (or somebody else does):
- * Please note that "icon name" here really *does* mean the name or
- * title of an window minimized as an icon on the desktop, or in the
- * taskbar. It has nothing to do with the freedesktop.org icon
- * naming stuff.
- */
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
-#if 0
- /* This is not the correct thing to do. We should keep both the
- * "normal" window title, and the icon name. When the window is
- * minimized, call SetWindowText() with the icon name, and when the
- * window is restored, with the normal window title. Also, the name
- * is in UTF-8, so we should do the normal conversion to either wide
- * chars or system codepage, and use either the W or A version of
- * SetWindowText(), depending on Windows version.
- */
- API_CALL (SetWindowText, (GDK_SURFACE_HWND (window), name));
-#endif
-}
-
-static GdkSurface *
-gdk_win32_surface_get_group (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- g_warning ("gdk_surface_get_group not yet implemented");
-
- return NULL;
-}
-
-static void
-gdk_win32_surface_set_group (GdkSurface *window,
- GdkSurface *leader)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (leader == NULL || GDK_IS_SURFACE (leader));
-
- if (GDK_SURFACE_DESTROYED (window) || GDK_SURFACE_DESTROYED (leader))
- return;
-
- g_warning ("gdk_surface_set_group not implemented");
-}
-
-static void
-update_single_bit (LONG *style,
- gboolean all,
- int gdk_bit,
- int style_bit)
-{
- /* all controls the interpretation of gdk_bit -- if all is TRUE,
- * gdk_bit indicates whether style_bit is off; if all is FALSE, gdk
- * bit indicate whether style_bit is on
- */
- if ((!all && gdk_bit) || (all && !gdk_bit))
- *style |= style_bit;
- else
- *style &= ~style_bit;
-}
-
-/*
- * Returns TRUE if window has no decorations.
- * Usually it means CSD windows, because GTK
- * calls gdk_surface_set_decorations (window, 0);
- * This is used to decide whether a toplevel should
- * be made layered, thus it
- * only returns TRUE for toplevels (until GTK minimal
- * system requirements are lifted to Windows 8 or newer,
- * because only toplevels can be layered).
- */
-gboolean
-_gdk_win32_surface_lacks_wm_decorations (GdkSurface *window)
-{
- GdkSurfaceImplWin32 *impl;
- LONG style;
- gboolean has_any_decorations;
-
- if (GDK_SURFACE_DESTROYED (window))
- return FALSE;
-
- /* only toplevels can be layered */
- if (!WINDOW_IS_TOPLEVEL (window))
- return FALSE;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- /* This is because GTK calls gdk_surface_set_decorations (window, 0),
- * even though GdkWMDecoration docs indicate that 0 does NOT mean
- * "no decorations".
- */
- if (impl->decorations &&
- *impl->decorations == 0)
- return TRUE;
-
- if (GDK_SURFACE_HWND (window) == 0)
- return FALSE;
-
- style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
-
- if (style == 0)
- {
- DWORD w32_error = GetLastError ();
-
- GDK_NOTE (MISC, g_print ("Failed to get style of window %p (handle %p): %lu\n",
- window, GDK_SURFACE_HWND (window), w32_error));
- return FALSE;
- }
-
- /* Keep this in sync with _gdk_win32_surface_update_style_bits() */
- /* We don't check what get_effective_window_decorations()
- * has to say, because it gives suggestions based on
- * various hints, while we want *actual* decorations,
- * or their absence.
- */
- has_any_decorations = FALSE;
-
- if (style & (WS_BORDER | WS_THICKFRAME | WS_CAPTION |
- WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX))
- has_any_decorations = TRUE;
- else
- GDK_NOTE (MISC, g_print ("Window %p (handle %p): has no decorations (style %lx)\n",
- window, GDK_SURFACE_HWND (window), style));
-
- return !has_any_decorations;
-}
-
-void
-_gdk_win32_surface_update_style_bits (GdkSurface *window)
-{
- GdkSurfaceImplWin32 *impl = (GdkSurfaceImplWin32 *)window->impl;
- GdkWMDecoration decorations;
- LONG old_style, new_style, old_exstyle, new_exstyle;
- gboolean all;
- RECT rect, before, after;
- gboolean was_topmost;
- gboolean will_be_topmost;
- HWND insert_after;
- UINT flags;
-
- if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
- return;
-
- old_style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
- old_exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
-
- GetClientRect (GDK_SURFACE_HWND (window), &before);
- after = before;
- AdjustWindowRectEx (&before, old_style, FALSE, old_exstyle);
-
- was_topmost = (old_exstyle & WS_EX_TOPMOST) ? TRUE : FALSE;
- will_be_topmost = was_topmost;
-
- old_exstyle &= ~WS_EX_TOPMOST;
-
- new_style = old_style;
- new_exstyle = old_exstyle;
-
- if (window->window_type == GDK_SURFACE_TEMP)
- {
- new_exstyle |= WS_EX_TOOLWINDOW;
- will_be_topmost = TRUE;
- }
- else if (impl->type_hint == GDK_SURFACE_TYPE_HINT_UTILITY)
- {
- new_exstyle |= WS_EX_TOOLWINDOW;
- }
- else
- {
- new_exstyle &= ~WS_EX_TOOLWINDOW;
- }
-
- /* We can get away with using layered windows
- * only when no decorations are needed. It can mean
- * CSD or borderless non-CSD windows (tooltips?).
- *
- * If this window cannot use layered windows, disable it always.
- * This currently applies to windows using OpenGL, which
- * does not work with layered windows.
- */
- if (impl->suppress_layered == 0)
- {
- if (_gdk_win32_surface_lacks_wm_decorations (window))
- impl->layered = g_strcmp0 (g_getenv ("GDK_WIN32_LAYERED"), "0") != 0;
- }
- else
- impl->layered = FALSE;
-
- if (impl->layered)
- new_exstyle |= WS_EX_LAYERED;
- else
- new_exstyle &= ~WS_EX_LAYERED;
-
- if (get_effective_window_decorations (window, &decorations))
- {
- all = (decorations & GDK_DECOR_ALL);
- /* Keep this in sync with the test in _gdk_win32_surface_lacks_wm_decorations() */
- update_single_bit (&new_style, all, decorations & GDK_DECOR_BORDER, WS_BORDER);
- update_single_bit (&new_style, all, decorations & GDK_DECOR_RESIZEH, WS_THICKFRAME);
- update_single_bit (&new_style, all, decorations & GDK_DECOR_TITLE, WS_CAPTION);
- update_single_bit (&new_style, all, decorations & GDK_DECOR_MENU, WS_SYSMENU);
- update_single_bit (&new_style, all, decorations & GDK_DECOR_MINIMIZE, WS_MINIMIZEBOX);
- update_single_bit (&new_style, all, decorations & GDK_DECOR_MAXIMIZE, WS_MAXIMIZEBOX);
- }
-
- if (old_style == new_style && old_exstyle == new_exstyle )
- {
- GDK_NOTE (MISC, g_print ("_gdk_win32_surface_update_style_bits: %p: no change\n",
- GDK_SURFACE_HWND (window)));
- return;
- }
-
- if (old_style != new_style)
- {
- GDK_NOTE (MISC, g_print ("_gdk_win32_surface_update_style_bits: %p: STYLE: %s => %s\n",
- GDK_SURFACE_HWND (window),
- _gdk_win32_surface_style_to_string (old_style),
- _gdk_win32_surface_style_to_string (new_style)));
-
- SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE, new_style);
- }
-
- if (old_exstyle != new_exstyle)
- {
- GDK_NOTE (MISC, g_print ("_gdk_win32_surface_update_style_bits: %p: EXSTYLE: %s => %s\n",
- GDK_SURFACE_HWND (window),
- _gdk_win32_surface_exstyle_to_string (old_exstyle),
- _gdk_win32_surface_exstyle_to_string (new_exstyle)));
-
- SetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE, new_exstyle);
- }
-
- AdjustWindowRectEx (&after, new_style, FALSE, new_exstyle);
-
- GetWindowRect (GDK_SURFACE_HWND (window), &rect);
- rect.left += after.left - before.left;
- rect.top += after.top - before.top;
- rect.right += after.right - before.right;
- rect.bottom += after.bottom - before.bottom;
-
- flags = SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOREPOSITION;
-
- if (will_be_topmost && !was_topmost)
- {
- insert_after = HWND_TOPMOST;
- }
- else if (was_topmost && !will_be_topmost)
- {
- insert_after = HWND_NOTOPMOST;
- }
- else
- {
- flags |= SWP_NOZORDER;
- insert_after = SWP_NOZORDER_SPECIFIED;
- }
-
- SetWindowPos (GDK_SURFACE_HWND (window), insert_after,
- rect.left, rect.top,
- rect.right - rect.left, rect.bottom - rect.top,
- flags);
-}
-
-static void
-update_single_system_menu_entry (HMENU hmenu,
- gboolean all,
- int gdk_bit,
- int menu_entry)
-{
- /* all controls the interpretation of gdk_bit -- if all is TRUE,
- * gdk_bit indicates whether menu entry is disabled; if all is
- * FALSE, gdk bit indicate whether menu entry is enabled
- */
- if ((!all && gdk_bit) || (all && !gdk_bit))
- EnableMenuItem (hmenu, menu_entry, MF_BYCOMMAND | MF_ENABLED);
- else
- EnableMenuItem (hmenu, menu_entry, MF_BYCOMMAND | MF_GRAYED);
-}
-
-static void
-update_system_menu (GdkSurface *window)
-{
- GdkWMFunction functions;
- BOOL all;
-
- if (_gdk_surface_get_functions (window, &functions))
- {
- HMENU hmenu = GetSystemMenu (GDK_SURFACE_HWND (window), FALSE);
-
- all = (functions & GDK_FUNC_ALL);
- update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_RESIZE, SC_SIZE);
- update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MOVE, SC_MOVE);
- update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MINIMIZE, SC_MINIMIZE);
- update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_MAXIMIZE, SC_MAXIMIZE);
- update_single_system_menu_entry (hmenu, all, functions & GDK_FUNC_CLOSE, SC_CLOSE);
- }
-}
-
-static void
-gdk_win32_surface_set_decorations (GdkSurface *window,
- GdkWMDecoration decorations)
-{
- GdkSurfaceImplWin32 *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- GDK_NOTE (MISC, g_print ("gdk_surface_set_decorations: %p: %s %s%s%s%s%s%s\n",
- GDK_SURFACE_HWND (window),
- (decorations & GDK_DECOR_ALL ? "clearing" : "setting"),
- (decorations & GDK_DECOR_BORDER ? "BORDER " : ""),
- (decorations & GDK_DECOR_RESIZEH ? "RESIZEH " : ""),
- (decorations & GDK_DECOR_TITLE ? "TITLE " : ""),
- (decorations & GDK_DECOR_MENU ? "MENU " : ""),
- (decorations & GDK_DECOR_MINIMIZE ? "MINIMIZE " : ""),
- (decorations & GDK_DECOR_MAXIMIZE ? "MAXIMIZE " : "")));
-
- if (!impl->decorations)
- impl->decorations = g_malloc (sizeof (GdkWMDecoration));
-
- *impl->decorations = decorations;
-
- _gdk_win32_surface_update_style_bits (window);
-}
-
-static gboolean
-gdk_win32_surface_get_decorations (GdkSurface *window,
- GdkWMDecoration *decorations)
-{
- GdkSurfaceImplWin32 *impl;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), FALSE);
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- if (impl->decorations == NULL)
- return FALSE;
-
- *decorations = *impl->decorations;
-
- return TRUE;
-}
-
-static GQuark
-get_functions_quark ()
-{
- static GQuark quark = 0;
-
- if (!quark)
- quark = g_quark_from_static_string ("gdk-window-functions");
-
- return quark;
-}
-
-static void
-gdk_win32_surface_set_functions (GdkSurface *window,
- GdkWMFunction functions)
-{
- GdkWMFunction* functions_copy;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- GDK_NOTE (MISC, g_print ("gdk_surface_set_functions: %p: %s %s%s%s%s%s\n",
- GDK_SURFACE_HWND (window),
- (functions & GDK_FUNC_ALL ? "clearing" : "setting"),
- (functions & GDK_FUNC_RESIZE ? "RESIZE " : ""),
- (functions & GDK_FUNC_MOVE ? "MOVE " : ""),
- (functions & GDK_FUNC_MINIMIZE ? "MINIMIZE " : ""),
- (functions & GDK_FUNC_MAXIMIZE ? "MAXIMIZE " : ""),
- (functions & GDK_FUNC_CLOSE ? "CLOSE " : "")));
-
- functions_copy = g_malloc (sizeof (GdkWMFunction));
- *functions_copy = functions;
- g_object_set_qdata_full (G_OBJECT (window), get_functions_quark (), functions_copy, g_free);
-
- update_system_menu (window);
-}
-
-gboolean
-_gdk_surface_get_functions (GdkSurface *window,
- GdkWMFunction *functions)
-{
- GdkWMFunction* functions_set;
-
- functions_set = g_object_get_qdata (G_OBJECT (window), get_functions_quark ());
- if (functions_set)
- *functions = *functions_set;
-
- return (functions_set != NULL);
-}
-
-#if defined(MORE_AEROSNAP_DEBUGGING)
-static void
-log_region (gchar *prefix, AeroSnapEdgeRegion *region)
-{
- GDK_NOTE (MISC, g_print ("Region %s:\n"
- "edge %d x %d @ %d x %d\n"
- "trig %d x %d @ %d x %d\n",
- prefix,
- region->edge.width,
- region->edge.height,
- region->edge.x,
- region->edge.y,
- region->trigger.width,
- region->trigger.height,
- region->trigger.x,
- region->trigger.y));
-}
-#endif
-
-static void
-calculate_aerosnap_regions (GdkW32DragMoveResizeContext *context)
-{
- GdkDisplay *display;
- gint n_monitors, monitor_idx, other_monitor_idx;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (context->window->impl);
-#if defined(MORE_AEROSNAP_DEBUGGING)
- gint i;
-#endif
-
- display = gdk_display_get_default ();
- n_monitors = gdk_display_get_n_monitors (display);
-
-#define _M_UP 0
-#define _M_DOWN 1
-#define _M_LEFT 2
-#define _M_RIGHT 3
-
- for (monitor_idx = 0; monitor_idx < n_monitors; monitor_idx++)
- {
- GdkRectangle wa;
- GdkRectangle geometry;
- AeroSnapEdgeRegion snap_region;
- gboolean move_edge[4] = { TRUE, FALSE, TRUE, TRUE };
- gboolean resize_edge[2] = { TRUE, TRUE };
- gint diff;
- gint thickness, trigger_thickness;
- GdkMonitor *monitor;
-
- monitor = gdk_display_get_monitor (display, monitor_idx);
- gdk_monitor_get_workarea (monitor, &wa);
- gdk_monitor_get_geometry (monitor, &geometry);
-
- for (other_monitor_idx = 0;
- other_monitor_idx < n_monitors &&
- (move_edge[_M_UP] || move_edge[_M_LEFT] ||
- move_edge[_M_RIGHT] || resize_edge[_M_DOWN]);
- other_monitor_idx++)
- {
- GdkRectangle other_wa;
- GdkMonitor *other_monitor;
-
- if (other_monitor_idx == monitor_idx)
- continue;
-
- other_monitor = gdk_display_get_monitor (display, other_monitor_idx);
- gdk_monitor_get_workarea (other_monitor, &other_wa);
-
- /* An edge triggers AeroSnap only if there are no
- * monitors beyond that edge.
- * Even if there's another monitor, but it does not cover
- * the whole edge (it's smaller or is not aligned to
- * the corner of current monitor), that edge is still
- * removed from the trigger list.
- */
- if (other_wa.x >= wa.x + wa.width)
- move_edge[_M_RIGHT] = FALSE;
-
- if (other_wa.x + other_wa.width <= wa.x)
- move_edge[_M_LEFT] = FALSE;
-
- if (other_wa.y + other_wa.height <= wa.y)
- {
- move_edge[_M_UP] = FALSE;
- resize_edge[_M_UP] = FALSE;
- }
-
- if (other_wa.y >= wa.y + wa.height)
- {
- /* no move_edge for the bottom edge, just resize_edge */
- resize_edge[_M_DOWN] = FALSE;
- }
- }
-
- thickness = AEROSNAP_REGION_THICKNESS * impl->window_scale;
- trigger_thickness = AEROSNAP_REGION_TRIGGER_THICKNESS * impl->window_scale;
-
- snap_region.edge = wa;
- snap_region.trigger = wa;
- snap_region.edge.height = thickness;
- snap_region.trigger.height = trigger_thickness;
-
- /* Extend both regions into toolbar space.
- * When there's no toolbar, diff == 0.
- */
- diff = wa.y - geometry.y;
- snap_region.edge.height += diff;
- snap_region.edge.y -= diff;
- snap_region.trigger.height += diff;
- snap_region.trigger.y -= diff;
-
- if (move_edge[_M_UP])
- g_array_append_val (context->maximize_regions, snap_region);
-
- if (resize_edge[_M_UP])
- g_array_append_val (context->fullup_regions, snap_region);
-
- snap_region.edge = wa;
- snap_region.trigger = wa;
- snap_region.edge.width = thickness;
- snap_region.trigger.width = trigger_thickness;
-
- diff = wa.x - geometry.x;
- snap_region.edge.width += diff;
- snap_region.edge.x -= diff;
- snap_region.trigger.width += diff;
- snap_region.trigger.x -= diff;
-
- if (move_edge[_M_LEFT])
- g_array_append_val (context->halfleft_regions, snap_region);
-
- snap_region.edge = wa;
- snap_region.trigger = wa;
- snap_region.edge.x += wa.width - thickness;
- snap_region.edge.width = thickness;
- snap_region.trigger.x += wa.width - trigger_thickness;
- snap_region.trigger.width = trigger_thickness;
-
- diff = (geometry.x + geometry.width) - (wa.x + wa.width);
- snap_region.edge.width += diff;
- snap_region.trigger.width += diff;
-
- if (move_edge[_M_RIGHT])
- g_array_append_val (context->halfright_regions, snap_region);
-
- snap_region.edge = wa;
- snap_region.trigger = wa;
- snap_region.edge.y += wa.height - thickness;
- snap_region.edge.height = thickness;
- snap_region.trigger.y += wa.height - trigger_thickness;
- snap_region.trigger.height = trigger_thickness;
-
- diff = (geometry.y + geometry.height) - (wa.y + wa.height);
- snap_region.edge.height += diff;
- snap_region.trigger.height += diff;
-
- if (resize_edge[_M_DOWN])
- g_array_append_val (context->fullup_regions, snap_region);
- }
-
-#undef _M_UP
-#undef _M_DOWN
-#undef _M_LEFT
-#undef _M_RIGHT
-
-#if defined(MORE_AEROSNAP_DEBUGGING)
- for (i = 0; i < context->maximize_regions->len; i++)
- log_region ("maximize", &g_array_index (context->maximize_regions, AeroSnapEdgeRegion, i));
-
- for (i = 0; i < context->halfleft_regions->len; i++)
- log_region ("halfleft", &g_array_index (context->halfleft_regions, AeroSnapEdgeRegion, i));
-
- for (i = 0; i < context->halfright_regions->len; i++)
- log_region ("halfright", &g_array_index (context->halfright_regions, AeroSnapEdgeRegion, i));
-
- for (i = 0; i < context->fullup_regions->len; i++)
- log_region ("fullup", &g_array_index (context->fullup_regions, AeroSnapEdgeRegion, i));
-#endif
-}
-
-static void
-discard_snapinfo (GdkSurface *window)
-{
- GdkSurfaceImplWin32 *impl;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- impl->snap_state = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
-
- if (impl->snap_stash == NULL)
- return;
-
- g_clear_pointer (&impl->snap_stash, g_free);
- g_clear_pointer (&impl->snap_stash_int, g_free);
-}
-
-static void
-unsnap (GdkSurface *window,
- GdkMonitor *monitor)
-{
- GdkSurfaceImplWin32 *impl;
- GdkRectangle rect;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- impl->snap_state = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
-
- if (impl->snap_stash == NULL)
- return;
-
- gdk_monitor_get_workarea (monitor, &rect);
-
- GDK_NOTE (MISC, g_print ("Monitor work area %d x %d @ %d : %d\n", rect.width, rect.height, rect.x, rect.y));
-
- if (rect.width >= impl->snap_stash_int->width &&
- rect.height >= impl->snap_stash_int->height)
- {
- /* If the window fits into new work area without resizing it,
- * place it into new work area without resizing it.
- */
- gdouble left, right, up, down, hratio, vratio;
- gdouble hscale, vscale;
- gdouble new_left, new_up;
-
- left = impl->snap_stash->x;
- right = 1.0 - (impl->snap_stash->x + impl->snap_stash->width);
- up = impl->snap_stash->y;
- down = 1.0 - (impl->snap_stash->y + impl->snap_stash->height);
- hscale = 1.0;
-
- if (right > 0.001)
- {
- hratio = left / right;
- hscale = hratio / (1.0 + hratio);
- }
-
- new_left = (gdouble) (rect.width - impl->snap_stash_int->width) * hscale;
-
- vscale = 1.0;
-
- if (down > 0.001)
- {
- vratio = up / down;
- vscale = vratio / (1.0 + vratio);
- }
-
- new_up = (gdouble) (rect.height - impl->snap_stash_int->height) * vscale;
-
- rect.x = round (rect.x + new_left);
- rect.y = round (rect.y + new_up);
- rect.width = impl->snap_stash_int->width;
- rect.height = impl->snap_stash_int->height;
- }
- else
- {
- /* Calculate actual unsnapped window size based on its
- * old relative size. Same for position.
- */
- rect.x += round (rect.width * impl->snap_stash->x);
- rect.y += round (rect.height * impl->snap_stash->y);
- rect.width = round (rect.width * impl->snap_stash->width);
- rect.height = round (rect.height * impl->snap_stash->height);
- }
-
- GDK_NOTE (MISC, g_print ("Unsnapped window size %d x %d @ %d : %d\n", rect.width, rect.height, rect.x, rect.y));
-
- gdk_surface_move_resize (window, rect.x, rect.y,
- rect.width, rect.height);
-
- g_clear_pointer (&impl->snap_stash, g_free);
- g_clear_pointer (&impl->snap_stash_int, g_free);
-}
-
-static void
-stash_window (GdkSurface *window,
- GdkSurfaceImplWin32 *impl)
-{
- gint x, y;
- gint width, wwidth;
- gint height, wheight;
- WINDOWPLACEMENT placement;
- HMONITOR hmonitor;
- MONITORINFO hmonitor_info;
-
- placement.length = sizeof(WINDOWPLACEMENT);
-
- /* Use W32 API to get unmaximized window size, which GDK doesn't remember */
- if (!GetWindowPlacement (GDK_SURFACE_HWND (window), &placement))
- return;
-
- /* MSDN is very vague, but in practice rcNormalPosition is the same as GetWindowRect(),
- * only with adjustments for toolbars (which creates rather weird coodinate space issues).
- * We need to get monitor info and apply workarea vs monitorarea diff to turn
- * these into screen coordinates proper.
- */
- hmonitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
- hmonitor_info.cbSize = sizeof (hmonitor_info);
-
- if (!GetMonitorInfoA (hmonitor, &hmonitor_info))
- return;
-
- if (impl->snap_stash == NULL)
- impl->snap_stash = g_new0 (GdkRectangleDouble, 1);
-
- if (impl->snap_stash_int == NULL)
- impl->snap_stash_int = g_new0 (GdkRectangle, 1);
-
- GDK_NOTE (MISC, g_print ("monitor work area %ld x %ld @ %ld : %ld\n",
- (hmonitor_info.rcWork.right - hmonitor_info.rcWork.left) / impl->window_scale,
- (hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top) / impl->window_scale,
- hmonitor_info.rcWork.left,
- hmonitor_info.rcWork.top));
- GDK_NOTE (MISC, g_print ("monitor area %ld x %ld @ %ld : %ld\n",
- (hmonitor_info.rcMonitor.right - hmonitor_info.rcMonitor.left) / impl->window_scale,
- (hmonitor_info.rcMonitor.bottom - hmonitor_info.rcMonitor.top) / impl->window_scale,
- hmonitor_info.rcMonitor.left,
- hmonitor_info.rcMonitor.top));
- GDK_NOTE (MISC, g_print ("window work place %ld x %ld @ %ld : %ld\n",
- (placement.rcNormalPosition.right - placement.rcNormalPosition.left) / impl->window_scale,
- (placement.rcNormalPosition.bottom - placement.rcNormalPosition.top) / impl->window_scale,
- placement.rcNormalPosition.left,
- placement.rcNormalPosition.top));
-
- width = (placement.rcNormalPosition.right - placement.rcNormalPosition.left) / impl->window_scale;
- height = (placement.rcNormalPosition.bottom - placement.rcNormalPosition.top) / impl->window_scale;
- x = (placement.rcNormalPosition.left - hmonitor_info.rcMonitor.left) / impl->window_scale;
- y = (placement.rcNormalPosition.top - hmonitor_info.rcMonitor.top) / impl->window_scale;
-
- wwidth = (hmonitor_info.rcWork.right - hmonitor_info.rcWork.left) / impl->window_scale;
- wheight = (hmonitor_info.rcWork.bottom - hmonitor_info.rcWork.top) / impl->window_scale;
-
- impl->snap_stash->x = (gdouble) (x) / (gdouble) (wwidth);
- impl->snap_stash->y = (gdouble) (y) / (gdouble) (wheight);
- impl->snap_stash->width = (gdouble) width / (gdouble) (wwidth);
- impl->snap_stash->height = (gdouble) height / (gdouble) (wheight);
-
- impl->snap_stash_int->x = x;
- impl->snap_stash_int->y = y;
- impl->snap_stash_int->width = width;
- impl->snap_stash_int->height = height;
-
- GDK_NOTE (MISC, g_print ("Stashed window %d x %d @ %d : %d as %f x %f @ %f : %f\n",
- width, height, x, y,
- impl->snap_stash->width, impl->snap_stash->height, impl->snap_stash->x, impl->snap_stash->y));
-}
-
-static void
-snap_up (GdkSurface *window)
-{
- SHORT maxysize;
- gint x, y;
- gint width, height;
- GdkSurfaceImplWin32 *impl;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- impl->snap_state = GDK_WIN32_AEROSNAP_STATE_FULLUP;
-
- stash_window (window, impl);
-
- maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN) / impl->window_scale;
- gdk_surface_get_position (window, &x, &y);
- width = gdk_surface_get_width (window);
-
- y = 0;
- height = maxysize;
-
- x = x - impl->margins.left;
- y = y - impl->margins.top;
- width += impl->margins_x;
- height += impl->margins_y;
-
- gdk_surface_move_resize (window, x, y, width, height);
-}
-
-static void
-snap_left (GdkSurface *window,
- GdkMonitor *monitor,
- GdkMonitor *snap_monitor)
-{
- GdkRectangle rect;
- GdkSurfaceImplWin32 *impl;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
-
- gdk_monitor_get_workarea (snap_monitor, &rect);
-
- stash_window (window, impl);
-
- rect.width = rect.width / 2;
-
- rect.x = rect.x - impl->margins.left;
- rect.y = rect.y - impl->margins.top;
- rect.width = rect.width + impl->margins_x;
- rect.height = rect.height + impl->margins_y;
-
- gdk_surface_move_resize (window, rect.x, rect.y, rect.width, rect.height);
-}
-
-static void
-snap_right (GdkSurface *window,
- GdkMonitor *monitor,
- GdkMonitor *snap_monitor)
-{
- GdkRectangle rect;
- GdkSurfaceImplWin32 *impl;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
-
- gdk_monitor_get_workarea (snap_monitor, &rect);
-
- stash_window (window, impl);
-
- rect.width = rect.width / 2;
- rect.x += rect.width;
-
- rect.x = rect.x - impl->margins.left;
- rect.y = rect.y - impl->margins.top;
- rect.width = rect.width + impl->margins_x;
- rect.height = rect.height + impl->margins_y;
-
- gdk_surface_move_resize (window, rect.x, rect.y, rect.width, rect.height);
-}
-
-void
-_gdk_win32_surface_handle_aerosnap (GdkSurface *window,
- GdkWin32AeroSnapCombo combo)
-{
- GdkSurfaceImplWin32 *impl;
- GdkDisplay *display;
- gint n_monitors;
- GdkSurfaceState window_state = gdk_surface_get_state (window);
- gboolean minimized = window_state & GDK_SURFACE_STATE_ICONIFIED;
- gboolean maximized = window_state & GDK_SURFACE_STATE_MAXIMIZED;
- gboolean halfsnapped;
- GdkMonitor *monitor;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- display = gdk_surface_get_display (window);
- n_monitors = gdk_display_get_n_monitors (display);
- monitor = gdk_display_get_monitor_at_window (display, window);
-
- if (minimized && maximized)
- minimized = FALSE;
-
- halfsnapped = (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT ||
- impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT ||
- impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP);
-
- switch (combo)
- {
- case GDK_WIN32_AEROSNAP_COMBO_NOTHING:
- /* Do nothing */
- break;
- case GDK_WIN32_AEROSNAP_COMBO_UP:
- if (!maximized)
- {
- unsnap (window, monitor);
- gdk_surface_maximize (window);
- }
- break;
- case GDK_WIN32_AEROSNAP_COMBO_DOWN:
- case GDK_WIN32_AEROSNAP_COMBO_SHIFTDOWN:
- if (maximized)
- {
- gdk_surface_unmaximize (window);
- unsnap (window, monitor);
- }
- else if (halfsnapped)
- unsnap (window, monitor);
- else if (!minimized)
- gdk_surface_iconify (window);
- break;
- case GDK_WIN32_AEROSNAP_COMBO_LEFT:
- if (maximized)
- gdk_surface_unmaximize (window);
-
- if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED ||
- impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP)
- {
- unsnap (window, monitor);
- snap_left (window, monitor, monitor);
- }
- else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT)
- {
- unsnap (window, monitor);
- snap_right (window,
- monitor,
- gdk_monitor_is_primary (monitor) ? monitor : gdk_display_get_monitor (display, n_monitors - 1));
- }
- else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT)
- {
- unsnap (window, monitor);
- }
- break;
- case GDK_WIN32_AEROSNAP_COMBO_RIGHT:
- if (maximized)
- gdk_surface_unmaximize (window);
-
- if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED ||
- impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP)
- {
- unsnap (window, monitor);
- snap_right (window, monitor, monitor);
- }
- else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT)
- {
- unsnap (window, monitor);
- }
- else if (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT)
- {
- gint i;
-
- unsnap (window, monitor);
- if (n_monitors == 1 ||
- monitor == gdk_display_get_monitor (display, n_monitors - 1))
- {
- snap_left (window, monitor, monitor);
- }
- else
- {
- for (i = 0; i < n_monitors; i++)
- {
- if (monitor == gdk_display_get_monitor (display, i))
- break;
- }
-
- snap_left (window, monitor, gdk_display_get_monitor (display, i + 1));
- }
- }
- break;
- case GDK_WIN32_AEROSNAP_COMBO_SHIFTUP:
- if (!maximized &&
- impl->snap_state == GDK_WIN32_AEROSNAP_STATE_UNDETERMINED)
- {
- snap_up (window);
- }
- break;
- case GDK_WIN32_AEROSNAP_COMBO_SHIFTLEFT:
- case GDK_WIN32_AEROSNAP_COMBO_SHIFTRIGHT:
- /* No implementation needed at the moment */
- break;
- }
-}
-
-static void
-apply_snap (GdkSurface *window,
- GdkWin32AeroSnapState snap)
-{
- GdkMonitor *monitor;
- GdkDisplay *display;
-
- display = gdk_surface_get_display (window);
- monitor = gdk_display_get_monitor_at_window (display, window);
-
- switch (snap)
- {
- case GDK_WIN32_AEROSNAP_STATE_UNDETERMINED:
- break;
- case GDK_WIN32_AEROSNAP_STATE_MAXIMIZE:
- unsnap (window, monitor);
- gdk_surface_maximize (window);
- break;
- case GDK_WIN32_AEROSNAP_STATE_HALFLEFT:
- unsnap (window, monitor);
- snap_left (window, monitor, monitor);
- break;
- case GDK_WIN32_AEROSNAP_STATE_HALFRIGHT:
- unsnap (window, monitor);
- snap_right (window, monitor, monitor);
- break;
- case GDK_WIN32_AEROSNAP_STATE_FULLUP:
- snap_up (window);
- break;
- }
-}
-
-/* Registers a dumb window class. This window
- * has DefWindowProc() for a window procedure and
- * does not do anything that GdkSurface-bound HWNDs do.
- */
-static ATOM
-RegisterGdkDumbClass ()
-{
- static ATOM klassDUMB = 0;
- static WNDCLASSEXW wcl;
- ATOM klass = 0;
-
- wcl.cbSize = sizeof (WNDCLASSEX);
- wcl.style = 0; /* DON'T set CS_<H,V>REDRAW. It causes total redraw
- * on WM_SIZE and WM_MOVE. Flicker, Performance!
- */
- wcl.lpfnWndProc = DefWindowProcW;
- wcl.cbClsExtra = 0;
- wcl.cbWndExtra = 0;
- wcl.hInstance = _gdk_app_hmodule;
- wcl.hIcon = 0;
- wcl.hIconSm = 0;
- wcl.lpszMenuName = NULL;
- wcl.hbrBackground = NULL;
- wcl.hCursor = LoadCursor (NULL, IDC_ARROW);
- wcl.style |= CS_OWNDC;
- wcl.lpszClassName = L"gdkWindowDumb";
-
- if (klassDUMB == 0)
- klassDUMB = RegisterClassExW (&wcl);
-
- klass = klassDUMB;
-
- if (klass == 0)
- {
- WIN32_API_FAILED ("RegisterClassExW");
- g_error ("That is a fatal error");
- }
-
- return klass;
-}
-
-static gboolean
-ensure_snap_indicator_exists (GdkW32DragMoveResizeContext *context)
-{
- if (context->shape_indicator == NULL)
- {
- HWND handle;
- ATOM klass;
- klass = RegisterGdkDumbClass ();
-
- handle = CreateWindowExW (WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOACTIVATE,
- MAKEINTRESOURCEW (klass),
- L"",
- WS_POPUP,
- 0,
- 0,
- 0, 0,
- NULL,
- NULL,
- _gdk_app_hmodule,
- NULL);
-
- context->shape_indicator = handle;
- }
-
- return context->shape_indicator != NULL;
-}
-
-static gboolean
-ensure_snap_indicator_surface (GdkW32DragMoveResizeContext *context,
- gint width,
- gint height,
- guint scale)
-{
- if (context->indicator_surface != NULL &&
- (context->indicator_surface_width < width ||
- context->indicator_surface_height < height))
- {
- cairo_surface_destroy (context->indicator_surface);
- context->indicator_surface = NULL;
- }
-
- if (context->indicator_surface == NULL)
- context->indicator_surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
- width * scale,
- height * scale);
-
- if (cairo_surface_status (context->indicator_surface) != CAIRO_STATUS_SUCCESS)
- {
- cairo_surface_destroy (context->indicator_surface);
- context->indicator_surface = NULL;
-
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Indicator is drawn with some inward offset, so that it does
- * not hug screen edges.
- */
-static void
-adjust_indicator_rectangle (GdkRectangle *rect,
- gboolean inward)
-{
- gdouble inverter;
- const gint gap = AEROSNAP_INDICATOR_EDGE_GAP;
-#if defined(MORE_AEROSNAP_DEBUGGING)
- GdkRectangle cache = *rect;
-#endif
-
- if (inward)
- inverter = 1.0;
- else
- inverter = -1.0;
-
- rect->x += (gap * inverter);
- rect->y += (gap * inverter);
- rect->width -= (gap * 2 * inverter);
- rect->height -= (gap * 2 * inverter);
-
-#if defined(MORE_AEROSNAP_DEBUGGING)
- GDK_NOTE (MISC, g_print ("Adjusted %d x %d @ %d : %d -> %d x %d @ %d : %d\n",
- cache.width, cache.height, cache.x, cache.y,
- rect->width, rect->height, rect->x, rect->y));
-#endif
-}
-
-static void
-rounded_rectangle (cairo_t *cr,
- gint x,
- gint y,
- gint width,
- gint height,
- gdouble radius,
- gdouble line_width,
- GdkRGBA *fill,
- GdkRGBA *outline)
-{
- gdouble degrees = M_PI / 180.0;
-
- if (fill == NULL && outline == NULL)
- return;
-
- cairo_save (cr);
- cairo_new_sub_path (cr);
- cairo_arc (cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
- cairo_arc (cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
- cairo_arc (cr, (x + radius), y + height - radius, radius, 90 * degrees, 180 * degrees);
- cairo_arc (cr, (x + radius), (y + radius), radius, 180 * degrees, 270 * degrees);
- cairo_close_path (cr);
-
- if (fill)
- {
- cairo_set_source_rgba (cr, fill->red, fill->green, fill->blue, fill->alpha);
-
- if (outline)
- cairo_fill_preserve (cr);
- else
- cairo_fill (cr);
- }
-
- if (outline)
- {
- cairo_set_source_rgba (cr, outline->red, outline->green, outline->blue, outline->alpha);
- cairo_set_line_width (cr, line_width);
- cairo_stroke (cr);
- }
-
- cairo_restore (cr);
-}
-
-/* Translates linear animation scale into some kind of curve */
-static gdouble
-curve (gdouble val)
-{
- /* TODO: try different curves. For now it's just linear */
- return val;
-}
-
-static gboolean
-draw_indicator (GdkW32DragMoveResizeContext *context,
- gint64 timestamp)
-{
- cairo_t *cr;
- GdkRGBA outline = {0, 0, 1.0, 1.0};
- GdkRGBA fill = {0, 0, 1.0, 0.8};
- GdkRectangle current_rect;
- gint64 current_time = g_get_monotonic_time ();
- gdouble animation_progress;
- gboolean last_draw;
- gdouble line_width;
- gdouble corner_radius;
- gint64 animation_duration;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (context->window->impl);
-
- line_width = AEROSNAP_INDICATOR_LINE_WIDTH * impl->window_scale;
- corner_radius = AEROSNAP_INDICATOR_CORNER_RADIUS;
- animation_duration = AEROSNAP_INDICATOR_ANIMATION_DURATION;
- last_draw = FALSE;
-
- if (timestamp == 0 &&
- current_time - context->indicator_start_time > animation_duration)
- {
- timestamp = context->indicator_start_time + animation_duration;
- last_draw = TRUE;
- }
-
- if (timestamp != 0)
- current_time = timestamp;
-
- animation_progress = (gdouble) (current_time - context->indicator_start_time) / animation_duration;
-
- if (animation_progress > 1.0)
- animation_progress = 1.0;
-
- if (animation_progress < 0)
- animation_progress = 0;
-
- animation_progress = curve (animation_progress);
-
- current_rect = context->indicator_start;
- current_rect.x += (context->indicator_target.x - context->indicator_start.x) * animation_progress;
- current_rect.y += (context->indicator_target.y - context->indicator_start.y) * animation_progress;
- current_rect.width += (context->indicator_target.width - context->indicator_start.width) * animation_progress;
- current_rect.height += (context->indicator_target.height - context->indicator_start.height) * animation_progress;
-
- if (context->op == GDK_WIN32_DRAGOP_RESIZE && last_draw)
- {
- switch (context->edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- current_rect.x = context->indicator_target.x + (context->indicator_target.width - current_rect.width);
- current_rect.y = context->indicator_target.y + (context->indicator_target.height - current_rect.height);
- break;
- case GDK_SURFACE_EDGE_NORTH:
- current_rect.y = context->indicator_target.y + (context->indicator_target.height - current_rect.height);
- break;
- case GDK_SURFACE_EDGE_WEST:
- current_rect.x = context->indicator_target.x + (context->indicator_target.width - current_rect.width);
- break;
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- current_rect.x = context->indicator_target.x + (context->indicator_target.width - current_rect.width);
- current_rect.y = context->indicator_target.y;
- break;
- case GDK_SURFACE_EDGE_NORTH_EAST:
- current_rect.x = context->indicator_target.x;
- current_rect.y = context->indicator_target.y + (context->indicator_target.height - current_rect.height);
- break;
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- current_rect.x = context->indicator_target.x;
- current_rect.y = context->indicator_target.y;
- break;
- case GDK_SURFACE_EDGE_SOUTH:
- current_rect.y = context->indicator_target.y;
- break;
- case GDK_SURFACE_EDGE_EAST:
- current_rect.x = context->indicator_target.x;
- break;
- }
- }
-
- cr = cairo_create (context->indicator_surface);
- rounded_rectangle (cr,
- (current_rect.x - context->indicator_window_rect.x) * impl->window_scale,
- (current_rect.y - context->indicator_window_rect.y) * impl->window_scale,
- current_rect.width * impl->window_scale,
- current_rect.height * impl->window_scale,
- corner_radius,
- line_width,
- &fill, &outline);
- cairo_destroy (cr);
-
-#if defined(MORE_AEROSNAP_DEBUGGING)
- GDK_NOTE (MISC, g_print ("Indicator is %d x %d @ %d : %d; current time is %" G_GINT64_FORMAT "\n",
- current_rect.width, current_rect.height,
- current_rect.x - context->indicator_window_rect.x,
- current_rect.y - context->indicator_window_rect.y,
- current_time));
-#endif
-
- return last_draw;
-}
-
-static gboolean
-redraw_indicator (gpointer user_data)
-{
- GdkW32DragMoveResizeContext *context = user_data;
- POINT window_position;
- SIZE window_size;
- BLENDFUNCTION blender;
- HDC hdc;
- POINT source_point = { 0, 0 };
- gboolean last_draw;
- gdouble indicator_opacity;
- GdkSurfaceImplWin32 *impl;
- gboolean do_source_remove = FALSE;
-
- indicator_opacity = AEROSNAP_INDICATOR_OPACITY;
-
- if (GDK_SURFACE_DESTROYED (context->window) ||
- !ensure_snap_indicator_exists (context))
- {
- do_source_remove = TRUE;
- }
-
- impl = GDK_SURFACE_IMPL_WIN32 (context->window->impl);
-
- if (!ensure_snap_indicator_surface (context,
- context->indicator_window_rect.width,
- context->indicator_window_rect.height,
- impl->window_scale))
- {
- do_source_remove = TRUE;
- }
-
- if (do_source_remove)
- {
- context->timer = 0;
- return G_SOURCE_REMOVE;
- }
-
- last_draw = draw_indicator (context, context->draw_timestamp);
-
- window_position.x = (context->indicator_window_rect.x - _gdk_offset_x) * impl->window_scale;
- window_position.y = (context->indicator_window_rect.y - _gdk_offset_y) * impl->window_scale;
- window_size.cx = context->indicator_window_rect.width * impl->window_scale;
- window_size.cy = context->indicator_window_rect.height * impl->window_scale;
-
- blender.BlendOp = AC_SRC_OVER;
- blender.BlendFlags = 0;
- blender.AlphaFormat = AC_SRC_ALPHA;
- blender.SourceConstantAlpha = 255 * indicator_opacity;
-
- hdc = cairo_win32_surface_get_dc (context->indicator_surface);
-
- API_CALL (SetWindowPos, (context->shape_indicator,
- GDK_SURFACE_HWND (context->window),
- 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_NOACTIVATE));
-
-#if defined(MORE_AEROSNAP_DEBUGGING)
- GDK_NOTE (MISC, g_print ("Indicator window position is %ld x %ld @ %ld : %ld\n",
- window_size.cx, window_size.cy,
- window_position.x, window_position.y));
-#endif
-
- API_CALL (UpdateLayeredWindow, (context->shape_indicator, NULL,
- &window_position, &window_size,
- hdc, &source_point,
- 0, &blender, ULW_ALPHA));
-
- if (last_draw)
- context->timer = 0;
-
- return last_draw ? G_SOURCE_REMOVE : G_SOURCE_CONTINUE;
-}
-
-static GdkRectangle
-unity_of_rects (GdkRectangle a,
- GdkRectangle b)
-{
- GdkRectangle u = b;
-
- if (a.x < u.x)
- {
- u.width += u.x - a.x;
- u.x = a.x;
- }
-
- if (a.y < u.y)
- {
- u.height += (u.y - a.y);
- u.y = a.y;
- }
-
- if (a.x + a.width > u.x + u.width)
- u.width += (a.x + a.width) - (u.x + u.width);
-
- if (a.y + a.height > u.y + u.height)
- u.height += (a.y + a.height) - (u.y + u.height);
-
-#if defined(MORE_AEROSNAP_DEBUGGING)
- GDK_NOTE (MISC, g_print ("Unified 2 rects into %d x %d @ %d : %d\n",
- u.width, u.height, u.x, u.y));
-#endif
-
- return u;
-}
-
-static void
-start_indicator_drawing (GdkW32DragMoveResizeContext *context,
- GdkRectangle from,
- GdkRectangle to,
- guint scale)
-{
- GdkRectangle to_adjusted, from_adjusted, from_or_to;
- gint64 indicator_animation_tick = AEROSNAP_INDICATOR_ANIMATION_TICK;
-
- GDK_NOTE (MISC, g_print ("Start drawing snap indicator %d x %d @ %d : %d -> %d x %d @ %d : %d\n",
- from.width * scale, from.height * scale, from.x, from.y, to.width * scale, to.height * scale, to.x, to.y));
-
- if (GDK_SURFACE_DESTROYED (context->window))
- return;
-
- if (!ensure_snap_indicator_exists (context))
- return;
-
- from_or_to = unity_of_rects (from, to);
-
- if (!ensure_snap_indicator_surface (context, from_or_to.width, from_or_to.height, scale))
- return;
-
- to_adjusted = to;
- adjust_indicator_rectangle (&to_adjusted, TRUE);
-
- from_adjusted = from;
- adjust_indicator_rectangle (&from_adjusted, TRUE);
-
- context->draw_timestamp = 0;
- context->indicator_start = from_adjusted;
- context->indicator_target = to_adjusted;
- context->indicator_window_rect = from_or_to;
- context->indicator_start_time = g_get_monotonic_time ();
-
- if (context->timer)
- {
- g_source_remove (context->timer);
- context->timer = 0;
- }
-
- context->timer = g_timeout_add_full (G_PRIORITY_DEFAULT,
- indicator_animation_tick,
- redraw_indicator,
- context,
- NULL);
-}
-
-static void
-update_fullup_indicator (GdkSurface *window,
- GdkW32DragMoveResizeContext *context)
-{
- SHORT maxysize;
- GdkRectangle from, to;
- GdkRectangle to_adjusted, from_adjusted, from_or_to;
- GdkSurfaceImplWin32 *impl;
-
- GDK_NOTE (MISC, g_print ("Update fullup indicator\n"));
-
- if (GDK_SURFACE_DESTROYED (context->window))
- return;
-
- if (context->shape_indicator == NULL)
- return;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN);
- gdk_surface_get_position (window, &to.x, &to.y);
- to.width = gdk_surface_get_width (window);
- to.height = gdk_surface_get_height (window);
-
- to.y = 0;
- to.height = maxysize;
- from = context->indicator_target;
-
- if (context->timer == 0)
- {
- from_adjusted = from;
- adjust_indicator_rectangle (&from_adjusted, FALSE);
-
- GDK_NOTE (MISC, g_print ("Restart fullup animation from %d x %d @ %d : %d -> %d x %d @ %d x %d\n",
- context->indicator_target.width, context->indicator_target.height,
- context->indicator_target.x, context->indicator_target.y,
- to.width, to.height, to.x, to.y));
- start_indicator_drawing (context, from_adjusted, to, impl->window_scale);
-
- return;
- }
-
- from_or_to = unity_of_rects (from, to);
-
- to_adjusted = to;
- adjust_indicator_rectangle (&to_adjusted, TRUE);
-
- GDK_NOTE (MISC, g_print ("Retarget fullup animation %d x %d @ %d : %d -> %d x %d @ %d x %d\n",
- context->indicator_target.width, context->indicator_target.height,
- context->indicator_target.x, context->indicator_target.y,
- to_adjusted.width, to_adjusted.height, to_adjusted.x, to_adjusted.y));
-
- context->indicator_target = to_adjusted;
- context->indicator_window_rect = from_or_to;
-
- ensure_snap_indicator_surface (context, from_or_to.width, from_or_to.height, impl->window_scale);
-}
-
-static void
-start_indicator (GdkSurface *window,
- GdkW32DragMoveResizeContext *context,
- gint x,
- gint y,
- GdkWin32AeroSnapState state)
-{
- GdkMonitor *monitor;
- GdkRectangle workarea;
- SHORT maxysize;
- GdkRectangle start_size, end_size;
- GdkDisplay *display;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- display = gdk_surface_get_display (window);
- monitor = gdk_display_get_monitor_at_point (display, x, y);
- gdk_monitor_get_workarea (monitor, &workarea);
-
- maxysize = GetSystemMetrics (SM_CYVIRTUALSCREEN) / impl->window_scale;
- gdk_surface_get_position (window, &start_size.x, &start_size.y);
- start_size.width = gdk_surface_get_width (window);
- start_size.height = gdk_surface_get_height (window);
-
- end_size = start_size;
-
- switch (state)
- {
- case GDK_WIN32_AEROSNAP_STATE_UNDETERMINED:
- return;
- case GDK_WIN32_AEROSNAP_STATE_MAXIMIZE:
- end_size.x = workarea.x;
- end_size.y = workarea.y;
- end_size.width = workarea.width;
- end_size.height = workarea.height;
- break;
- case GDK_WIN32_AEROSNAP_STATE_HALFLEFT:
- end_size.x = workarea.x;
- end_size.y = workarea.y;
- end_size.width = workarea.width / 2;
- end_size.height = workarea.height;
- break;
- case GDK_WIN32_AEROSNAP_STATE_HALFRIGHT:
- end_size.x = (workarea.x + workarea.width / 2);
- end_size.y = workarea.y;
- end_size.width = workarea.width / 2;
- end_size.height = workarea.height;
- break;
- case GDK_WIN32_AEROSNAP_STATE_FULLUP:
- end_size.y = 0;
- end_size.height = maxysize;
- break;
- }
-
- start_indicator_drawing (context, start_size, end_size, impl->window_scale);
-}
-
-static void
-stop_indicator (GdkSurface *window,
- GdkW32DragMoveResizeContext *context)
-{
- GDK_NOTE (MISC, g_print ("Stop drawing snap indicator\n"));
-
- if (context->timer)
- {
- g_source_remove (context->timer);
- context->timer = 0;
- }
-
- API_CALL (SetWindowPos, (context->shape_indicator,
- SWP_NOZORDER_SPECIFIED,
- 0, 0, 0, 0,
- SWP_NOZORDER | SWP_NOMOVE |
- SWP_NOSIZE | SWP_NOREDRAW | SWP_HIDEWINDOW | SWP_NOACTIVATE));
-}
-
-static gint
-point_in_aerosnap_region (gint x,
- gint y,
- AeroSnapEdgeRegion *region)
-{
- gint edge, trigger;
-
- edge = (x >= region->edge.x &&
- y >= region->edge.y &&
- x <= region->edge.x + region->edge.width &&
- y <= region->edge.y + region->edge.height) ? 1 : 0;
- trigger = (x >= region->trigger.x &&
- y >= region->trigger.y &&
- x <= region->trigger.x + region->trigger.width &&
- y <= region->trigger.y + region->trigger.height) ? 1 : 0;
- return edge + trigger;
-}
-
-static void
-handle_aerosnap_move_resize (GdkSurface *window,
- GdkW32DragMoveResizeContext *context,
- gint x,
- gint y)
-{
- gint i;
- AeroSnapEdgeRegion *reg;
- gint maximize = 0;
- gint halfleft = 0;
- gint halfright = 0;
- gint fullup = 0;
- gboolean fullup_edge = FALSE;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- if (context->op == GDK_WIN32_DRAGOP_RESIZE)
- switch (context->edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- case GDK_SURFACE_EDGE_NORTH_EAST:
- case GDK_SURFACE_EDGE_WEST:
- case GDK_SURFACE_EDGE_EAST:
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- break;
- case GDK_SURFACE_EDGE_SOUTH:
- case GDK_SURFACE_EDGE_NORTH:
- fullup_edge = TRUE;
- break;
- }
-
- for (i = 0; i < context->maximize_regions->len && maximize == 0; i++)
- {
- reg = &g_array_index (context->maximize_regions, AeroSnapEdgeRegion, i);
- maximize = point_in_aerosnap_region (x, y, reg);
- }
-
- for (i = 0; i < context->halfleft_regions->len && halfleft == 0; i++)
- {
- reg = &g_array_index (context->halfleft_regions, AeroSnapEdgeRegion, i);
- halfleft = point_in_aerosnap_region (x, y, reg);
- }
-
- for (i = 0; i < context->halfright_regions->len && halfright == 0; i++)
- {
- reg = &g_array_index (context->halfright_regions, AeroSnapEdgeRegion, i);
- halfright = point_in_aerosnap_region (x, y, reg);
- }
-
- for (i = 0; i < context->fullup_regions->len && fullup == 0; i++)
- {
- reg = &g_array_index (context->fullup_regions, AeroSnapEdgeRegion, i);
- fullup = point_in_aerosnap_region (x, y, reg);
- }
-
-#if defined(MORE_AEROSNAP_DEBUGGING)
- GDK_NOTE (MISC, g_print ("AeroSnap: point %d : %d - max: %d, left %d, right %d, up %d\n",
- x, y, maximize, halfleft, halfright, fullup));
-#endif
-
- if (!context->revealed)
- {
- if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize == 2)
- {
- context->revealed = TRUE;
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_MAXIMIZE;
- start_indicator (window, context, x, y, context->current_snap);
- }
- else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft == 2)
- {
- context->revealed = TRUE;
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
- start_indicator (window, context, x, y, context->current_snap);
- }
- else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright == 2)
- {
- context->revealed = TRUE;
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
- start_indicator (window, context, x, y, context->current_snap);
- }
- else if (context->op == GDK_WIN32_DRAGOP_RESIZE && fullup == 2 && fullup_edge)
- {
- context->revealed = TRUE;
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_FULLUP;
- start_indicator (window, context, x, y, context->current_snap);
- }
-
- return;
- }
-
- switch (context->current_snap)
- {
- case GDK_WIN32_AEROSNAP_STATE_UNDETERMINED:
- if (context->op == GDK_WIN32_DRAGOP_RESIZE && fullup > 0)
- {
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_FULLUP;
- start_indicator (window, context, x, y, context->current_snap);
- }
- break;
- case GDK_WIN32_AEROSNAP_STATE_MAXIMIZE:
- if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize > 0)
- break;
- if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft > 0)
- {
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
- start_indicator (window, context, x, y, context->current_snap);
- }
- else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright > 0)
- {
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
- start_indicator (window, context, x, y, context->current_snap);
- }
- else
- {
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
- stop_indicator (window, context);
- context->revealed = FALSE;
- }
- break;
- case GDK_WIN32_AEROSNAP_STATE_HALFLEFT:
- if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft > 0)
- break;
- if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize > 0)
- {
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_MAXIMIZE;
- start_indicator (window, context, x, y, context->current_snap);
- }
- else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright > 0)
- {
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
- start_indicator (window, context, x, y, context->current_snap);
- }
- else
- {
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
- stop_indicator (window, context);
- context->revealed = FALSE;
- }
- break;
- case GDK_WIN32_AEROSNAP_STATE_HALFRIGHT:
- if (context->op == GDK_WIN32_DRAGOP_MOVE && halfright > 0)
- break;
- if (context->op == GDK_WIN32_DRAGOP_MOVE && maximize > 0)
- {
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_MAXIMIZE;
- start_indicator (window, context, x, y, context->current_snap);
- }
- else if (context->op == GDK_WIN32_DRAGOP_MOVE && halfleft > 0)
- {
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
- start_indicator (window, context, x, y, context->current_snap);
- }
- else
- {
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
- stop_indicator (window, context);
- context->revealed = FALSE;
- }
- break;
- case GDK_WIN32_AEROSNAP_STATE_FULLUP:
- if (context->op == GDK_WIN32_DRAGOP_RESIZE && fullup > 0 && fullup_edge)
- {
- update_fullup_indicator (window, context);
- break;
- }
-
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
- stop_indicator (window, context);
- break;
- }
-}
-
-
-static const gchar *
-get_cursor_name_from_op (GdkW32WindowDragOp op,
- GdkSurfaceEdge edge)
-{
- switch (op)
- {
- case GDK_WIN32_DRAGOP_MOVE:
- return "move";
- case GDK_WIN32_DRAGOP_RESIZE:
- switch (edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- return "nw-resize";
- case GDK_SURFACE_EDGE_NORTH:
- return "n-resize";
- case GDK_SURFACE_EDGE_NORTH_EAST:
- return "ne-resize";
- case GDK_SURFACE_EDGE_WEST:
- return "w-resize";
- case GDK_SURFACE_EDGE_EAST:
- return "e-resize";
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- return "sw-resize";
- case GDK_SURFACE_EDGE_SOUTH:
- return "s-resize";
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- return "se-resize";
- }
- /* default: warn about unhandled enum values,
- * fallthrough to GDK_WIN32_DRAGOP_NONE case
- */
- case GDK_WIN32_DRAGOP_COUNT:
- g_assert_not_reached ();
- case GDK_WIN32_DRAGOP_NONE:
- return "default";
- /* default: warn about unhandled enum values */
- }
-
- g_assert_not_reached ();
-
- return NULL;
-}
-
-static gboolean
-point_in_window (GdkSurface *window,
- gdouble x,
- gdouble y)
-{
- return x >= 0 && x < window->width &&
- y >= 0 && y < window->height &&
- (window->shape == NULL ||
- cairo_region_contains_point (window->shape, x, y)) &&
- (window->input_shape == NULL ||
- cairo_region_contains_point (window->input_shape, x, y));
-}
-
-static GdkSurface *
-child_window_at_coordinates (GdkSurface *window,
- gint root_x,
- gint root_y)
-{
- gint x, y;
- GList *l;
- GList *children;
-
- children = gdk_surface_peek_children (window);
- gdk_surface_get_root_origin (window, &x, &y);
- x = root_x - x;
- y = root_y - y;
-
- for (l = children; l; l = g_list_next (l))
- {
- GdkSurface *child = GDK_SURFACE (l->data);
-
- if (point_in_window (child, x, y))
- return child;
- }
-
- return window;
-}
-
-static void
-setup_drag_move_resize_context (GdkSurface *window,
- GdkW32DragMoveResizeContext *context,
- GdkW32WindowDragOp op,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- RECT rect;
- const gchar *cursor_name;
- GdkSurface *pointer_window;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- GdkDisplay *display = gdk_device_get_display (device);
- gboolean maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
-
- /* Before we drag, we need to undo any maximization or snapping.
- * AeroSnap behaviour:
- * If snapped halfleft/halfright:
- * horizontal resize:
- * resize
- * don't unsnap
- * keep stashed unsnapped size intact
- * vertical resize:
- * resize
- * unsnap to new size (merge cached unsnapped state with current
- * snapped state in such a way that the gripped edge
- * does not move)
- * diagonal resize:
- * difficult to test (first move is usually either purely
- * horizontal or purely vertical, in which
- * case the above behaviour applies)
- * If snapped up:
- * horizontal resize:
- * resize
- * don't unsnap
- * apply new width and x position to unsnapped cache,
- * so that unsnapped window only regains its height
- * and y position, but inherits x and width from
- * the fullup snapped state
- * vertical resize:
- * unsnap to new size (merge cached unsnapped state with current
- * snapped state in such a way that the gripped edge
- * does not move)
- *
- * This implementation behaviour:
- * If snapped halfleft/halfright/fullup:
- * any resize:
- * unsnap to current size, discard cached pre-snap state
- *
- * TODO: make this implementation behave as AeroSnap on resizes?
- * There's also the case where
- * a halfleft/halfright window isn't unsnapped when it's
- * being moved horizontally, but it's more difficult to implement.
- */
- if (op == GDK_WIN32_DRAGOP_RESIZE &&
- (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT ||
- impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT ||
- impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP))
- {
- discard_snapinfo (window);
- }
- else if (maximized ||
- (impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFRIGHT ||
- impl->snap_state == GDK_WIN32_AEROSNAP_STATE_HALFLEFT ||
- impl->snap_state == GDK_WIN32_AEROSNAP_STATE_FULLUP))
- {
- GdkMonitor *monitor;
- gint wx, wy, wwidth, wheight;
- gint swx, swy, swwidth, swheight;
- gboolean pointer_outside_of_window;
- gint offsetx, offsety;
- gboolean left_half;
- GdkDisplay *display;
-
- display = gdk_surface_get_display (window);
- monitor = gdk_display_get_monitor_at_window (display, window);
- gdk_surface_get_geometry (window, &wx, &wy, &wwidth, &wheight);
-
- swx = wx;
- swy = wy;
- swwidth = wwidth;
- swheight = wheight;
-
- /* Subtract window shadow. We don't want pointer to go outside of
- * the visible window during drag-move. For drag-resize it's OK.
- * Don't take shadow into account if the window is maximized -
- * maximized windows don't have shadows.
- */
- if (op == GDK_WIN32_DRAGOP_MOVE && !maximized)
- {
- swx += impl->margins.left / impl->window_scale;
- swy += impl->margins.top / impl->window_scale;
- swwidth -= impl->margins_x;
- swheight -= impl->margins_y;
- }
-
- pointer_outside_of_window = root_x < swx || root_x > swx + swwidth ||
- root_y < swy || root_y > swy + swheight;
- /* Calculate the offset of the pointer relative to the window */
- offsetx = root_x - swx;
- offsety = root_y - swy;
-
- /* Figure out in which half of the window the pointer is.
- * The code currently only concerns itself with horizontal
- * dimension (left/right halves).
- * There's no upper/lower half, because usually window
- * is dragged by its upper half anyway. If that changes, adjust
- * accordingly.
- */
- left_half = (offsetx < swwidth / 2);
-
- /* Inverse the offset for it to be from the right edge */
- if (!left_half)
- offsetx = swwidth - offsetx;
-
- GDK_NOTE (MISC, g_print ("Pointer at %d : %d, this is %d : %d relative to the window's %s\n",
- root_x, root_y, offsetx, offsety,
- left_half ? "left half" : "right half"));
-
- /* Move window in such a way that on unmaximization/unsnapping the pointer
- * is still pointing at the appropriate half of the window,
- * with the same offset from the left or right edge. If the new
- * window size is too small, and adding that offset puts the pointer
- * into the other half or even beyond, move the pointer to the middle.
- */
- if (!pointer_outside_of_window && maximized)
- {
- WINDOWPLACEMENT placement;
- gint unmax_width, unmax_height;
- gint shadow_unmax_width, shadow_unmax_height;
-
- placement.length = sizeof (placement);
- API_CALL (GetWindowPlacement, (GDK_SURFACE_HWND (window), &placement));
-
- GDK_NOTE (MISC, g_print ("W32 WM unmaximized window placement is %ld x %ld @ %ld : %ld\n",
- placement.rcNormalPosition.right - placement.rcNormalPosition.left,
- placement.rcNormalPosition.bottom - placement.rcNormalPosition.top,
- placement.rcNormalPosition.left + _gdk_offset_x * impl->window_scale,
- placement.rcNormalPosition.top + _gdk_offset_y * impl->window_scale));
-
- unmax_width = placement.rcNormalPosition.right - placement.rcNormalPosition.left;
- unmax_height = placement.rcNormalPosition.bottom - placement.rcNormalPosition.top;
-
- shadow_unmax_width = unmax_width - impl->margins_x * impl->window_scale;
- shadow_unmax_height = unmax_height - impl->margins_y * impl->window_scale;
-
- if (offsetx * impl->window_scale < (shadow_unmax_width / 2) &&
- offsety * impl->window_scale < (shadow_unmax_height / 2))
- {
- placement.rcNormalPosition.top = (root_y - offsety + impl->margins.top - _gdk_offset_y) * impl->window_scale;
- placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + unmax_height;
-
- if (left_half)
- {
- placement.rcNormalPosition.left = (root_x - offsetx + impl->margins.left - _gdk_offset_x) * impl->window_scale;
- placement.rcNormalPosition.right = placement.rcNormalPosition.left + unmax_width;
- }
- else
- {
- placement.rcNormalPosition.right = (root_x + offsetx + impl->margins.right - _gdk_offset_x) * impl->window_scale;
- placement.rcNormalPosition.left = placement.rcNormalPosition.right - unmax_width;
- }
- }
- else
- {
- placement.rcNormalPosition.left = (root_x * impl->window_scale) -
- (unmax_width / 2) -
- (_gdk_offset_x * impl->window_scale);
-
- if (offsety * impl->window_scale < shadow_unmax_height / 2)
- placement.rcNormalPosition.top = (root_y - offsety + impl->margins.top - _gdk_offset_y) * impl->window_scale;
- else
- placement.rcNormalPosition.top = (root_y * impl->window_scale) -
- (unmax_height / 2) -
- (_gdk_offset_y * impl->window_scale);
-
- placement.rcNormalPosition.right = placement.rcNormalPosition.left + unmax_width;
- placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + unmax_height;
- }
-
- GDK_NOTE (MISC, g_print ("Unmaximized window will be at %ld : %ld\n",
- placement.rcNormalPosition.left + _gdk_offset_x * impl->window_scale,
- placement.rcNormalPosition.top + _gdk_offset_y * impl->window_scale));
-
- API_CALL (SetWindowPlacement, (GDK_SURFACE_HWND (window), &placement));
- }
- else if (!pointer_outside_of_window && impl->snap_stash_int)
- {
- GdkRectangle new_pos;
- GdkRectangle snew_pos;
-
- new_pos.width = impl->snap_stash_int->width;
- new_pos.height = impl->snap_stash_int->height;
- snew_pos = new_pos;
-
- if (op == GDK_WIN32_DRAGOP_MOVE)
- {
- snew_pos.width -= impl->margins_x;
- snew_pos.height -= impl->margins_y;
- }
-
- if (offsetx < snew_pos.width / 2 && offsety < snew_pos.height / 2)
- {
- new_pos.y = root_y - offsety + impl->margins.top / impl->window_scale;
-
- if (left_half)
- new_pos.x = root_x - offsetx + impl->margins.left / impl->window_scale;
- else
- new_pos.x = root_x + offsetx + impl->margins.left / impl->window_scale - new_pos.width;
- }
- else
- {
- new_pos.x = root_x - new_pos.width / 2;
- new_pos.y = root_y - new_pos.height / 2;
- }
-
- GDK_NOTE (MISC, g_print ("Unsnapped window to %d : %d\n",
- new_pos.x, new_pos.y));
- discard_snapinfo (window);
- gdk_surface_move_resize (window, new_pos.x, new_pos.y,
- new_pos.width, new_pos.height);
- }
-
-
- if (maximized)
- gdk_surface_unmaximize (window);
- else
- unsnap (window, monitor);
-
- if (pointer_outside_of_window)
- {
- /* Pointer outside of the window, move pointer into window */
- GDK_NOTE (MISC, g_print ("Pointer at %d : %d is outside of %d x %d @ %d : %d, move it to %d : %d\n",
- root_x, root_y, wwidth, wheight, wx, wy, wx + wwidth / 2, wy + wheight / 2));
- root_x = wx + wwidth / 2;
- /* This is Gnome behaviour. Windows WM would put the pointer
- * in the middle of the titlebar, but GDK doesn't know where
- * the titlebar is, if any.
- */
- root_y = wy + wheight / 2;
- gdk_device_warp (device, root_x, root_y);
- }
- }
-
- _gdk_win32_get_window_rect (window, &rect);
-
- cursor_name = get_cursor_name_from_op (op, edge);
-
- context->cursor = gdk_cursor_new_from_name (cursor_name, NULL);
-
- pointer_window = child_window_at_coordinates (window, root_x, root_y);
-
- /* Note: This triggers a WM_CAPTURECHANGED, which will trigger
- * gdk_win32_surface_end_move_resize_drag(), which will end
- * our op before it even begins, but only if context->op is not NONE.
- * This is why we first do the grab, *then* set the op.
- */
- gdk_device_grab (device, pointer_window,
- GDK_OWNERSHIP_NONE, FALSE,
- GDK_ALL_EVENTS_MASK,
- context->cursor,
- timestamp);
-
- context->window = g_object_ref (window);
- context->op = op;
- context->edge = edge;
- context->device = device;
- context->button = button;
- context->start_root_x = root_x;
- context->start_root_y = root_y;
- context->timestamp = timestamp;
- context->start_rect = rect;
-
- context->shape_indicator = NULL;
- context->revealed = FALSE;
- context->halfleft_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
- context->halfright_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
- context->maximize_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
- context->fullup_regions = g_array_new (FALSE, FALSE, sizeof (AeroSnapEdgeRegion));
-
- calculate_aerosnap_regions (context);
-
- GDK_NOTE (EVENTS,
- g_print ("begin drag moveresize: window %p, toplevel %p, "
- "op %u, edge %d, device %p, "
- "button %d, coord %d:%d, time %u\n",
- pointer_window, gdk_surface_get_toplevel (window),
- context->op, context->edge, context->device,
- context->button, context->start_root_x,
- context->start_root_y, context->timestamp));
-}
-
-void
-gdk_win32_surface_end_move_resize_drag (GdkSurface *window)
-{
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- GdkW32DragMoveResizeContext *context = &impl->drag_move_resize_context;
-
- context->op = GDK_WIN32_DRAGOP_NONE;
-
- gdk_device_ungrab (context->device, GDK_CURRENT_TIME);
-
- g_clear_object (&context->cursor);
-
- context->revealed = FALSE;
-
- if (context->timer)
- {
- g_source_remove (context->timer);
- context->timer = 0;
- }
-
- g_clear_object (&context->window);
-
- if (context->indicator_surface)
- {
- cairo_surface_destroy (context->indicator_surface);
- context->indicator_surface = NULL;
- }
-
- if (context->shape_indicator)
- {
- stop_indicator (window, context);
- DestroyWindow (context->shape_indicator);
- context->shape_indicator = NULL;
- }
-
- g_clear_pointer (&context->halfleft_regions, g_array_unref);
- g_clear_pointer (&context->halfright_regions, g_array_unref);
- g_clear_pointer (&context->maximize_regions, g_array_unref);
- g_clear_pointer (&context->fullup_regions, g_array_unref);
-
- GDK_NOTE (EVENTS,
- g_print ("end drag moveresize: window %p, toplevel %p,"
- "op %u, edge %d, device %p, "
- "button %d, coord %d:%d, time %u\n",
- window, gdk_surface_get_toplevel (window),
- context->op, context->edge, context->device,
- context->button, context->start_root_x,
- context->start_root_y, context->timestamp));
-
- if (context->current_snap != GDK_WIN32_AEROSNAP_STATE_UNDETERMINED)
- apply_snap (window, context->current_snap);
-
- context->current_snap = GDK_WIN32_AEROSNAP_STATE_UNDETERMINED;
-}
-
-static void
-gdk_win32_get_window_size_and_position_from_client_rect (GdkSurface *window,
- RECT *window_rect,
- SIZE *window_size,
- POINT *window_position)
-{
- GdkSurfaceImplWin32 *impl;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- /* Turn client area into window area */
- _gdk_win32_adjust_client_rect (window, window_rect);
-
- /* Convert GDK screen coordinates to W32 desktop coordinates */
- window_rect->left -= _gdk_offset_x * impl->window_scale;
- window_rect->right -= _gdk_offset_x * impl->window_scale;
- window_rect->top -= _gdk_offset_y * impl->window_scale;
- window_rect->bottom -= _gdk_offset_y * impl->window_scale;
-
- window_position->x = window_rect->left;
- window_position->y = window_rect->top;
- window_size->cx = window_rect->right - window_rect->left;
- window_size->cy = window_rect->bottom - window_rect->top;
-}
-
-static void
-gdk_win32_update_layered_window_from_cache (GdkSurface *window,
- RECT *client_rect)
-{
- POINT window_position;
- SIZE window_size;
- BLENDFUNCTION blender;
- HDC hdc;
- SIZE *window_size_ptr;
- POINT source_point = { 0, 0 };
- POINT *source_point_ptr;
- GdkSurfaceImplWin32 *impl;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- gdk_win32_get_window_size_and_position_from_client_rect (window,
- client_rect,
- &window_size,
- &window_position);
-
- blender.BlendOp = AC_SRC_OVER;
- blender.BlendFlags = 0;
- blender.AlphaFormat = AC_SRC_ALPHA;
- blender.SourceConstantAlpha = impl->layered_opacity * 255;
-
- /* Size didn't change, so move immediately, no need to wait for redraw */
- /* Strictly speaking, we don't need to supply hdc, source_point and
- * window_size here. However, without these arguments
- * the window moves but does not update its contents on Windows 7 when
- * desktop composition is off. This forces us to provide hdc and
- * source_point. window_size is here to avoid the function
- * inexplicably failing with error 317.
- */
- if (gdk_display_is_composited (gdk_surface_get_display (window)))
- {
- hdc = NULL;
- window_size_ptr = NULL;
- source_point_ptr = NULL;
- }
- else
- {
- hdc = cairo_win32_surface_get_dc (impl->cache_surface);
- window_size_ptr = &window_size;
- source_point_ptr = &source_point;
- }
-
- API_CALL (UpdateLayeredWindow, (GDK_SURFACE_HWND (window), NULL,
- &window_position, window_size_ptr,
- hdc, source_point_ptr,
- 0, &blender, ULW_ALPHA));
-}
-
-void
-gdk_win32_surface_do_move_resize_drag (GdkSurface *window,
- gint x,
- gint y)
-{
- RECT rect;
- RECT new_rect;
- gint diffy, diffx;
- MINMAXINFO mmi;
- GdkSurfaceImplWin32 *impl;
- GdkW32DragMoveResizeContext *context;
- gint width;
- gint height;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
- context = &impl->drag_move_resize_context;
-
- if (!_gdk_win32_get_window_rect (window, &rect))
- return;
-
- new_rect = context->start_rect;
- diffx = (x - context->start_root_x) * impl->window_scale;
- diffy = (y - context->start_root_y) * impl->window_scale;
-
- switch (context->op)
- {
- case GDK_WIN32_DRAGOP_RESIZE:
-
- switch (context->edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- new_rect.left += diffx;
- new_rect.top += diffy;
- break;
-
- case GDK_SURFACE_EDGE_NORTH:
- new_rect.top += diffy;
- break;
-
- case GDK_SURFACE_EDGE_NORTH_EAST:
- new_rect.right += diffx;
- new_rect.top += diffy;
- break;
-
- case GDK_SURFACE_EDGE_WEST:
- new_rect.left += diffx;
- break;
-
- case GDK_SURFACE_EDGE_EAST:
- new_rect.right += diffx;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- new_rect.left += diffx;
- new_rect.bottom += diffy;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH:
- new_rect.bottom += diffy;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- default:
- new_rect.right += diffx;
- new_rect.bottom += diffy;
- break;
- }
-
- /* When handling WM_GETMINMAXINFO, mmi is already populated
- * by W32 WM and we apply our stuff on top of that.
- * Here it isn't, so we should at least clear it.
- */
- memset (&mmi, 0, sizeof (mmi));
-
- if (!_gdk_win32_surface_fill_min_max_info (window, &mmi))
- break;
-
- width = new_rect.right - new_rect.left;
- height = new_rect.bottom - new_rect.top;
-
- if (width > mmi.ptMaxTrackSize.x)
- {
- switch (context->edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- case GDK_SURFACE_EDGE_WEST:
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- new_rect.left = new_rect.right - mmi.ptMaxTrackSize.x;
- break;
-
- case GDK_SURFACE_EDGE_NORTH_EAST:
- case GDK_SURFACE_EDGE_EAST:
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- default:
- new_rect.right = new_rect.left + mmi.ptMaxTrackSize.x;
- break;
- }
- }
- else if (width < mmi.ptMinTrackSize.x)
- {
- switch (context->edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- case GDK_SURFACE_EDGE_WEST:
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- new_rect.left = new_rect.right - mmi.ptMinTrackSize.x;
- break;
-
- case GDK_SURFACE_EDGE_NORTH_EAST:
- case GDK_SURFACE_EDGE_EAST:
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- default:
- new_rect.right = new_rect.left + mmi.ptMinTrackSize.x;
- break;
- }
- }
-
- if (height > mmi.ptMaxTrackSize.y)
- {
- switch (context->edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- case GDK_SURFACE_EDGE_NORTH:
- case GDK_SURFACE_EDGE_NORTH_EAST:
- new_rect.top = new_rect.bottom - mmi.ptMaxTrackSize.y;
-
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- case GDK_SURFACE_EDGE_SOUTH:
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- default:
- new_rect.bottom = new_rect.top + mmi.ptMaxTrackSize.y;
- break;
- }
- }
- else if (height < mmi.ptMinTrackSize.y)
- {
- switch (context->edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- case GDK_SURFACE_EDGE_NORTH:
- case GDK_SURFACE_EDGE_NORTH_EAST:
- new_rect.top = new_rect.bottom - mmi.ptMinTrackSize.y;
-
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- case GDK_SURFACE_EDGE_SOUTH:
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- default:
- new_rect.bottom = new_rect.top + mmi.ptMinTrackSize.y;
- break;
- }
- }
-
- break;
- case GDK_WIN32_DRAGOP_MOVE:
- new_rect.left += diffx;
- new_rect.top += diffy;
- new_rect.right += diffx;
- new_rect.bottom += diffy;
- break;
- default:
- break;
- }
-
- if (context->op == GDK_WIN32_DRAGOP_RESIZE &&
- (rect.left != new_rect.left ||
- rect.right != new_rect.right ||
- rect.top != new_rect.top ||
- rect.bottom != new_rect.bottom))
- {
- context->native_move_resize_pending = TRUE;
- _gdk_win32_do_emit_configure_event (window, new_rect);
- }
- else if (context->op == GDK_WIN32_DRAGOP_MOVE &&
- (rect.left != new_rect.left ||
- rect.top != new_rect.top))
- {
- context->native_move_resize_pending = FALSE;
-
- _gdk_win32_do_emit_configure_event (window, new_rect);
-
- if (impl->layered)
- {
- gdk_win32_update_layered_window_from_cache (window, &new_rect);
- }
- else
- {
- SIZE window_size;
- POINT window_position;
-
- gdk_win32_get_window_size_and_position_from_client_rect (window,
- &new_rect,
- &window_size,
- &window_position);
-
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- SWP_NOZORDER_SPECIFIED,
- window_position.x, window_position.y,
- 0, 0,
- SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE));
- }
- }
-
- if (context->op == GDK_WIN32_DRAGOP_RESIZE ||
- context->op == GDK_WIN32_DRAGOP_MOVE)
- handle_aerosnap_move_resize (window, context, x, y);
-}
-
-static void
-gdk_win32_surface_begin_resize_drag (GdkSurface *window,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GdkSurfaceImplWin32 *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- IsIconic (GDK_SURFACE_HWND (window)))
- return;
-
- /* Tell Windows to start interactively resizing the window by pretending that
- * the left pointer button was clicked in the suitable edge or corner. This
- * will only work if the button is down when this function is called, and
- * will only work with button 1 (left), since Windows only allows window
- * dragging using the left mouse button.
- */
-
- if (button != 1)
- return;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
- gdk_win32_surface_end_move_resize_drag (window);
-
- setup_drag_move_resize_context (window, &impl->drag_move_resize_context,
- GDK_WIN32_DRAGOP_RESIZE, edge, device,
- button, root_x, root_y, timestamp);
-}
-
-static void
-gdk_win32_surface_begin_move_drag (GdkSurface *window,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GdkSurfaceImplWin32 *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- IsIconic (GDK_SURFACE_HWND (window)))
- return;
-
- /* Tell Windows to start interactively moving the window by pretending that
- * the left pointer button was clicked in the titlebar. This will only work
- * if the button is down when this function is called, and will only work
- * with button 1 (left), since Windows only allows window dragging using the
- * left mouse button.
- */
- if (button != 1)
- return;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
- gdk_win32_surface_end_move_resize_drag (window);
-
- setup_drag_move_resize_context (window, &impl->drag_move_resize_context,
- GDK_WIN32_DRAGOP_MOVE, GDK_SURFACE_EDGE_NORTH_WEST,
- device, button, root_x, root_y, timestamp);
-}
-
-
-/*
- * Setting window states
- */
-static void
-gdk_win32_surface_iconify (GdkSurface *window)
-{
- HWND old_active_window;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_surface_iconify: %p: %s\n",
- GDK_SURFACE_HWND (window),
- _gdk_win32_surface_state_to_string (window->state)));
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- old_active_window = GetActiveWindow ();
- GtkShowWindow (window, SW_MINIMIZE);
- if (old_active_window != GDK_SURFACE_HWND (window))
- SetActiveWindow (old_active_window);
- }
- else
- {
- gdk_synthesize_window_state (window,
- 0,
- GDK_SURFACE_STATE_ICONIFIED);
- }
-}
-
-static void
-gdk_win32_surface_deiconify (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_surface_deiconify: %p: %s\n",
- GDK_SURFACE_HWND (window),
- _gdk_win32_surface_state_to_string (window->state)));
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- show_window_internal (window, GDK_SURFACE_IS_MAPPED (window), TRUE);
- }
- else
- {
- gdk_synthesize_window_state (window,
- GDK_SURFACE_STATE_ICONIFIED,
- 0);
- }
-}
-
-static void
-gdk_win32_surface_stick (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- /* FIXME: Do something? */
-}
-
-static void
-gdk_win32_surface_unstick (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- /* FIXME: Do something? */
-}
-
-static void
-gdk_win32_surface_maximize (GdkSurface *window)
-{
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_surface_maximize: %p: %s\n",
- GDK_SURFACE_HWND (window),
- _gdk_win32_surface_state_to_string (window->state)));
-
- if (GDK_SURFACE_IS_MAPPED (window))
- GtkShowWindow (window, SW_MAXIMIZE);
- else
- gdk_synthesize_window_state (window,
- 0,
- GDK_SURFACE_STATE_MAXIMIZED);
-}
-
-static void
-gdk_win32_surface_unmaximize (GdkSurface *window)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_surface_unmaximize: %p: %s\n",
- GDK_SURFACE_HWND (window),
- _gdk_win32_surface_state_to_string (window->state)));
-
- if (GDK_SURFACE_IS_MAPPED (window))
- GtkShowWindow (window, SW_RESTORE);
- else
- gdk_synthesize_window_state (window,
- GDK_SURFACE_STATE_MAXIMIZED,
- 0);
-}
-
-static void
-gdk_win32_surface_fullscreen (GdkSurface *window)
-{
- gint x, y, width, height;
- FullscreenInfo *fi;
- HMONITOR monitor;
- MONITORINFO mi;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- fi = g_new (FullscreenInfo, 1);
-
- if (!GetWindowRect (GDK_SURFACE_HWND (window), &(fi->r)))
- g_free (fi);
- else
- {
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- monitor = MonitorFromWindow (GDK_SURFACE_HWND (window), MONITOR_DEFAULTTONEAREST);
- mi.cbSize = sizeof (mi);
- if (monitor && GetMonitorInfo (monitor, &mi))
- {
- x = mi.rcMonitor.left;
- y = mi.rcMonitor.top;
- width = mi.rcMonitor.right - x;
- height = mi.rcMonitor.bottom - y;
- }
- else
- {
- x = y = 0;
- width = GetSystemMetrics (SM_CXSCREEN);
- height = GetSystemMetrics (SM_CYSCREEN);
- }
-
- /* remember for restoring */
- fi->hint_flags = impl->hint_flags;
- impl->hint_flags &= ~GDK_HINT_MAX_SIZE;
- g_object_set_data (G_OBJECT (window), "fullscreen-info", fi);
- fi->style = GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE);
-
- /* Send state change before configure event */
- gdk_synthesize_window_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
-
- SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE,
- (fi->style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP);
-
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_TOP,
- x, y, width, height,
- SWP_NOCOPYBITS | SWP_SHOWWINDOW));
- }
-}
-
-static void
-gdk_win32_surface_unfullscreen (GdkSurface *window)
-{
- FullscreenInfo *fi;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- fi = g_object_get_data (G_OBJECT (window), "fullscreen-info");
- if (fi)
- {
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- gdk_synthesize_window_state (window, GDK_SURFACE_STATE_FULLSCREEN, 0);
-
- impl->hint_flags = fi->hint_flags;
- SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE, fi->style);
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window), HWND_NOTOPMOST,
- fi->r.left, fi->r.top,
- fi->r.right - fi->r.left, fi->r.bottom - fi->r.top,
- SWP_NOCOPYBITS | SWP_SHOWWINDOW));
-
- g_object_set_data (G_OBJECT (window), "fullscreen-info", NULL);
- g_free (fi);
- _gdk_win32_surface_update_style_bits (window);
- }
-}
-
-static void
-gdk_win32_surface_set_keep_above (GdkSurface *window,
- gboolean setting)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_surface_set_keep_above: %p: %s\n",
- GDK_SURFACE_HWND (window),
- setting ? "YES" : "NO"));
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- setting ? HWND_TOPMOST : HWND_NOTOPMOST,
- 0, 0, 0, 0,
- SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
- }
-
- gdk_synthesize_window_state (window,
- setting ? GDK_SURFACE_STATE_BELOW : GDK_SURFACE_STATE_ABOVE,
- setting ? GDK_SURFACE_STATE_ABOVE : 0);
-}
-
-static void
-gdk_win32_surface_set_keep_below (GdkSurface *window,
- gboolean setting)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_surface_set_keep_below: %p: %s\n",
- GDK_SURFACE_HWND (window),
- setting ? "YES" : "NO"));
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- setting ? HWND_BOTTOM : HWND_NOTOPMOST,
- 0, 0, 0, 0,
- SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE));
- }
-
- gdk_synthesize_window_state (window,
- setting ? GDK_SURFACE_STATE_ABOVE : GDK_SURFACE_STATE_BELOW,
- setting ? GDK_SURFACE_STATE_BELOW : 0);
-}
-
-static void
-gdk_win32_surface_focus (GdkSurface *window,
- guint32 timestamp)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_surface_focus: %p: %s\n",
- GDK_SURFACE_HWND (window),
- _gdk_win32_surface_state_to_string (window->state)));
-
- if (window->state & GDK_SURFACE_STATE_MAXIMIZED)
- GtkShowWindow (window, SW_SHOWMAXIMIZED);
- else if (window->state & GDK_SURFACE_STATE_ICONIFIED)
- GtkShowWindow (window, SW_RESTORE);
- else if (!IsWindowVisible (GDK_SURFACE_HWND (window)))
- GtkShowWindow (window, SW_SHOWNORMAL);
- else
- GtkShowWindow (window, SW_SHOW);
-
- SetFocus (GDK_SURFACE_HWND (window));
-}
-
-static void
-gdk_win32_surface_set_modal_hint (GdkSurface *window,
- gboolean modal)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_surface_set_modal_hint: %p: %s\n",
- GDK_SURFACE_HWND (window),
- modal ? "YES" : "NO"));
-
- if (modal == window->modal_hint)
- return;
-
- window->modal_hint = modal;
-
-#if 0
- /* Not sure about this one.. -- Cody */
- if (GDK_SURFACE_IS_MAPPED (window))
- API_CALL (SetWindowPos, (GDK_SURFACE_HWND (window),
- modal ? HWND_TOPMOST : HWND_NOTOPMOST,
- 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE));
-#else
-
- if (modal)
- {
- _gdk_push_modal_window (window);
- gdk_surface_raise (window);
- }
- else
- {
- _gdk_remove_modal_window (window);
- }
-
-#endif
-}
-
-static void
-gdk_win32_surface_set_skip_taskbar_hint (GdkSurface *window,
- gboolean skips_taskbar)
-{
- static GdkSurface *owner = NULL;
- //GdkSurfaceAttr wa;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- GDK_NOTE (MISC, g_print ("gdk_surface_set_skip_taskbar_hint: %p: %s, doing nothing\n",
- GDK_SURFACE_HWND (window),
- skips_taskbar ? "YES" : "NO"));
-
- // ### TODO: Need to figure out what to do here.
- return;
-
- if (skips_taskbar)
- {
-#if 0
- if (owner == NULL)
- {
- wa.window_type = GDK_SURFACE_TEMP;
- wa.wclass = GDK_INPUT_OUTPUT;
- wa.width = wa.height = 1;
- wa.event_mask = 0;
- owner = gdk_surface_new_internal (NULL, &wa, 0, TRUE);
- }
-#endif
-
- SetWindowLongPtr (GDK_SURFACE_HWND (window), GWLP_HWNDPARENT, (LONG_PTR) GDK_SURFACE_HWND (owner));
-
-#if 0 /* Should we also turn off the minimize and maximize buttons? */
- SetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE,
- GetWindowLong (GDK_SURFACE_HWND (window), GWL_STYLE) & ~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_SYSMENU));
-
- SetWindowPos (GDK_SURFACE_HWND (window), SWP_NOZORDER_SPECIFIED,
- 0, 0, 0, 0,
- SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE |
- SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
-#endif
- }
- else
- {
- SetWindowLongPtr (GDK_SURFACE_HWND (window), GWLP_HWNDPARENT, 0);
- }
-}
-
-static void
-gdk_win32_surface_set_skip_pager_hint (GdkSurface *window,
- gboolean skips_pager)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- GDK_NOTE (MISC, g_print ("gdk_surface_set_skip_pager_hint: %p: %s, doing nothing\n",
- GDK_SURFACE_HWND (window),
- skips_pager ? "YES" : "NO"));
-}
-
-static void
-gdk_win32_surface_set_type_hint (GdkSurface *window,
- GdkSurfaceTypeHint hint)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC,
- G_STMT_START{
- static GEnumClass *class = NULL;
- if (!class)
- class = g_type_class_ref (GDK_TYPE_SURFACE_TYPE_HINT);
- g_print ("gdk_surface_set_type_hint: %p: %s\n",
- GDK_SURFACE_HWND (window),
- g_enum_get_value (class, hint)->value_name);
- }G_STMT_END);
-
- ((GdkSurfaceImplWin32 *)window->impl)->type_hint = hint;
-
- _gdk_win32_surface_update_style_bits (window);
-}
-
-static GdkSurfaceTypeHint
-gdk_win32_surface_get_type_hint (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), GDK_SURFACE_TYPE_HINT_NORMAL);
-
- if (GDK_SURFACE_DESTROYED (window))
- return GDK_SURFACE_TYPE_HINT_NORMAL;
-
- return GDK_SURFACE_IMPL_WIN32 (window->impl)->type_hint;
-}
-
-static HRGN
-cairo_region_to_hrgn (const cairo_region_t *region,
- gint x_origin,
- gint y_origin,
- guint scale)
-{
- HRGN hrgn;
- RGNDATA *rgndata;
- RECT *rect;
- cairo_rectangle_int_t r;
- const int nrects = cairo_region_num_rectangles (region);
- guint nbytes =
- sizeof (RGNDATAHEADER) + (sizeof (RECT) * nrects);
- int i;
-
- rgndata = g_malloc (nbytes);
- rgndata->rdh.dwSize = sizeof (RGNDATAHEADER);
- rgndata->rdh.iType = RDH_RECTANGLES;
- rgndata->rdh.nCount = rgndata->rdh.nRgnSize = 0;
- SetRect (&rgndata->rdh.rcBound,
- G_MAXLONG, G_MAXLONG, G_MINLONG, G_MINLONG);
-
- for (i = 0; i < nrects; i++)
- {
- rect = ((RECT *) rgndata->Buffer) + rgndata->rdh.nCount++;
-
- cairo_region_get_rectangle (region, i, &r);
- rect->left = (r.x + x_origin) * scale;
- rect->right = (rect->left + r.width) * scale;
- rect->top = (r.y + y_origin) * scale;
- rect->bottom = (rect->top + r.height) * scale;
-
- if (rect->left < rgndata->rdh.rcBound.left)
- rgndata->rdh.rcBound.left = rect->left;
- if (rect->right > rgndata->rdh.rcBound.right)
- rgndata->rdh.rcBound.right = rect->right;
- if (rect->top < rgndata->rdh.rcBound.top)
- rgndata->rdh.rcBound.top = rect->top;
- if (rect->bottom > rgndata->rdh.rcBound.bottom)
- rgndata->rdh.rcBound.bottom = rect->bottom;
- }
- if ((hrgn = ExtCreateRegion (NULL, nbytes, rgndata)) == NULL)
- WIN32_API_FAILED ("ExtCreateRegion");
-
- g_free (rgndata);
-
- return (hrgn);
-}
-
-static void
-gdk_win32_surface_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
- GdkSurfaceImplWin32 *impl;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (!shape_region)
- {
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_shape_combine_region: %p: none\n",
- GDK_SURFACE_HWND (window)));
- SetWindowRgn (GDK_SURFACE_HWND (window), NULL, TRUE);
- }
- else
- {
- HRGN hrgn;
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- hrgn = cairo_region_to_hrgn (shape_region, 0, 0, impl->window_scale);
-
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_shape_combine_region: %p: %p\n",
- GDK_SURFACE_HWND (window),
- hrgn));
-
- do_shape_combine_region (window, hrgn, offset_x, offset_y);
- }
-}
-
-GdkSurface *
-gdk_win32_surface_lookup_for_display (GdkDisplay *display,
- HWND anid)
-{
- g_return_val_if_fail (display == gdk_display_get_default (), NULL);
-
- return (GdkSurface*) gdk_win32_handle_table_lookup (anid);
-}
-
-static void
-gdk_win32_surface_set_opacity (GdkSurface *window,
- gdouble opacity)
-{
- LONG exstyle;
- typedef BOOL (WINAPI *PFN_SetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
- PFN_SetLayeredWindowAttributes setLayeredWindowAttributes = NULL;
- GdkSurfaceImplWin32 *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (!WINDOW_IS_TOPLEVEL (window) || GDK_SURFACE_DESTROYED (window))
- return;
-
- if (opacity < 0)
- opacity = 0;
- else if (opacity > 1)
- opacity = 1;
-
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- if (impl->layered)
- {
- if (impl->layered_opacity != opacity)
- {
- RECT window_rect;
-
- impl->layered_opacity = opacity;
-
- gdk_win32_get_window_client_area_rect (window, impl->window_scale, &window_rect);
- gdk_win32_update_layered_window_from_cache (window, &window_rect);
- }
-
- return;
- }
-
- exstyle = GetWindowLong (GDK_SURFACE_HWND (window), GWL_EXSTYLE);
-
- if (!(exstyle & WS_EX_LAYERED))
- SetWindowLong (GDK_SURFACE_HWND (window),
- GWL_EXSTYLE,
- exstyle | WS_EX_LAYERED);
-
- setLayeredWindowAttributes =
- (PFN_SetLayeredWindowAttributes)GetProcAddress (GetModuleHandle ("user32.dll"), "SetLayeredWindowAttributes");
-
- if (setLayeredWindowAttributes)
- {
- API_CALL (setLayeredWindowAttributes, (GDK_SURFACE_HWND (window),
- 0,
- opacity * 0xff,
- LWA_ALPHA));
- }
-}
-
-gboolean
-gdk_win32_surface_is_win32 (GdkSurface *window)
-{
- return GDK_SURFACE_IS_WIN32 (window);
-}
-
-static gboolean
-gdk_win32_surface_show_window_menu (GdkSurface *window,
- GdkEvent *event)
-{
- double event_x, event_y;
- gint x, y;
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- switch (event->type)
- {
- case GDK_BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- case GDK_TOUCH_BEGIN:
- case GDK_TOUCH_END:
- break;
- default:
- return FALSE;
- }
-
- gdk_event_get_root_coords (event, &event_x, &event_y);
- x = event_x - _gdk_offset_x;
- y = event_y - _gdk_offset_y;
-
- SendMessage (GDK_SURFACE_HWND (window),
- WM_SYSMENU,
- 0,
- MAKELPARAM (x * impl->window_scale, y * impl->window_scale));
-
- return TRUE;
-}
-
-/**
- * _gdk_win32_acquire_dc
- * @impl: a Win32 #GdkSurfaceImplWin32 implementation
- *
- * Gets a DC with the given drawable selected into it.
- *
- * Returns: The DC, on success. Otherwise
- * %NULL. If this function succeeded
- * _gdk_win32_impl_release_dc() must be called
- * release the DC when you are done using it.
- **/
-static HDC
-_gdk_win32_impl_acquire_dc (GdkSurfaceImplWin32 *impl)
-{
- if (GDK_IS_SURFACE_IMPL_WIN32 (impl) &&
- GDK_SURFACE_DESTROYED (impl->wrapper))
- return NULL;
-
- /* We don't call this function for layered windows, but
- * in case we do...
- */
- if (impl->layered)
- return NULL;
-
- if (!impl->hdc)
- {
- impl->hdc = GetDC (impl->handle);
- if (!impl->hdc)
- WIN32_GDI_FAILED ("GetDC");
- }
-
- if (impl->hdc)
- {
- impl->hdc_count++;
- return impl->hdc;
- }
- else
- {
- return NULL;
- }
-}
-
-/**
- * _gdk_win32_impl_release_dc
- * @impl: a Win32 #GdkSurfaceImplWin32 implementation
- *
- * Releases the reference count for the DC
- * from _gdk_win32_impl_acquire_dc()
- **/
-static void
-_gdk_win32_impl_release_dc (GdkSurfaceImplWin32 *impl)
-{
- if (impl->layered)
- return;
-
- g_return_if_fail (impl->hdc_count > 0);
-
- impl->hdc_count--;
- if (impl->hdc_count == 0)
- {
- if (impl->saved_dc_bitmap)
- {
- GDI_CALL (SelectObject, (impl->hdc, impl->saved_dc_bitmap));
- impl->saved_dc_bitmap = NULL;
- }
-
- if (impl->hdc)
- {
- GDI_CALL (ReleaseDC, (impl->handle, impl->hdc));
- impl->hdc = NULL;
- }
- }
-}
-
-HWND
-gdk_win32_surface_get_impl_hwnd (GdkSurface *window)
-{
- if (GDK_SURFACE_IS_WIN32 (window))
- return GDK_SURFACE_HWND (window);
- return NULL;
-}
-
-static void
-gdk_win32_cairo_surface_destroy (void *data)
-{
- GdkSurfaceImplWin32 *impl = data;
-
- _gdk_win32_impl_release_dc (impl);
- impl->cairo_surface = NULL;
-}
-
-static cairo_surface_t *
-gdk_win32_ref_cairo_surface_layered (GdkSurface *window,
- GdkSurfaceImplWin32 *impl)
-{
- gint width, height;
- RECT window_rect;
-
- gdk_win32_get_window_client_area_rect (window, impl->window_scale, &window_rect);
-
- /* Turn client area into window area */
- _gdk_win32_adjust_client_rect (window, &window_rect);
-
- width = window_rect.right - window_rect.left;
- height = window_rect.bottom - window_rect.top;
-
- if (width > impl->dib_width ||
- height > impl->dib_height)
- {
- cairo_surface_t *new_cache;
- cairo_t *cr;
-
- /* Create larger cache surface, copy old cache surface over it */
- new_cache = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
- width,
- height);
-
- if (impl->cache_surface)
- {
- cr = cairo_create (new_cache);
- cairo_set_source_surface (cr, impl->cache_surface, 0, 0);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint (cr);
- cairo_destroy (cr);
- cairo_surface_flush (new_cache);
-
- cairo_surface_destroy (impl->cache_surface);
- }
-
- impl->cache_surface = new_cache;
-
- cairo_surface_set_device_scale (impl->cache_surface,
- impl->window_scale,
- impl->window_scale);
-
- if (impl->cairo_surface)
- cairo_surface_destroy (impl->cairo_surface);
-
- impl->cairo_surface = NULL;
- }
-
- /* This is separate, because cairo_surface gets killed
- * off frequently by outside code, whereas cache_surface
- * is only killed by us, above.
- */
- if (!impl->cairo_surface)
- {
- impl->cairo_surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
- width,
- height);
- impl->dib_width = width;
- impl->dib_height = height;
-
- cairo_surface_set_device_scale (impl->cairo_surface,
- impl->window_scale,
- impl->window_scale);
-
- cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
- impl, gdk_win32_cairo_surface_destroy);
- }
- else
- {
- cairo_surface_reference (impl->cairo_surface);
- }
-
- return impl->cairo_surface;
-}
-
-static cairo_surface_t *
-gdk_win32_ref_cairo_surface (GdkSurface *window)
-{
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- if (GDK_IS_SURFACE_IMPL_WIN32 (impl) &&
- GDK_SURFACE_DESTROYED (impl->wrapper))
- return NULL;
-
- if (impl->layered)
- return gdk_win32_ref_cairo_surface_layered (window, impl);
-
- if (!impl->cairo_surface)
- {
- HDC hdc = _gdk_win32_impl_acquire_dc (impl);
- if (!hdc)
- return NULL;
-
- impl->cairo_surface = cairo_win32_surface_create_with_format (hdc, CAIRO_FORMAT_ARGB32);
- cairo_surface_set_device_scale (impl->cairo_surface,
- impl->window_scale,
- impl->window_scale);
-
- cairo_surface_set_user_data (impl->cairo_surface, &gdk_win32_cairo_key,
- impl, gdk_win32_cairo_surface_destroy);
- }
- else
- cairo_surface_reference (impl->cairo_surface);
-
- return impl->cairo_surface;
-}
-
-BOOL WINAPI
-GtkShowWindow (GdkSurface *window,
- int cmd_show)
-{
- cairo_t *cr;
- cairo_surface_t *surface;
- RECT window_rect;
- HDC hdc;
- POINT window_position;
- SIZE window_size;
- POINT source_point;
- BLENDFUNCTION blender;
-
- HWND hwnd = GDK_SURFACE_HWND (window);
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- switch (cmd_show)
- {
- case SW_FORCEMINIMIZE:
- case SW_HIDE:
- case SW_MINIMIZE:
- break;
- case SW_MAXIMIZE:
- case SW_RESTORE:
- case SW_SHOW:
- case SW_SHOWDEFAULT:
- case SW_SHOWMINIMIZED:
- case SW_SHOWMINNOACTIVE:
- case SW_SHOWNA:
- case SW_SHOWNOACTIVATE:
- case SW_SHOWNORMAL:
- if (IsWindowVisible (hwnd))
- break;
-
- if ((WS_EX_LAYERED & GetWindowLongPtr (hwnd, GWL_EXSTYLE)) != WS_EX_LAYERED)
- break;
-
- /* Window was hidden, will be shown. Erase it, GDK will repaint soon,
- * but not soon enough, so it's possible to see old content before
- * the next redraw, unless we erase the window first.
- */
- GetWindowRect (hwnd, &window_rect);
- source_point.x = source_point.y = 0;
-
- window_position.x = window_rect.left;
- window_position.y = window_rect.top;
- window_size.cx = window_rect.right - window_rect.left;
- window_size.cy = window_rect.bottom - window_rect.top;
-
- blender.BlendOp = AC_SRC_OVER;
- blender.BlendFlags = 0;
- blender.AlphaFormat = AC_SRC_ALPHA;
- blender.SourceConstantAlpha = 255;
-
- /* Create a surface of appropriate size and clear it */
- surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32,
- window_size.cx,
- window_size.cy);
- cairo_surface_set_device_scale (surface, impl->window_scale, impl->window_scale);
- cr = cairo_create (surface);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
- cairo_paint (cr);
- cairo_destroy (cr);
- cairo_surface_flush (surface);
- hdc = cairo_win32_surface_get_dc (surface);
-
- /* No API_CALL() wrapper, don't check for errors */
- UpdateLayeredWindow (hwnd, NULL,
- &window_position, &window_size,
- hdc, &source_point,
- 0, &blender, ULW_ALPHA);
-
- cairo_surface_destroy (surface);
-
- break;
- }
-
- /* Ensure that maximized window size is corrected later on */
- if (cmd_show == SW_MAXIMIZE)
- impl->maximizing = TRUE;
-
- return ShowWindow (hwnd, cmd_show);
-}
-
-static void
-gdk_win32_surface_set_shadow_width (GdkSurface *window,
- gint left,
- gint right,
- gint top,
- gint bottom)
-{
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- GDK_NOTE (MISC, g_print ("gdk_win32_surface_set_shadow_width: window %p, "
- "left %d, top %d, right %d, bottom %d\n",
- window, left, top, right, bottom));
-
- impl->zero_margins = left == 0 && right == 0 && top == 0 && bottom == 0;
-
- if (impl->zero_margins)
- return;
-
- impl->margins.left = left;
- impl->margins.right = right * impl->window_scale;
- impl->margins.top = top;
- impl->margins.bottom = bottom * impl->window_scale;
- impl->margins_x = left + right;
- impl->margins_y = top + bottom;
-}
-
-
-gint
-_gdk_win32_surface_get_scale_factor (GdkSurface *window)
-{
- GdkDisplay *display;
- GdkSurfaceImplWin32 *impl;
-
- GdkWin32Display *win32_display;
- UINT dpix, dpiy;
- gboolean is_scale_acquired;
-
- if (GDK_SURFACE_DESTROYED (window))
- return 1;
-
- g_return_val_if_fail (window != NULL, 1);
-
- display = gdk_surface_get_display (window);
- impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- win32_display = GDK_WIN32_DISPLAY (display);
-
- if (win32_display->dpi_aware_type != PROCESS_DPI_UNAWARE)
- {
- if (win32_display->has_fixed_scale)
- impl->window_scale = win32_display->window_scale;
- else
- impl->window_scale = _gdk_win32_display_get_monitor_scale_factor (win32_display,
- NULL,
- GDK_SURFACE_HWND (window),
- NULL);
-
- return impl->window_scale;
- }
- else
- {
- if (win32_display->has_fixed_scale)
- {
- static gsize hidpi_msg_displayed = 0;
-
- if (g_once_init_enter (&hidpi_msg_displayed))
- {
- g_message ("Note: GDK_SCALE is ignored as HiDPI awareness is disabled.");
- g_once_init_leave (&hidpi_msg_displayed, 1);
- }
- }
-
- /* Application is not DPI aware, don't bother */
- return 1;
- }
-}
-
-void
-_gdk_win32_surface_get_unscaled_size (GdkSurface *window,
- gint *unscaled_width,
- gint *unscaled_height)
-{
- GdkSurfaceImplWin32 *impl = GDK_SURFACE_IMPL_WIN32 (window->impl);
-
- if (unscaled_width)
- *unscaled_width = impl->unscaled_width;
- if (unscaled_height)
- *unscaled_height = impl->unscaled_height;
-}
-
-static void
-gdk_win32_input_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
- /* Partial input shape support is implemented by handling the
- * NC_NCHITTEST message
- */
-}
-
-static void
-gdk_surface_impl_win32_class_init (GdkSurfaceImplWin32Class *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_CLASS (klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- object_class->finalize = gdk_surface_impl_win32_finalize;
-
- impl_class->ref_cairo_surface = gdk_win32_ref_cairo_surface;
-
- impl_class->show = gdk_win32_surface_show;
- impl_class->hide = gdk_win32_surface_hide;
- impl_class->withdraw = gdk_win32_surface_withdraw;
- impl_class->set_events = gdk_win32_surface_set_events;
- impl_class->get_events = gdk_win32_surface_get_events;
- impl_class->raise = gdk_win32_surface_raise;
- impl_class->lower = gdk_win32_surface_lower;
- impl_class->restack_toplevel = gdk_win32_surface_restack_toplevel;
- impl_class->move_resize = gdk_win32_surface_move_resize;
- impl_class->get_geometry = gdk_win32_surface_get_geometry;
- impl_class->get_device_state = gdk_surface_win32_get_device_state;
- impl_class->get_root_coords = gdk_win32_surface_get_root_coords;
-
- impl_class->shape_combine_region = gdk_win32_surface_shape_combine_region;
- impl_class->input_shape_combine_region = gdk_win32_input_shape_combine_region;
- impl_class->destroy = gdk_win32_surface_destroy;
- impl_class->begin_paint = gdk_win32_surface_begin_paint;
- impl_class->end_paint = gdk_win32_surface_end_paint;
-
- //impl_class->beep = gdk_x11_surface_beep;
-
-
- impl_class->show_window_menu = gdk_win32_surface_show_window_menu;
- impl_class->focus = gdk_win32_surface_focus;
- impl_class->set_type_hint = gdk_win32_surface_set_type_hint;
- impl_class->get_type_hint = gdk_win32_surface_get_type_hint;
- impl_class->set_modal_hint = gdk_win32_surface_set_modal_hint;
- impl_class->set_skip_taskbar_hint = gdk_win32_surface_set_skip_taskbar_hint;
- impl_class->set_skip_pager_hint = gdk_win32_surface_set_skip_pager_hint;
- impl_class->set_urgency_hint = gdk_win32_surface_set_urgency_hint;
- impl_class->set_geometry_hints = gdk_win32_surface_set_geometry_hints;
- impl_class->set_title = gdk_win32_surface_set_title;
- impl_class->set_role = gdk_win32_surface_set_role;
- //impl_class->set_startup_id = gdk_x11_surface_set_startup_id;
- impl_class->set_transient_for = gdk_win32_surface_set_transient_for;
- impl_class->get_frame_extents = gdk_win32_surface_get_frame_extents;
- impl_class->set_accept_focus = gdk_win32_surface_set_accept_focus;
- impl_class->set_focus_on_map = gdk_win32_surface_set_focus_on_map;
- impl_class->set_icon_list = gdk_win32_surface_set_icon_list;
- impl_class->set_icon_name = gdk_win32_surface_set_icon_name;
- impl_class->iconify = gdk_win32_surface_iconify;
- impl_class->deiconify = gdk_win32_surface_deiconify;
- impl_class->stick = gdk_win32_surface_stick;
- impl_class->unstick = gdk_win32_surface_unstick;
- impl_class->maximize = gdk_win32_surface_maximize;
- impl_class->unmaximize = gdk_win32_surface_unmaximize;
- impl_class->fullscreen = gdk_win32_surface_fullscreen;
- impl_class->unfullscreen = gdk_win32_surface_unfullscreen;
- impl_class->set_keep_above = gdk_win32_surface_set_keep_above;
- impl_class->set_keep_below = gdk_win32_surface_set_keep_below;
- impl_class->get_group = gdk_win32_surface_get_group;
- impl_class->set_group = gdk_win32_surface_set_group;
- impl_class->set_decorations = gdk_win32_surface_set_decorations;
- impl_class->get_decorations = gdk_win32_surface_get_decorations;
- impl_class->set_functions = gdk_win32_surface_set_functions;
-
- impl_class->set_shadow_width = gdk_win32_surface_set_shadow_width;
- impl_class->begin_resize_drag = gdk_win32_surface_begin_resize_drag;
- impl_class->begin_move_drag = gdk_win32_surface_begin_move_drag;
- impl_class->set_opacity = gdk_win32_surface_set_opacity;
- impl_class->destroy_notify = gdk_win32_surface_destroy_notify;
- impl_class->register_dnd = _gdk_win32_surface_register_dnd;
- impl_class->drag_begin = _gdk_win32_surface_drag_begin;
- impl_class->create_gl_context = _gdk_win32_surface_create_gl_context;
- impl_class->get_scale_factor = _gdk_win32_surface_get_scale_factor;
- impl_class->get_unscaled_size = _gdk_win32_surface_get_unscaled_size;
-}
-
-HGDIOBJ
-gdk_win32_surface_get_handle (GdkSurface *window)
-{
- if (!GDK_SURFACE_IS_WIN32 (window))
- {
- g_warning (G_STRLOC " window is not a native Win32 window");
- return NULL;
- }
-
- return GDK_SURFACE_HWND (window);
-}
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#ifndef __GDK_SURFACE_WIN32_H__
-#define __GDK_SURFACE_WIN32_H__
-
-#include "gdk/win32/gdkprivate-win32.h"
-#include "gdk/gdkwindowimpl.h"
-#include "gdk/gdkcursor.h"
-
-#include <windows.h>
-
-G_BEGIN_DECLS
-
-/* Window implementation for Win32
- */
-
-typedef struct _GdkSurfaceImplWin32 GdkSurfaceImplWin32;
-typedef struct _GdkSurfaceImplWin32Class GdkSurfaceImplWin32Class;
-
-#define GDK_TYPE_SURFACE_IMPL_WIN32 (_gdk_surface_impl_win32_get_type ())
-#define GDK_SURFACE_IMPL_WIN32(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL_WIN32, GdkSurfaceImplWin32))
-#define GDK_SURFACE_IMPL_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL_WIN32, GdkSurfaceImplWin32Class))
-#define GDK_IS_SURFACE_IMPL_WIN32(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL_WIN32))
-#define GDK_IS_SURFACE_IMPL_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL_WIN32))
-#define GDK_SURFACE_IMPL_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL_WIN32, GdkSurfaceImplWin32Class))
-
-enum _GdkWin32AeroSnapCombo
-{
- GDK_WIN32_AEROSNAP_COMBO_NOTHING = 0,
- GDK_WIN32_AEROSNAP_COMBO_UP,
- GDK_WIN32_AEROSNAP_COMBO_DOWN,
- GDK_WIN32_AEROSNAP_COMBO_LEFT,
- GDK_WIN32_AEROSNAP_COMBO_RIGHT,
- /* Same order as non-shift variants. We use it to do things like:
- * AEROSNAP_UP + 4 = AEROSNAP_SHIFTUP
- */
- GDK_WIN32_AEROSNAP_COMBO_SHIFTUP,
- GDK_WIN32_AEROSNAP_COMBO_SHIFTDOWN,
- GDK_WIN32_AEROSNAP_COMBO_SHIFTLEFT,
- GDK_WIN32_AEROSNAP_COMBO_SHIFTRIGHT
-};
-
-typedef enum _GdkWin32AeroSnapCombo GdkWin32AeroSnapCombo;
-
-enum _GdkWin32AeroSnapState
-{
- GDK_WIN32_AEROSNAP_STATE_UNDETERMINED = 0,
- GDK_WIN32_AEROSNAP_STATE_HALFLEFT,
- GDK_WIN32_AEROSNAP_STATE_HALFRIGHT,
- GDK_WIN32_AEROSNAP_STATE_FULLUP,
- /* Maximize state is only used by edge-snap */
- GDK_WIN32_AEROSNAP_STATE_MAXIMIZE
-};
-
-typedef enum _GdkWin32AeroSnapState GdkWin32AeroSnapState;
-
-struct _GdkRectangleDouble
-{
- gdouble x;
- gdouble y;
- gdouble width;
- gdouble height;
-};
-
-typedef struct _GdkRectangleDouble GdkRectangleDouble;
-
-enum _GdkW32WindowDragOp
-{
- GDK_WIN32_DRAGOP_NONE = 0,
- GDK_WIN32_DRAGOP_RESIZE,
- GDK_WIN32_DRAGOP_MOVE,
- GDK_WIN32_DRAGOP_COUNT
-};
-
-typedef enum _GdkW32WindowDragOp GdkW32WindowDragOp;
-
-typedef enum _GdkWin32MonitorDpiType
-{
- MDT_EFFECTIVE_DPI = 0,
- MDT_ANGULAR_DPI = 1,
- MDT_RAW_DPI = 2,
- MDT_DEFAULT = MDT_EFFECTIVE_DPI
-} GdkWin32MonitorDpiType;
-
-struct _GdkW32DragMoveResizeContext
-{
- /* The window that is being moved/resized */
- GdkSurface *window;
-
- /* The kind of drag-operation going on. */
- GdkW32WindowDragOp op;
-
- /* The edge that was grabbed for resizing. Not used for moving. */
- GdkSurfaceEdge edge;
-
- /* The device used to initiate the op.
- * We grab it at the beginning and ungrab it at the end.
- */
- GdkDevice *device;
-
- /* The button pressed down to initiate the op.
- * The op will be canceled only when *this* button
- * is released.
- */
- gint button;
-
- /* Initial cursor position when the operation began.
- * Current cursor position is subtracted from it to find how far
- * to move window border(s).
- */
- gint start_root_x;
- gint start_root_y;
-
- /* Initial window rectangle (position and size).
- * The window is resized/moved relative to this (see start_root_*).
- */
- RECT start_rect;
-
- /* Not used */
- guint32 timestamp;
-
- /* TRUE if during the next redraw we should call SetWindowPos() to push
- * the window size and poistion to the native window.
- */
- gboolean native_move_resize_pending;
-
- /* The cursor we should use while the operation is running. */
- GdkCursor *cursor;
-
- /* This window looks like an outline and is drawn under the window
- * that is being dragged. It indicates the shape the dragged window
- * will take if released at a particular point.
- * Indicator window size always matches the target indicator shape,
- * the the actual indicator drawn on it might not, depending on
- * how much time elapsed since the animation started.
- */
- HWND shape_indicator;
-
- /* Used to draw the indicator */
- cairo_surface_t *indicator_surface;
- gint indicator_surface_width;
- gint indicator_surface_height;
-
- /* Size/position of shape_indicator */
- GdkRectangle indicator_window_rect;
-
- /* Indicator will animate to occupy this rectangle */
- GdkRectangle indicator_target;
-
- /* Indicator will start animating from this rectangle */
- GdkRectangle indicator_start;
-
- /* Timestamp of the animation start */
- gint64 indicator_start_time;
-
- /* Timer that drives the animation */
- guint timer;
-
- /* A special timestamp, if we want to draw not how
- * the animation should look *now*, but how it should
- * look at arbitrary moment of time.
- * Set to 0 to tell GDK to use current time.
- */
- gint64 draw_timestamp;
-
- /* Indicates that a transformation was revealed:
- *
- * For drag-resize: If it's FALSE,
- * then the pointer have not yet hit a trigger that triggers fullup.
- * If TRUE, then the pointer did hit a trigger that triggers fullup
- * at some point during this drag op.
- * This is used to prevent drag-resize from triggering
- * a transformation when first approaching a trigger of the work area -
- * one must drag it all the way to the very trigger to trigger; afterwards
- * a transformation will start triggering at some distance from the trigger
- * for as long as the op is still running. This is how AeroSnap works.
- *
- * For drag-move: If it's FALSE,
- * then the pointer have not yet hit a trigger, even if it is
- * already within a edge region.
- * If it's TRUE, then the pointer did hit a trigger within an
- * edge region, and have not yet left an edge region
- * (passing from one edge region into another doesn't count).
- */
- gboolean revealed;
-
- /* Arrays of GdkRectangle pairs, describing the areas of the virtual
- * desktop that trigger various AeroSnap window transofrmations
- * Coordinates are GDK screen coordinates.
- */
- GArray *halfleft_regions;
- GArray *halfright_regions;
- GArray *maximize_regions;
- GArray *fullup_regions;
-
- /* Current pointer position will result in this kind of snapping,
- * if the drag op is finished.
- */
- GdkWin32AeroSnapState current_snap;
-};
-
-typedef struct _GdkW32DragMoveResizeContext GdkW32DragMoveResizeContext;
-
-struct _GdkSurfaceImplWin32
-{
- GdkSurfaceImpl parent_instance;
-
- GdkSurface *wrapper;
- HANDLE handle;
-
- gint8 toplevel_window_type;
-
- HICON hicon_big;
- HICON hicon_small;
-
- /* When VK_PACKET sends us a leading surrogate, it's stashed here.
- * Later, when another VK_PACKET sends a tailing surrogate, we make up
- * a full unicode character from them, or discard the leading surrogate,
- * if the next key is not a tailing surrogate.
- */
- wchar_t leading_surrogate_keydown;
- wchar_t leading_surrogate_keyup;
-
- /* Window size hints */
- gint hint_flags;
- GdkGeometry hints;
-
- GdkEventMask native_event_mask;
-
- GdkSurfaceTypeHint type_hint;
-
- GdkSurface *transient_owner;
- GSList *transient_children;
- gint num_transients;
- gboolean changing_state;
-
- gint initial_x;
- gint initial_y;
-
- /* left/right/top/bottom width of the shadow/resize-grip around the window */
- RECT margins;
-
- /* left+right and top+bottom from @margins */
- gint margins_x;
- gint margins_y;
-
- /* Set to TRUE when GTK tells us that margins are 0 everywhere.
- * We don't actually set margins to 0, we just set this bit.
- */
- guint zero_margins : 1;
- guint no_bg : 1;
- guint inhibit_configure : 1;
-
- /* Set to TRUE if window is using true layered mode adjustments
- * via UpdateLayeredWindow().
- * Layered windows that get SetLayeredWindowAttributes() called
- * on them are not true layered windows.
- */
- guint layered : 1;
-
- /* If TRUE, the @temp_styles is set to the styles that were temporarily
- * added to this window.
- */
- guint have_temp_styles : 1;
-
- /* If TRUE, the window is in the process of being maximized.
- * This is set by WM_SYSCOMMAND and by gdk_win32_surface_maximize (),
- * and is unset when WM_WINDOWPOSCHANGING is handled.
- */
- guint maximizing : 1;
-
- /* GDK does not keep window contents around, it just draws new
- * stuff over the window where changes occurred.
- * cache_surface retains old window contents, because
- * UpdateLayeredWindow() doesn't do partial redraws.
- */
- cairo_surface_t *cache_surface;
- cairo_surface_t *cairo_surface;
-
- /* Unlike window-backed surfaces, DIB-backed surface
- * does not provide a way to query its size,
- * so we have to remember it ourselves.
- */
- gint dib_width;
- gint dib_height;
-
- /* If the client wants uniformly-transparent window,
- * we remember the opacity value here and apply it
- * during UpdateLayredWindow() call, for layered windows.
- */
- gdouble layered_opacity;
-
- HDC hdc;
- int hdc_count;
- HBITMAP saved_dc_bitmap; /* Original bitmap for dc */
-
- GdkW32DragMoveResizeContext drag_move_resize_context;
-
- /* Remembers where the window was snapped.
- * Some snap operations change their meaning if
- * the window is already snapped.
- */
- GdkWin32AeroSnapState snap_state;
-
- /* Remembers window position before it was snapped.
- * This is used to unsnap it.
- * Position and size are percentages of the workarea
- * of the monitor on which the window was before it was snapped.
- */
- GdkRectangleDouble *snap_stash;
-
- /* Also remember the same position, but in absolute form. */
- GdkRectangle *snap_stash_int;
-
- /* Decorations set by gdk_surface_set_decorations() or NULL if unset */
- GdkWMDecoration* decorations;
-
- /* No. of windows to force layered windows off */
- guint suppress_layered;
-
- /* Temporary styles that this window got for the purpose of
- * handling WM_SYSMENU.
- * They are removed at the first opportunity (usually WM_INITMENU).
- */
- LONG_PTR temp_styles;
-
- /* scale of window on HiDPI */
- gint window_scale;
- gint unscaled_width;
- gint unscaled_height;
-};
-
-struct _GdkSurfaceImplWin32Class
-{
- GdkSurfaceImplClass parent_class;
-};
-
-GType _gdk_surface_impl_win32_get_type (void);
-
-void _gdk_win32_surface_tmp_unset_bg (GdkSurface *window,
- gboolean recurse);
-void _gdk_win32_surface_tmp_reset_bg (GdkSurface *window,
- gboolean recurse);
-
-void _gdk_win32_surface_tmp_unset_parent_bg (GdkSurface *window);
-void _gdk_win32_surface_tmp_reset_parent_bg (GdkSurface *window);
-
-void _gdk_win32_surface_update_style_bits (GdkSurface *window);
-
-gint _gdk_win32_surface_get_scale_factor (GdkSurface *window);
-
-G_END_DECLS
-
-#endif /* __GDK_SURFACE_WIN32_H__ */
'gdkwin32cursor.h',
'gdkwin32display.h',
'gdkwin32id.c',
- 'gdkwindow-win32.c',
+ 'gdksurface-win32.c',
])
gdk_win32_public_headers = files([
'gdkwin32misc.h',
'gdkwin32monitor.h',
'gdkwin32screen.h',
- 'gdkwin32window.h',
+ 'gdkwin32surface.h',
])
install_headers(gdk_win32_public_headers, subdir: 'gtk-4.0/gdk/win32/')
#include "gdkdeviceprivate.h"
#include "gdkinternals.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkprivate-x11.h"
#include "gdkdisplay-x11.h"
#include "gdkasync.h"
#include "gdkdisplayprivate.h"
#include "gdkkeys.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkinternals.h"
#include "gdkx11devicemanager.h"
#include "gdkx11display.h"
#include "gdkeventsource.h"
#include "gdkinternals.h"
-#include "gdkwindow-x11.h"
+#include "gdksurface-x11.h"
#include "gdkprivate-x11.h"
#include "gdkdisplay-x11.h"
#include "xsettings-client.h"
#include "config.h"
#include "gdkeventtranslator.h"
-#include "gdkwindow-x11.h"
+#include "gdksurface-x11.h"
typedef GdkEventTranslatorIface GdkEventTranslatorInterface;
G_DEFINE_INTERFACE (GdkEventTranslator, _gdk_x11_event_translator, G_TYPE_OBJECT);
#include "gdkprivate-x11.h"
#include "gdkscreen-x11.h"
#include "gdkdisplay-x11.h"
-#include "gdkwindow-x11.h"
+#include "gdksurface-x11.h"
typedef struct _GdkSurfaceQueueItem GdkSurfaceQueueItem;
#include "gdkx11display.h"
#include "gdkx11glcontext.h"
#include "gdkx11screen.h"
-#include "gdkx11window.h"
+#include "gdkx11surface.h"
#include "gdkvisual-x11.h"
#include "gdkx11property.h"
#include <X11/Xatom.h>
#include "gdkglcontextprivate.h"
#include "gdkdisplayprivate.h"
#include "gdkvisual-x11.h"
-#include "gdkwindow.h"
+#include "gdksurface.h"
#include "gdkinternals.h"
G_BEGIN_DECLS
#include "gdkcursor.h"
#include "gdkinternals.h"
#include "gdkx.h"
-#include "gdkwindow-x11.h"
+#include "gdksurface-x11.h"
#include "gdkscreen-x11.h"
#include <X11/Xlib.h>
#include "gdkintl.h"
#include "gdkx11display.h"
#include "gdkx11property.h"
-#include "gdkx11window.h"
+#include "gdkx11surface.h"
typedef struct GdkX11SelectionInputStreamPrivate GdkX11SelectionInputStreamPrivate;
#include "gdktextlistconverter-x11.h"
#include "gdkx11display.h"
#include "gdkx11property.h"
-#include "gdkx11window.h"
+#include "gdkx11surface.h"
typedef struct _GdkX11PendingSelectionNotify GdkX11PendingSelectionNotify;
typedef struct _GdkX11SelectionOutputStreamPrivate GdkX11SelectionOutputStreamPrivate;
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
+ * Josh MacDonald, Ryan Lortie
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "config.h"
+
+#include "gdksurface-x11.h"
+
+#include "gdksurface.h"
+#include "gdksurfaceimpl.h"
+#include "gdkvisual-x11.h"
+#include "gdkinternals.h"
+#include "gdkdeviceprivate.h"
+#include "gdkframeclockprivate.h"
+#include "gdkasync.h"
+#include "gdkeventsource.h"
+#include "gdkdisplay-x11.h"
+#include "gdkglcontext-x11.h"
+#include "gdkprivate-x11.h"
+#include "gdktextureprivate.h"
+#include "gdk-private.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#include <cairo-xlib.h>
+
+#include "MwmUtil.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+
+#include <X11/extensions/shape.h>
+
+#ifdef HAVE_XKB
+#include <X11/XKBlib.h>
+#endif
+
+#ifdef HAVE_XCOMPOSITE
+#include <X11/extensions/Xcomposite.h>
+#endif
+
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+
+#ifdef HAVE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif
+
+const int _gdk_x11_event_mask_table[21] =
+{
+ ExposureMask,
+ PointerMotionMask,
+ PointerMotionHintMask,
+ ButtonMotionMask,
+ Button1MotionMask,
+ Button2MotionMask,
+ Button3MotionMask,
+ ButtonPressMask,
+ ButtonReleaseMask,
+ KeyPressMask,
+ KeyReleaseMask,
+ EnterWindowMask,
+ LeaveWindowMask,
+ FocusChangeMask,
+ StructureNotifyMask,
+ PropertyChangeMask,
+ VisibilityChangeMask,
+ 0, /* PROXIMITY_IN */
+ 0, /* PROXIMTY_OUT */
+ SubstructureNotifyMask,
+ ButtonPressMask /* SCROLL; on X mouse wheel events is treated as mouse button 4/5 */
+};
+
+const gint _gdk_x11_event_mask_table_size = G_N_ELEMENTS (_gdk_x11_event_mask_table);
+
+/* Forward declarations */
+static void gdk_x11_surface_apply_fullscreen_mode (GdkSurface *window);
+static gboolean gdk_surface_icon_name_set (GdkSurface *window);
+static void set_wm_name (GdkDisplay *display,
+ Window xwindow,
+ const gchar *name);
+static void move_to_current_desktop (GdkSurface *window);
+
+static void gdk_surface_impl_x11_finalize (GObject *object);
+
+#define WINDOW_IS_TOPLEVEL_OR_FOREIGN(window) \
+ (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL || \
+ GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP || \
+ GDK_SURFACE_TYPE (window) == GDK_SURFACE_FOREIGN)
+
+#define WINDOW_IS_TOPLEVEL(window) \
+ (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL || \
+ GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP)
+
+/* Return whether time1 is considered later than time2 as far as xserver
+ * time is concerned. Accounts for wraparound.
+ */
+#define XSERVER_TIME_IS_LATER(time1, time2) \
+ ( (( time1 > time2 ) && ( time1 - time2 < ((guint32)-1)/2 )) || \
+ (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 )) \
+ )
+
+struct _GdkX11Surface {
+ GdkSurface parent;
+};
+
+struct _GdkX11SurfaceClass {
+ GdkSurfaceClass parent_class;
+};
+
+G_DEFINE_TYPE (GdkX11Surface, gdk_x11_surface, GDK_TYPE_SURFACE)
+
+static void
+gdk_x11_surface_class_init (GdkX11SurfaceClass *x11_surface_class)
+{
+}
+
+static void
+gdk_x11_surface_init (GdkX11Surface *x11_surface)
+{
+}
+
+
+G_DEFINE_TYPE (GdkSurfaceImplX11, gdk_surface_impl_x11, GDK_TYPE_SURFACE_IMPL)
+
+static void
+gdk_surface_impl_x11_init (GdkSurfaceImplX11 *impl)
+{
+ impl->window_scale = 1;
+ impl->frame_sync_enabled = TRUE;
+}
+
+GdkToplevelX11 *
+_gdk_x11_surface_get_toplevel (GdkSurface *window)
+{
+ GdkSurfaceImplX11 *impl;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ if (!WINDOW_IS_TOPLEVEL (window))
+ return NULL;
+
+ impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (!impl->toplevel)
+ {
+ impl->toplevel = g_new0 (GdkToplevelX11, 1);
+ impl->toplevel->have_focused = FALSE;
+ }
+
+ return impl->toplevel;
+}
+
+/**
+ * _gdk_x11_surface_update_size:
+ * @impl: a #GdkSurfaceImplX11.
+ *
+ * Updates the state of the window (in particular the drawable's
+ * cairo surface) when its size has changed.
+ **/
+void
+_gdk_x11_surface_update_size (GdkSurfaceImplX11 *impl)
+{
+ if (impl->cairo_surface)
+ {
+ cairo_xlib_surface_set_size (impl->cairo_surface,
+ impl->unscaled_width, impl->unscaled_height);
+ }
+}
+
+static void
+gdk_x11_surface_get_unscaled_size (GdkSurface *window,
+ int *unscaled_width,
+ int *unscaled_height)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (unscaled_width)
+ *unscaled_width = impl->unscaled_width;
+
+ if (unscaled_height)
+ *unscaled_height = impl->unscaled_height;
+}
+
+static gboolean
+gdk_x11_surface_supports_edge_constraints (GdkSurface *window)
+{
+ return gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
+ g_intern_static_string ("_GTK_EDGE_CONSTRAINTS"));
+}
+
+static void
+set_sync_counter(Display *display,
+ XSyncCounter counter,
+ gint64 value)
+{
+ XSyncValue sync_value;
+
+ XSyncIntsToValue (&sync_value,
+ value & G_GINT64_CONSTANT(0xFFFFFFFF),
+ value >> 32);
+ XSyncSetCounter (display, counter, sync_value);
+}
+
+static void
+window_pre_damage (GdkSurface *window)
+{
+ GdkSurface *toplevel_window = gdk_surface_get_toplevel (window);
+ GdkSurfaceImplX11 *impl;
+
+ if (!toplevel_window || !WINDOW_IS_TOPLEVEL (toplevel_window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_X11 (toplevel_window->impl);
+
+ if (impl->toplevel->in_frame &&
+ impl->toplevel->current_counter_value % 2 == 0)
+ {
+ impl->toplevel->current_counter_value += 1;
+ set_sync_counter (GDK_SURFACE_XDISPLAY (impl->wrapper),
+ impl->toplevel->extended_update_counter,
+ impl->toplevel->current_counter_value);
+ }
+}
+
+static void
+on_surface_changed (void *data)
+{
+ GdkSurface *window = data;
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (impl->tracking_damage)
+ window_pre_damage (window);
+}
+
+/* We want to know when cairo drawing causes damage to the window,
+ * so we engage in the _NET_WM_FRAME_DRAWN protocol with the
+ * window only when there actually is drawing. To do that we use
+ * a technique (hack) suggested by Uli Schlachter - if we set
+ * a dummy "mime data" on the cairo surface (this facility is
+ * used to attach JPEG data to an imager), then cairo wil flush
+ * and remove the mime data before making any changes to the window.
+ */
+
+static void
+hook_surface_changed (GdkSurface *window)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (impl->cairo_surface)
+ {
+ cairo_surface_set_mime_data (impl->cairo_surface,
+ "x-gdk/change-notify",
+ (unsigned char *)"X",
+ 1,
+ on_surface_changed,
+ window);
+ impl->tracking_damage = 1;
+ }
+}
+
+static void
+unhook_surface_changed (GdkSurface *window)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (impl->cairo_surface)
+ {
+ impl->tracking_damage = 0;
+ cairo_surface_set_mime_data (impl->cairo_surface,
+ "x-gdk/change-notify",
+ NULL, 0,
+ NULL, NULL);
+ }
+}
+
+static void
+gdk_x11_surface_predict_presentation_time (GdkSurface *window)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+ GdkFrameClock *clock;
+ GdkFrameTimings *timings;
+ gint64 presentation_time;
+ gint64 refresh_interval;
+
+ if (!WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ clock = gdk_surface_get_frame_clock (window);
+
+ timings = gdk_frame_clock_get_current_timings (clock);
+
+ gdk_frame_clock_get_refresh_info (clock,
+ timings->frame_time,
+ &refresh_interval, &presentation_time);
+
+ if (presentation_time != 0)
+ {
+ if (timings->slept_before)
+ {
+ presentation_time += refresh_interval;
+ }
+ else
+ {
+ if (presentation_time < timings->frame_time + refresh_interval / 2)
+ presentation_time += refresh_interval;
+ }
+ }
+ else
+ {
+ if (timings->slept_before)
+ presentation_time = timings->frame_time + refresh_interval + refresh_interval / 2;
+ else
+ presentation_time = timings->frame_time + refresh_interval;
+ }
+
+ if (presentation_time < impl->toplevel->throttled_presentation_time)
+ presentation_time = impl->toplevel->throttled_presentation_time;
+
+ timings->predicted_presentation_time = presentation_time;
+}
+
+static void
+gdk_x11_surface_begin_frame (GdkSurface *window,
+ gboolean force_frame)
+{
+ GdkSurfaceImplX11 *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (!WINDOW_IS_TOPLEVEL (window) ||
+ impl->toplevel->extended_update_counter == None)
+ return;
+
+ impl->toplevel->in_frame = TRUE;
+
+ if (impl->toplevel->configure_counter_value != 0 &&
+ impl->toplevel->configure_counter_value_is_extended)
+ {
+ impl->toplevel->current_counter_value = impl->toplevel->configure_counter_value;
+ if ((impl->toplevel->current_counter_value % 2) == 1)
+ impl->toplevel->current_counter_value += 1;
+
+ impl->toplevel->configure_counter_value = 0;
+
+ window_pre_damage (window);
+ }
+ else if (force_frame)
+ {
+ /* When mapping the window, we really want to freeze the
+ rendering of the window by the compositor until we've
+ actually painted something into the window's buffer. */
+ window_pre_damage (window);
+ }
+ else
+ {
+ hook_surface_changed (window);
+ }
+}
+
+static void
+gdk_x11_surface_end_frame (GdkSurface *window)
+{
+ GdkFrameClock *clock;
+ GdkFrameTimings *timings;
+ GdkSurfaceImplX11 *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (!WINDOW_IS_TOPLEVEL (window) ||
+ impl->toplevel->extended_update_counter == None ||
+ !impl->toplevel->in_frame)
+ return;
+
+ clock = gdk_surface_get_frame_clock (window);
+ timings = gdk_frame_clock_get_current_timings (clock);
+
+ impl->toplevel->in_frame = FALSE;
+
+ if (impl->toplevel->current_counter_value % 2 == 1)
+ {
+ if (GDK_DISPLAY_DEBUG_CHECK (gdk_surface_get_display (window), FRAMES))
+ {
+ XImage *image = XGetImage (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ 0, 0, 1, 1,
+ (1 << 24) - 1,
+ ZPixmap);
+ XDestroyImage (image);
+ }
+
+ /* An increment of 3 means that the frame was not drawn as fast as possible,
+ * but rather at a particular time. This can trigger different handling from
+ * the compositor.
+ */
+ if (timings->slept_before)
+ impl->toplevel->current_counter_value += 3;
+ else
+ impl->toplevel->current_counter_value += 1;
+
+ set_sync_counter(GDK_SURFACE_XDISPLAY (impl->wrapper),
+ impl->toplevel->extended_update_counter,
+ impl->toplevel->current_counter_value);
+
+ if (impl->frame_sync_enabled &&
+ gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
+ g_intern_static_string ("_NET_WM_FRAME_DRAWN")))
+ {
+ impl->toplevel->frame_pending = TRUE;
+ _gdk_frame_clock_freeze (gdk_surface_get_frame_clock (window));
+ timings->cookie = impl->toplevel->current_counter_value;
+ }
+ }
+
+ unhook_surface_changed (window);
+
+ if (impl->toplevel->configure_counter_value != 0 &&
+ !impl->toplevel->configure_counter_value_is_extended)
+ {
+ set_sync_counter (GDK_SURFACE_XDISPLAY (window),
+ impl->toplevel->update_counter,
+ impl->toplevel->configure_counter_value);
+
+ impl->toplevel->configure_counter_value = 0;
+ }
+
+ if (!impl->toplevel->frame_pending)
+ timings->complete = TRUE;
+}
+
+/*****************************************************
+ * X11 specific implementations of generic functions *
+ *****************************************************/
+
+static cairo_surface_t *
+gdk_x11_create_cairo_surface (GdkSurfaceImplX11 *impl,
+ int width,
+ int height)
+{
+ Visual *visual;
+
+ visual = gdk_x11_display_get_window_visual (GDK_X11_DISPLAY (gdk_surface_get_display (impl->wrapper)));
+ return cairo_xlib_surface_create (GDK_SURFACE_XDISPLAY (impl->wrapper),
+ GDK_SURFACE_IMPL_X11 (impl)->xid,
+ visual,
+ width, height);
+}
+
+static cairo_surface_t *
+gdk_x11_ref_cairo_surface (GdkSurface *window)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return NULL;
+
+ if (!impl->cairo_surface)
+ {
+ impl->cairo_surface = gdk_x11_create_cairo_surface (impl,
+ gdk_surface_get_width (window) * impl->window_scale,
+ gdk_surface_get_height (window) * impl->window_scale);
+ cairo_surface_set_device_scale (impl->cairo_surface, impl->window_scale, impl->window_scale);
+
+ if (WINDOW_IS_TOPLEVEL (window) && impl->toplevel->in_frame)
+ hook_surface_changed (window);
+ }
+
+ cairo_surface_reference (impl->cairo_surface);
+
+ return impl->cairo_surface;
+}
+
+static void
+gdk_surface_impl_x11_finalize (GObject *object)
+{
+ GdkSurface *wrapper;
+ GdkSurfaceImplX11 *impl;
+
+ g_return_if_fail (GDK_IS_SURFACE_IMPL_X11 (object));
+
+ impl = GDK_SURFACE_IMPL_X11 (object);
+
+ wrapper = impl->wrapper;
+
+ if (WINDOW_IS_TOPLEVEL (wrapper) && impl->toplevel->in_frame)
+ unhook_surface_changed (wrapper);
+
+ _gdk_x11_surface_grab_check_destroy (wrapper);
+
+ if (!GDK_SURFACE_DESTROYED (wrapper))
+ {
+ GdkDisplay *display = GDK_SURFACE_DISPLAY (wrapper);
+
+ _gdk_x11_display_remove_window (display, impl->xid);
+ if (impl->toplevel && impl->toplevel->focus_window)
+ _gdk_x11_display_remove_window (display, impl->toplevel->focus_window);
+ }
+
+ g_free (impl->toplevel);
+
+ if (impl->cursor)
+ g_object_unref (impl->cursor);
+
+ G_OBJECT_CLASS (gdk_surface_impl_x11_parent_class)->finalize (object);
+}
+
+typedef struct {
+ GdkDisplay *display;
+ Pixmap pixmap;
+} FreePixmapData;
+
+static void
+free_pixmap (gpointer datap)
+{
+ FreePixmapData *data = datap;
+
+ if (!gdk_display_is_closed (data->display))
+ {
+ XFreePixmap (GDK_DISPLAY_XDISPLAY (data->display),
+ data->pixmap);
+ }
+
+ g_object_unref (data->display);
+ g_slice_free (FreePixmapData, data);
+}
+
+static void
+attach_free_pixmap_handler (cairo_surface_t *surface,
+ GdkDisplay *display,
+ Pixmap pixmap)
+{
+ static const cairo_user_data_key_t key;
+ FreePixmapData *data;
+
+ data = g_slice_new (FreePixmapData);
+ data->display = g_object_ref (display);
+ data->pixmap = pixmap;
+
+ cairo_surface_set_user_data (surface, &key, data, free_pixmap);
+}
+
+/* Cairo does not guarantee we get an xlib surface if we call
+ * cairo_surface_create_similar(). In some cases however, we must use a
+ * pixmap or bitmap in the X11 API.
+ * These functions ensure an Xlib surface.
+ */
+cairo_surface_t *
+_gdk_x11_display_create_bitmap_surface (GdkDisplay *display,
+ int width,
+ int height)
+{
+ cairo_surface_t *surface;
+ Pixmap pixmap;
+
+ pixmap = XCreatePixmap (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SCREEN_XROOTWIN (GDK_X11_DISPLAY (display)->screen),
+ width, height, 1);
+ surface = cairo_xlib_surface_create_for_bitmap (GDK_DISPLAY_XDISPLAY (display),
+ pixmap,
+ GDK_X11_SCREEN (GDK_X11_DISPLAY (display)->screen)->xscreen,
+ width, height);
+ attach_free_pixmap_handler (surface, display, pixmap);
+
+ return surface;
+}
+
+/* Create a surface backed with a pixmap without alpha on the same screen as window */
+static cairo_surface_t *
+gdk_x11_surface_create_pixmap_surface (GdkSurface *window,
+ int width,
+ int height)
+{
+ GdkDisplay *display;
+ Display *dpy;
+ cairo_surface_t *surface;
+ Pixmap pixmap;
+
+ display = gdk_surface_get_display (window);
+ dpy = GDK_DISPLAY_XDISPLAY (display);
+
+ pixmap = XCreatePixmap (dpy,
+ GDK_SURFACE_XID (window),
+ width, height,
+ DefaultDepth (dpy, DefaultScreen (dpy)));
+ surface = cairo_xlib_surface_create (dpy,
+ pixmap,
+ DefaultVisual (dpy, DefaultScreen (dpy)),
+ width, height);
+ attach_free_pixmap_handler (surface, display, pixmap);
+
+ return surface;
+}
+
+static void
+set_wm_protocols (GdkSurface *window)
+{
+ GdkDisplay *display = gdk_surface_get_display (window);
+ Atom protocols[4];
+ int n = 0;
+
+ protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW");
+ protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS");
+ protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING");
+
+#ifdef HAVE_XSYNC
+ if (GDK_X11_DISPLAY (display)->use_sync)
+ protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST");
+#endif
+
+ XSetWMProtocols (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window), protocols, n);
+}
+
+static const gchar *
+get_default_title (void)
+{
+ const char *title;
+
+ title = g_get_application_name ();
+ if (!title)
+ title = g_get_prgname ();
+ if (!title)
+ title = "";
+
+ return title;
+}
+
+static void
+check_leader_window_title (GdkDisplay *display)
+{
+ GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+
+ if (display_x11->leader_window && !display_x11->leader_window_title_set)
+ {
+ set_wm_name (display,
+ display_x11->leader_window,
+ get_default_title ());
+
+ display_x11->leader_window_title_set = TRUE;
+ }
+}
+
+static Window
+create_focus_window (GdkDisplay *display,
+ XID parent)
+{
+ GdkX11Display *display_x11;
+ GdkEventMask event_mask;
+ Display *xdisplay;
+ Window focus_window;
+ XSetWindowAttributes attrs;
+
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+ display_x11 = GDK_X11_DISPLAY (display);
+
+ focus_window = XCreateWindow (xdisplay, parent,
+ -1, -1, 1, 1, 0,
+ 0, /* depth */
+ InputOnly,
+ CopyFromParent,
+ 0, &attrs);
+
+ event_mask = (GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK |
+ GDK_FOCUS_CHANGE_MASK);
+
+ gdk_x11_event_source_select_events ((GdkEventSource *) display_x11->event_source,
+ focus_window,
+ event_mask, 0);
+
+ XMapWindow (xdisplay, focus_window);
+
+ return focus_window;
+}
+
+static void
+ensure_sync_counter (GdkSurface *window)
+{
+#ifdef HAVE_XSYNC
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
+ GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (window);
+
+ if (toplevel &&
+ toplevel->update_counter == None &&
+ GDK_X11_DISPLAY (display)->use_sync)
+ {
+ Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+ XSyncValue value;
+ Atom atom;
+ XID counters[2];
+
+ XSyncIntToValue (&value, 0);
+
+ toplevel->update_counter = XSyncCreateCounter (xdisplay, value);
+ toplevel->extended_update_counter = XSyncCreateCounter (xdisplay, value);
+
+ atom = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_SYNC_REQUEST_COUNTER");
+
+ counters[0] = toplevel->update_counter;
+ counters[1] = toplevel->extended_update_counter;
+ XChangeProperty (xdisplay, GDK_SURFACE_XID (window),
+ atom, XA_CARDINAL,
+ 32, PropModeReplace,
+ (guchar *)counters, 2);
+
+ toplevel->current_counter_value = 0;
+ }
+ }
+#endif
+}
+
+static void
+setup_toplevel_window (GdkSurface *window,
+ GdkX11Screen *x11_screen)
+{
+ GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (window);
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+ GdkDisplay *display = gdk_surface_get_display (window);
+ Display *xdisplay = GDK_SURFACE_XDISPLAY (window);
+ XID xid = GDK_SURFACE_XID (window);
+ XSizeHints size_hints;
+ long pid;
+ Window leader_window;
+
+ set_wm_protocols (window);
+
+ if (!window->input_only)
+ {
+ /* The focus window is off the visible area, and serves to receive key
+ * press events so they don't get sent to child windows.
+ */
+ toplevel->focus_window = create_focus_window (display, xid);
+ _gdk_x11_display_add_window (x11_screen->display,
+ &toplevel->focus_window,
+ window);
+ }
+
+ check_leader_window_title (x11_screen->display);
+
+ /* FIXME: Is there any point in doing this? Do any WM's pay
+ * attention to PSize, and even if they do, is this the
+ * correct value???
+ */
+ size_hints.flags = PSize;
+ size_hints.width = window->width * impl->window_scale;
+ size_hints.height = window->height * impl->window_scale;
+
+ XSetWMNormalHints (xdisplay, xid, &size_hints);
+
+ /* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
+ XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
+
+ pid = getpid ();
+ XChangeProperty (xdisplay, xid,
+ gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_WM_PID"),
+ XA_CARDINAL, 32,
+ PropModeReplace,
+ (guchar *)&pid, 1);
+
+ leader_window = GDK_X11_DISPLAY (x11_screen->display)->leader_window;
+ if (!leader_window)
+ leader_window = xid;
+ XChangeProperty (xdisplay, xid,
+ gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "WM_CLIENT_LEADER"),
+ XA_WINDOW, 32, PropModeReplace,
+ (guchar *) &leader_window, 1);
+
+ if (toplevel->focus_window != None)
+ XChangeProperty (xdisplay, xid,
+ gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_WM_USER_TIME_WINDOW"),
+ XA_WINDOW, 32, PropModeReplace,
+ (guchar *) &toplevel->focus_window, 1);
+
+ if (!window->focus_on_map)
+ gdk_x11_surface_set_user_time (window, 0);
+ else if (GDK_X11_DISPLAY (x11_screen->display)->user_time != 0)
+ gdk_x11_surface_set_user_time (window, GDK_X11_DISPLAY (x11_screen->display)->user_time);
+
+ ensure_sync_counter (window);
+
+ /* Start off in a frozen state - we'll finish this when we first paint */
+ gdk_x11_surface_begin_frame (window, TRUE);
+}
+
+static void
+on_frame_clock_before_paint (GdkFrameClock *clock,
+ GdkSurface *window)
+{
+ gdk_x11_surface_predict_presentation_time (window);
+ gdk_x11_surface_begin_frame (window, FALSE);
+}
+
+static void
+on_frame_clock_after_paint (GdkFrameClock *clock,
+ GdkSurface *window)
+{
+ gdk_x11_surface_end_frame (window);
+
+}
+
+static void
+connect_frame_clock (GdkSurface *window)
+{
+ GdkSurfaceImplX11 *impl;
+
+ impl = GDK_SURFACE_IMPL_X11 (window->impl);
+ if (WINDOW_IS_TOPLEVEL (window) && !impl->frame_clock_connected)
+ {
+ GdkFrameClock *frame_clock = gdk_surface_get_frame_clock (window);
+
+ g_signal_connect (frame_clock, "before-paint",
+ G_CALLBACK (on_frame_clock_before_paint), window);
+ g_signal_connect (frame_clock, "after-paint",
+ G_CALLBACK (on_frame_clock_after_paint), window);
+
+ impl->frame_clock_connected = TRUE;
+ }
+}
+
+void
+_gdk_x11_display_create_window_impl (GdkDisplay *display,
+ GdkSurface *window,
+ GdkSurface *real_parent,
+ GdkEventMask event_mask,
+ GdkSurfaceAttr *attributes)
+{
+ GdkSurfaceImplX11 *impl;
+ GdkX11Screen *x11_screen;
+ GdkX11Display *display_x11;
+
+ Window xparent;
+ Visual *xvisual;
+ Display *xdisplay;
+
+ XSetWindowAttributes xattributes;
+ long xattributes_mask;
+ XClassHint *class_hint;
+
+ unsigned int class;
+ int depth;
+
+ int abs_x;
+ int abs_y;
+
+ display_x11 = GDK_X11_DISPLAY (display);
+ x11_screen = GDK_X11_SCREEN (display_x11->screen);
+ if (real_parent)
+ xparent = GDK_SURFACE_XID (real_parent);
+ else
+ xparent = GDK_SCREEN_XROOTWIN (x11_screen);
+
+ impl = g_object_new (GDK_TYPE_SURFACE_IMPL_X11, NULL);
+ window->impl = GDK_SURFACE_IMPL (impl);
+ impl->wrapper = GDK_SURFACE (window);
+ impl->window_scale = x11_screen->window_scale;
+
+ xdisplay = x11_screen->xdisplay;
+
+ xattributes_mask = 0;
+
+ xvisual = gdk_x11_display_get_window_visual (display_x11);
+
+ impl->override_redirect = FALSE;
+
+ /* Sanity checks */
+ switch (window->window_type)
+ {
+ case GDK_SURFACE_TOPLEVEL:
+ case GDK_SURFACE_TEMP:
+ if (window->parent)
+ {
+ /* The common code warns for this case */
+ xparent = GDK_SCREEN_XROOTWIN (x11_screen);
+ }
+ break;
+
+ case GDK_SURFACE_CHILD:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (!window->input_only)
+ {
+ class = InputOutput;
+
+ xattributes.background_pixel = BlackPixel (xdisplay, x11_screen->screen_num);
+
+ xattributes.border_pixel = BlackPixel (xdisplay, x11_screen->screen_num);
+ xattributes_mask |= CWBorderPixel | CWBackPixel;
+
+ xattributes.bit_gravity = NorthWestGravity;
+ xattributes_mask |= CWBitGravity;
+
+ xattributes.colormap = gdk_x11_display_get_window_colormap (display_x11);
+ xattributes_mask |= CWColormap;
+
+ if (window->window_type == GDK_SURFACE_TEMP)
+ {
+ xattributes.save_under = True;
+ xattributes.override_redirect = True;
+ xattributes.cursor = None;
+ xattributes_mask |= CWSaveUnder | CWOverrideRedirect;
+
+ impl->override_redirect = TRUE;
+ }
+
+ depth = gdk_x11_display_get_window_depth (display_x11);
+ }
+ else
+ {
+ class = InputOnly;
+
+ if (window->window_type == GDK_SURFACE_TEMP)
+ {
+ xattributes.override_redirect = True;
+ xattributes_mask |= CWOverrideRedirect;
+
+ impl->override_redirect = TRUE;
+ }
+
+ depth = 0;
+ }
+
+ if (window->width * impl->window_scale > 32767 ||
+ window->height * impl->window_scale > 32767)
+ {
+ g_warning ("Native Windows wider or taller than 32767 pixels are not supported");
+
+ if (window->width * impl->window_scale > 32767)
+ window->width = 32767 / impl->window_scale;
+ if (window->height * impl->window_scale > 32767)
+ window->height = 32767 / impl->window_scale;
+ }
+
+ impl->unscaled_width = window->width * impl->window_scale;
+ impl->unscaled_height = window->height * impl->window_scale;
+
+ if (window->parent)
+ {
+ abs_x = window->parent->abs_x;
+ abs_y = window->parent->abs_y;
+ }
+ else
+ {
+ abs_x = 0;
+ abs_y = 0;
+ }
+
+ impl->xid = XCreateWindow (xdisplay, xparent,
+ (window->x + abs_x) * impl->window_scale,
+ (window->y + abs_y) * impl->window_scale,
+ window->width * impl->window_scale, window->height * impl->window_scale,
+ 0, depth, class, xvisual,
+ xattributes_mask, &xattributes);
+
+ g_object_ref (window);
+ _gdk_x11_display_add_window (x11_screen->display, &impl->xid, window);
+
+ switch (GDK_SURFACE_TYPE (window))
+ {
+ case GDK_SURFACE_TOPLEVEL:
+ case GDK_SURFACE_TEMP:
+ gdk_surface_set_title (window, get_default_title ());
+
+ class_hint = XAllocClassHint ();
+ class_hint->res_name = (char *) g_get_prgname ();
+ class_hint->res_class = (char *) display_x11->program_class;
+ XSetClassHint (xdisplay, impl->xid, class_hint);
+ XFree (class_hint);
+
+ setup_toplevel_window (window, x11_screen);
+ break;
+
+ case GDK_SURFACE_CHILD:
+ default:
+ break;
+ }
+
+ gdk_x11_event_source_select_events ((GdkEventSource *) display_x11->event_source,
+ GDK_SURFACE_XID (window), event_mask,
+ StructureNotifyMask | PropertyChangeMask);
+
+ connect_frame_clock (window);
+
+ gdk_surface_freeze_toplevel_updates (window);
+}
+
+static GdkEventMask
+x_event_mask_to_gdk_event_mask (long mask)
+{
+ GdkEventMask event_mask = 0;
+ int i;
+
+ for (i = 0; i < _gdk_x11_event_mask_table_size; i++)
+ {
+ if (mask & _gdk_x11_event_mask_table[i])
+ event_mask |= 1 << (i + 1);
+ }
+
+ return event_mask;
+}
+
+/**
+ * gdk_x11_surface_foreign_new_for_display:
+ * @display: (type GdkX11Display): the #GdkDisplay where the window handle comes from.
+ * @window: an Xlib Window
+ *
+ * Wraps a native window in a #GdkSurface. The function will try to
+ * look up the window using gdk_x11_surface_lookup_for_display() first.
+ * If it does not find it there, it will create a new window.
+ *
+ * This may fail if the window has been destroyed. If the window
+ * was already known to GDK, a new reference to the existing
+ * #GdkSurface is returned.
+ *
+ * Returns: (transfer full): a #GdkSurface wrapper for the native
+ * window, or %NULL if the window has been destroyed. The wrapper
+ * will be newly created, if one doesn’t exist already.
+ */
+GdkSurface *
+gdk_x11_surface_foreign_new_for_display (GdkDisplay *display,
+ Window window)
+{
+ GdkX11Screen *screen;
+ GdkSurface *win;
+ GdkSurfaceImplX11 *impl;
+ GdkX11Display *display_x11;
+ XWindowAttributes attrs;
+ Window root, parent;
+ Window *children = NULL;
+ guint nchildren;
+ gboolean result;
+
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+
+ display_x11 = GDK_X11_DISPLAY (display);
+
+ if ((win = gdk_x11_surface_lookup_for_display (display, window)) != NULL)
+ return g_object_ref (win);
+
+ gdk_x11_display_error_trap_push (display);
+ result = XGetWindowAttributes (display_x11->xdisplay, window, &attrs);
+ if (gdk_x11_display_error_trap_pop (display) || !result)
+ return NULL;
+
+ /* FIXME: This is pretty expensive.
+ * Maybe the caller should supply the parent
+ */
+ gdk_x11_display_error_trap_push (display);
+ result = XQueryTree (display_x11->xdisplay, window, &root, &parent, &children, &nchildren);
+ if (gdk_x11_display_error_trap_pop (display) || !result)
+ return NULL;
+
+ if (children)
+ XFree (children);
+
+ screen = _gdk_x11_display_screen_for_xrootwin (display, root);
+ if (screen == NULL)
+ return NULL;
+
+ win = _gdk_display_create_window (display);
+ win->impl = g_object_new (GDK_TYPE_SURFACE_IMPL_X11, NULL);
+ win->impl_window = win;
+
+ impl = GDK_SURFACE_IMPL_X11 (win->impl);
+ impl->wrapper = win;
+ impl->window_scale = GDK_X11_SCREEN (screen)->window_scale;
+
+ /* Always treat foreigns as toplevels */
+ win->parent = NULL;
+
+ impl->xid = window;
+
+ win->x = attrs.x / impl->window_scale;
+ win->y = attrs.y / impl->window_scale;
+ impl->unscaled_width = attrs.width;
+ impl->unscaled_height = attrs.height;
+ win->width = attrs.width / impl->window_scale;
+ win->height = attrs.height / impl->window_scale;
+ win->window_type = GDK_SURFACE_FOREIGN;
+ win->destroyed = FALSE;
+
+ win->event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
+
+ if (attrs.map_state == IsUnmapped)
+ win->state = GDK_SURFACE_STATE_WITHDRAWN;
+ else
+ win->state = 0;
+ win->viewable = TRUE;
+
+ g_object_ref (win);
+ _gdk_x11_display_add_window (display, &GDK_SURFACE_XID (win), win);
+
+ /* Update the clip region, etc */
+ _gdk_surface_update_size (win);
+
+ return win;
+}
+
+static void
+gdk_toplevel_x11_free_contents (GdkDisplay *display,
+ GdkToplevelX11 *toplevel)
+{
+ if (toplevel->icon_pixmap)
+ {
+ cairo_surface_destroy (toplevel->icon_pixmap);
+ toplevel->icon_pixmap = NULL;
+ }
+ if (toplevel->icon_mask)
+ {
+ cairo_surface_destroy (toplevel->icon_mask);
+ toplevel->icon_mask = NULL;
+ }
+ if (toplevel->group_leader)
+ {
+ g_object_unref (toplevel->group_leader);
+ toplevel->group_leader = NULL;
+ }
+#ifdef HAVE_XSYNC
+ if (toplevel->update_counter != None)
+ {
+ XSyncDestroyCounter (GDK_DISPLAY_XDISPLAY (display),
+ toplevel->update_counter);
+ XSyncDestroyCounter (GDK_DISPLAY_XDISPLAY (display),
+ toplevel->extended_update_counter);
+ toplevel->update_counter = None;
+ toplevel->extended_update_counter = None;
+
+ toplevel->current_counter_value = 0;
+ }
+#endif
+}
+
+static void
+gdk_x11_surface_destroy (GdkSurface *window,
+ gboolean recursing,
+ gboolean foreign_destroy)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+ GdkToplevelX11 *toplevel;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+ if (toplevel)
+ gdk_toplevel_x11_free_contents (GDK_SURFACE_DISPLAY (window), toplevel);
+
+ unhook_surface_changed (window);
+
+ if (impl->cairo_surface)
+ {
+ cairo_surface_finish (impl->cairo_surface);
+ cairo_surface_destroy (impl->cairo_surface);
+ impl->cairo_surface = NULL;
+ }
+
+ if (!recursing && !foreign_destroy)
+ XDestroyWindow (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XID (window));
+}
+
+/* This function is called when the XWindow is really gone.
+ */
+static void
+gdk_x11_surface_destroy_notify (GdkSurface *window)
+{
+ GdkSurfaceImplX11 *window_impl;
+
+ window_impl = GDK_SURFACE_IMPL_X11 ((window)->impl);
+
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ if (GDK_SURFACE_TYPE(window) != GDK_SURFACE_FOREIGN)
+ g_warning ("GdkSurface %#lx unexpectedly destroyed", GDK_SURFACE_XID (window));
+
+ _gdk_surface_destroy (window, TRUE);
+ }
+
+ _gdk_x11_display_remove_window (GDK_SURFACE_DISPLAY (window), GDK_SURFACE_XID (window));
+ if (window_impl->toplevel && window_impl->toplevel->focus_window)
+ _gdk_x11_display_remove_window (GDK_SURFACE_DISPLAY (window), window_impl->toplevel->focus_window);
+
+ _gdk_x11_surface_grab_check_destroy (window);
+
+ g_object_unref (window);
+}
+
+static void
+update_wm_hints (GdkSurface *window,
+ gboolean force)
+{
+ GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (window);
+ GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
+ XWMHints wm_hints;
+
+ if (!force &&
+ !toplevel->is_leader &&
+ window->state & GDK_SURFACE_STATE_WITHDRAWN)
+ return;
+
+ wm_hints.flags = StateHint | InputHint;
+ wm_hints.input = window->accept_focus ? True : False;
+ wm_hints.initial_state = NormalState;
+
+ if (window->state & GDK_SURFACE_STATE_ICONIFIED)
+ {
+ wm_hints.flags |= StateHint;
+ wm_hints.initial_state = IconicState;
+ }
+
+ if (toplevel->icon_pixmap)
+ {
+ wm_hints.flags |= IconPixmapHint;
+ wm_hints.icon_pixmap = cairo_xlib_surface_get_drawable (toplevel->icon_pixmap);
+ }
+
+ if (toplevel->icon_mask)
+ {
+ wm_hints.flags |= IconMaskHint;
+ wm_hints.icon_mask = cairo_xlib_surface_get_drawable (toplevel->icon_mask);
+ }
+
+ wm_hints.flags |= WindowGroupHint;
+ if (toplevel->group_leader && !GDK_SURFACE_DESTROYED (toplevel->group_leader))
+ {
+ wm_hints.flags |= WindowGroupHint;
+ wm_hints.window_group = GDK_SURFACE_XID (toplevel->group_leader);
+ }
+ else
+ wm_hints.window_group = GDK_X11_DISPLAY (display)->leader_window;
+
+ if (toplevel->urgency_hint)
+ wm_hints.flags |= XUrgencyHint;
+
+ XSetWMHints (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ &wm_hints);
+}
+
+static void
+set_initial_hints (GdkSurface *window)
+{
+ GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
+ Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+ Window xwindow = GDK_SURFACE_XID (window);
+ GdkToplevelX11 *toplevel;
+ Atom atoms[9];
+ gint i;
+
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+
+ if (!toplevel)
+ return;
+
+ update_wm_hints (window, TRUE);
+
+ /* We set the spec hints regardless of whether the spec is supported,
+ * since it can't hurt and it's kind of expensive to check whether
+ * it's supported.
+ */
+
+ i = 0;
+
+ if (window->state & GDK_SURFACE_STATE_MAXIMIZED)
+ {
+ atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_STATE_MAXIMIZED_VERT");
+ ++i;
+ atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_STATE_MAXIMIZED_HORZ");
+ ++i;
+ toplevel->have_maxhorz = toplevel->have_maxvert = TRUE;
+ }
+
+ if (window->state & GDK_SURFACE_STATE_ABOVE)
+ {
+ atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_STATE_ABOVE");
+ ++i;
+ }
+
+ if (window->state & GDK_SURFACE_STATE_BELOW)
+ {
+ atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_STATE_BELOW");
+ ++i;
+ }
+
+ if (window->state & GDK_SURFACE_STATE_STICKY)
+ {
+ atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_STATE_STICKY");
+ ++i;
+ toplevel->have_sticky = TRUE;
+ }
+
+ if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
+ {
+ atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_STATE_FULLSCREEN");
+ ++i;
+ toplevel->have_fullscreen = TRUE;
+ }
+
+ if (window->modal_hint)
+ {
+ atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_STATE_MODAL");
+ ++i;
+ }
+
+ if (toplevel->skip_taskbar_hint)
+ {
+ atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_STATE_SKIP_TASKBAR");
+ ++i;
+ }
+
+ if (toplevel->skip_pager_hint)
+ {
+ atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_STATE_SKIP_PAGER");
+ ++i;
+ }
+
+ if (window->state & GDK_SURFACE_STATE_ICONIFIED)
+ {
+ atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_STATE_HIDDEN");
+ ++i;
+ toplevel->have_hidden = TRUE;
+ }
+
+ if (i > 0)
+ {
+ XChangeProperty (xdisplay,
+ xwindow,
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
+ XA_ATOM, 32, PropModeReplace,
+ (guchar*) atoms, i);
+ }
+ else
+ {
+ XDeleteProperty (xdisplay,
+ xwindow,
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"));
+ }
+
+ if (window->state & GDK_SURFACE_STATE_STICKY)
+ {
+ atoms[0] = 0xFFFFFFFF;
+ XChangeProperty (xdisplay,
+ xwindow,
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
+ XA_CARDINAL, 32, PropModeReplace,
+ (guchar*) atoms, 1);
+ toplevel->on_all_desktops = TRUE;
+ }
+ else
+ {
+ XDeleteProperty (xdisplay,
+ xwindow,
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"));
+ }
+
+ toplevel->map_serial = NextRequest (xdisplay);
+}
+
+static void
+gdk_surface_x11_show (GdkSurface *window, gboolean already_mapped)
+{
+ GdkDisplay *display;
+ GdkX11Display *display_x11;
+ GdkToplevelX11 *toplevel;
+ Display *xdisplay = GDK_SURFACE_XDISPLAY (window);
+ Window xwindow = GDK_SURFACE_XID (window);
+
+ if (!already_mapped)
+ set_initial_hints (window);
+
+ if (WINDOW_IS_TOPLEVEL (window))
+ {
+ display = gdk_surface_get_display (window);
+ display_x11 = GDK_X11_DISPLAY (display);
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+
+ if (toplevel->user_time != 0 &&
+ display_x11->user_time != 0 &&
+ XSERVER_TIME_IS_LATER (display_x11->user_time, toplevel->user_time))
+ gdk_x11_surface_set_user_time (window, display_x11->user_time);
+ }
+
+ XMapWindow (xdisplay, xwindow);
+
+ /* Fullscreen on current monitor is the default, no need to apply this mode
+ * when mapping a window. This also ensures that the default behavior remains
+ * consistent with pre-fullscreen mode implementation.
+ */
+ if (window->fullscreen_mode != GDK_FULLSCREEN_ON_CURRENT_MONITOR)
+ gdk_x11_surface_apply_fullscreen_mode (window);
+}
+
+static void
+gdk_surface_x11_hide (GdkSurface *window)
+{
+ /* We'll get the unmap notify eventually, and handle it then,
+ * but checking here makes things more consistent if we are
+ * just doing stuff ourself.
+ */
+ _gdk_x11_surface_grab_check_unmap (window,
+ NextRequest (GDK_SURFACE_XDISPLAY (window)));
+
+ /* You can't simply unmap toplevel windows. */
+ switch (window->window_type)
+ {
+ case GDK_SURFACE_TOPLEVEL:
+ case GDK_SURFACE_TEMP: /* ? */
+ gdk_surface_withdraw (window);
+ return;
+
+ case GDK_SURFACE_FOREIGN:
+ case GDK_SURFACE_CHILD:
+ default:
+ break;
+ }
+
+ _gdk_surface_clear_update_area (window);
+
+ XUnmapWindow (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window));
+}
+
+static void
+gdk_surface_x11_withdraw (GdkSurface *window)
+{
+ if (!window->destroyed)
+ {
+ if (GDK_SURFACE_IS_MAPPED (window))
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_SURFACE_STATE_WITHDRAWN);
+
+ g_assert (!GDK_SURFACE_IS_MAPPED (window));
+
+ XWithdrawWindow (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window), 0);
+ }
+}
+
+static inline void
+window_x11_move (GdkSurface *window,
+ gint x,
+ gint y)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ XMoveWindow (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ x * impl->window_scale, y * impl->window_scale);
+
+ if (impl->override_redirect)
+ {
+ window->x = x;
+ window->y = y;
+ }
+}
+
+static inline void
+window_x11_resize (GdkSurface *window,
+ gint width,
+ gint height)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (width < 1)
+ width = 1;
+
+ if (height < 1)
+ height = 1;
+
+ window_pre_damage (window);
+
+ XResizeWindow (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ width * impl->window_scale, height * impl->window_scale);
+
+ if (impl->override_redirect)
+ {
+ impl->unscaled_width = width * impl->window_scale;
+ impl->unscaled_height = height * impl->window_scale;
+ window->width = width;
+ window->height = height;
+ _gdk_x11_surface_update_size (GDK_SURFACE_IMPL_X11 (window->impl));
+ }
+ else
+ {
+ if (width * impl->window_scale != impl->unscaled_width || height * impl->window_scale != impl->unscaled_height)
+ window->resize_count += 1;
+ }
+}
+
+static inline void
+window_x11_move_resize (GdkSurface *window,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (width < 1)
+ width = 1;
+
+ if (height < 1)
+ height = 1;
+
+ window_pre_damage (window);
+
+ XMoveResizeWindow (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ x * impl->window_scale, y * impl->window_scale,
+ width * impl->window_scale, height * impl->window_scale);
+
+ if (impl->override_redirect)
+ {
+ window->x = x;
+ window->y = y;
+
+ impl->unscaled_width = width * impl->window_scale;
+ impl->unscaled_height = height * impl->window_scale;
+ window->width = width;
+ window->height = height;
+
+ _gdk_x11_surface_update_size (GDK_SURFACE_IMPL_X11 (window->impl));
+ }
+ else
+ {
+ if (width * impl->window_scale != impl->unscaled_width || height * impl->window_scale != impl->unscaled_height)
+ window->resize_count += 1;
+ }
+}
+
+static void
+gdk_surface_x11_move_resize (GdkSurface *window,
+ gboolean with_move,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ if (with_move && (width < 0 && height < 0))
+ window_x11_move (window, x, y);
+ else
+ {
+ if (with_move)
+ window_x11_move_resize (window, x, y, width, height);
+ else
+ window_x11_resize (window, width, height);
+ }
+}
+
+void
+_gdk_x11_surface_set_window_scale (GdkSurface *window,
+ int scale)
+{
+ GdkSurfaceImplX11 *impl;
+ GdkToplevelX11 *toplevel;
+ GdkSurfaceHints geom_mask;
+
+ impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ impl->window_scale = scale;
+ if (impl->cairo_surface)
+ cairo_surface_set_device_scale (impl->cairo_surface, impl->window_scale, impl->window_scale);
+ _gdk_surface_update_size (window);
+
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+ if (toplevel && window->window_type != GDK_SURFACE_FOREIGN)
+ {
+ /* These are affected by window scale: */
+ geom_mask = toplevel->last_geometry_hints_mask &
+ (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE | GDK_HINT_BASE_SIZE | GDK_HINT_RESIZE_INC);
+ if (geom_mask)
+ gdk_surface_set_geometry_hints (window,
+ &toplevel->last_geometry_hints,
+ geom_mask);
+ }
+
+ if (window->window_type == GDK_SURFACE_FOREIGN)
+ XMoveWindow (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ window->x * impl->window_scale,
+ window->y * impl->window_scale);
+ else
+ {
+ if (impl->override_redirect)
+ {
+ impl->unscaled_width = window->width * impl->window_scale;
+ impl->unscaled_height = window->height * impl->window_scale;
+ }
+
+ XResizeWindow (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ window->width * impl->window_scale,
+ window->height * impl->window_scale);
+ }
+
+ gdk_surface_invalidate_rect (window, NULL, TRUE);
+}
+
+static void
+gdk_surface_x11_raise (GdkSurface *window)
+{
+ XRaiseWindow (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XID (window));
+}
+
+static void
+gdk_surface_x11_restack_toplevel (GdkSurface *window,
+ GdkSurface *sibling,
+ gboolean above)
+{
+ XWindowChanges changes;
+
+ changes.sibling = GDK_SURFACE_XID (sibling);
+ changes.stack_mode = above ? Above : Below;
+ XReconfigureWMWindow (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ gdk_x11_screen_get_screen_number (GDK_SURFACE_SCREEN (window)),
+ CWStackMode | CWSibling, &changes);
+}
+
+static void
+gdk_surface_x11_lower (GdkSurface *window)
+{
+ XLowerWindow (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XID (window));
+}
+
+/**
+ * gdk_x11_surface_move_to_current_desktop:
+ * @window: (type GdkX11Surface): a #GdkSurface
+ *
+ * Moves the window to the correct workspace when running under a
+ * window manager that supports multiple workspaces, as described
+ * in the [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
+ * Will not do anything if the window is already on all workspaces.
+ */
+void
+gdk_x11_surface_move_to_current_desktop (GdkSurface *window)
+{
+ GdkToplevelX11 *toplevel;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD);
+
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+
+ if (toplevel->on_all_desktops)
+ return;
+
+ move_to_current_desktop (window);
+}
+
+static void
+move_to_current_desktop (GdkSurface *window)
+{
+ guint32 desktop;
+
+ desktop = gdk_x11_screen_get_current_desktop (GDK_SURFACE_SCREEN (window));
+ gdk_x11_surface_move_to_desktop (window, desktop);
+}
+
+static guint32
+get_netwm_cardinal_property (GdkSurface *window,
+ const gchar *name)
+{
+ GdkX11Screen *x11_screen = GDK_SURFACE_SCREEN (window);
+ GdkAtom atom;
+ guint32 prop = 0;
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ guchar *data;
+
+ atom = g_intern_static_string (name);
+
+ if (!gdk_x11_screen_supports_net_wm_hint (x11_screen, atom))
+ return 0;
+
+ XGetWindowProperty (x11_screen->xdisplay,
+ GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (window), name),
+ 0, G_MAXLONG,
+ False, XA_CARDINAL, &type, &format, &nitems,
+ &bytes_after, &data);
+ if (type == XA_CARDINAL)
+ {
+ prop = *(gulong *)data;
+ XFree (data);
+ }
+
+ return prop;
+}
+
+/**
+ * gdk_x11_surface_get_desktop:
+ * @window: (type GdkX11Surface): a #GdkSurface
+ *
+ * Gets the number of the workspace @window is on.
+ *
+ * Returns: the current workspace of @window
+ */
+guint32
+gdk_x11_surface_get_desktop (GdkSurface *window)
+{
+ g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
+
+ return get_netwm_cardinal_property (window, "_NET_WM_DESKTOP");
+}
+
+/**
+ * gdk_x11_surface_move_to_desktop:
+ * @window: (type GdkX11Surface): a #GdkSurface
+ * @desktop: the number of the workspace to move the window to
+ *
+ * Moves the window to the given workspace when running unde a
+ * window manager that supports multiple workspaces, as described
+ * in the [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
+ */
+void
+gdk_x11_surface_move_to_desktop (GdkSurface *window,
+ guint32 desktop)
+{
+ GdkAtom atom;
+ XClientMessageEvent xclient;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ atom = g_intern_static_string ("_NET_WM_DESKTOP");
+ if (!gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window), atom))
+ return;
+
+ memset (&xclient, 0, sizeof (xclient));
+ xclient.type = ClientMessage;
+ xclient.serial = 0;
+ xclient.send_event = True;
+ xclient.window = GDK_SURFACE_XID (window);
+ xclient.message_type = gdk_x11_atom_to_xatom_for_display (GDK_SURFACE_DISPLAY (window), atom);
+ xclient.format = 32;
+
+ xclient.data.l[0] = desktop;
+ xclient.data.l[1] = 1; /* source indication */
+ xclient.data.l[2] = 0;
+ xclient.data.l[3] = 0;
+ xclient.data.l[4] = 0;
+
+ XSendEvent (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XROOTWIN (window),
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ (XEvent *)&xclient);
+}
+
+static void
+gdk_x11_surface_focus (GdkSurface *window,
+ guint32 timestamp)
+{
+ GdkDisplay *display;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ display = GDK_SURFACE_DISPLAY (window);
+
+ if (gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
+ g_intern_static_string ("_NET_ACTIVE_WINDOW")))
+ {
+ XClientMessageEvent xclient;
+
+ memset (&xclient, 0, sizeof (xclient));
+ xclient.type = ClientMessage;
+ xclient.window = GDK_SURFACE_XID (window);
+ xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
+ "_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[2] = None; /* currently active window */
+ xclient.data.l[3] = 0;
+ xclient.data.l[4] = 0;
+
+ XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XROOTWIN (window), False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ (XEvent *)&xclient);
+ }
+ else
+ {
+ XRaiseWindow (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window));
+
+ /* There is no way of knowing reliably whether we are viewable;
+ * so trap errors asynchronously around the XSetInputFocus call
+ */
+ gdk_x11_display_error_trap_push (display);
+ XSetInputFocus (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SURFACE_XID (window),
+ RevertToParent,
+ timestamp);
+ gdk_x11_display_error_trap_pop_ignored (display);
+ }
+}
+
+static void
+gdk_x11_surface_set_type_hint (GdkSurface *window,
+ GdkSurfaceTypeHint hint)
+{
+ GdkDisplay *display;
+ Atom atom;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ display = gdk_surface_get_display (window);
+
+ switch (hint)
+ {
+ case GDK_SURFACE_TYPE_HINT_DIALOG:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DIALOG");
+ break;
+ case GDK_SURFACE_TYPE_HINT_MENU:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_MENU");
+ break;
+ case GDK_SURFACE_TYPE_HINT_TOOLBAR:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR");
+ break;
+ case GDK_SURFACE_TYPE_HINT_UTILITY:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_UTILITY");
+ break;
+ case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_SPLASH");
+ break;
+ case GDK_SURFACE_TYPE_HINT_DOCK:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DOCK");
+ break;
+ case GDK_SURFACE_TYPE_HINT_DESKTOP:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DESKTOP");
+ break;
+ case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU");
+ break;
+ case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_POPUP_MENU");
+ break;
+ case GDK_SURFACE_TYPE_HINT_TOOLTIP:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLTIP");
+ break;
+ case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NOTIFICATION");
+ break;
+ case GDK_SURFACE_TYPE_HINT_COMBO:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_COMBO");
+ break;
+ case GDK_SURFACE_TYPE_HINT_DND:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DND");
+ break;
+ default:
+ g_warning ("Unknown hint %d passed to gdk_surface_set_type_hint", hint);
+ /* Fall thru */
+ case GDK_SURFACE_TYPE_HINT_NORMAL:
+ atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NORMAL");
+ break;
+ }
+
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
+ XA_ATOM, 32, PropModeReplace,
+ (guchar *)&atom, 1);
+}
+
+static GdkSurfaceTypeHint
+gdk_x11_surface_get_type_hint (GdkSurface *window)
+{
+ GdkDisplay *display;
+ GdkSurfaceTypeHint type;
+ Atom type_return;
+ gint format_return;
+ gulong nitems_return;
+ gulong bytes_after_return;
+ guchar *data = NULL;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), GDK_SURFACE_TYPE_HINT_NORMAL);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return GDK_SURFACE_TYPE_HINT_NORMAL;
+
+ type = GDK_SURFACE_TYPE_HINT_NORMAL;
+
+ display = gdk_surface_get_display (window);
+
+ if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
+ 0, G_MAXLONG, False, XA_ATOM, &type_return,
+ &format_return, &nitems_return, &bytes_after_return,
+ &data) == Success)
+ {
+ if ((type_return == XA_ATOM) && (format_return == 32) &&
+ (data) && (nitems_return == 1))
+ {
+ Atom atom = *(Atom*)data;
+
+ if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DIALOG"))
+ type = GDK_SURFACE_TYPE_HINT_DIALOG;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_MENU"))
+ type = GDK_SURFACE_TYPE_HINT_MENU;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR"))
+ type = GDK_SURFACE_TYPE_HINT_TOOLBAR;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_UTILITY"))
+ type = GDK_SURFACE_TYPE_HINT_UTILITY;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_SPLASH"))
+ type = GDK_SURFACE_TYPE_HINT_SPLASHSCREEN;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DOCK"))
+ type = GDK_SURFACE_TYPE_HINT_DOCK;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DESKTOP"))
+ type = GDK_SURFACE_TYPE_HINT_DESKTOP;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"))
+ type = GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_POPUP_MENU"))
+ type = GDK_SURFACE_TYPE_HINT_POPUP_MENU;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLTIP"))
+ type = GDK_SURFACE_TYPE_HINT_TOOLTIP;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NOTIFICATION"))
+ type = GDK_SURFACE_TYPE_HINT_NOTIFICATION;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_COMBO"))
+ type = GDK_SURFACE_TYPE_HINT_COMBO;
+ else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DND"))
+ type = GDK_SURFACE_TYPE_HINT_DND;
+ }
+
+ if (type_return != None && data != NULL)
+ XFree (data);
+ }
+
+ return type;
+}
+
+static void
+gdk_wmspec_change_state (gboolean add,
+ GdkSurface *window,
+ GdkAtom state1,
+ GdkAtom state2)
+{
+ GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
+ XClientMessageEvent xclient;
+
+#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
+#define _NET_WM_STATE_ADD 1 /* add/set property */
+#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
+
+ memset (&xclient, 0, sizeof (xclient));
+ xclient.type = ClientMessage;
+ xclient.window = GDK_SURFACE_XID (window);
+ xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE");
+ xclient.format = 32;
+ 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] = 1; /* source indication */
+ xclient.data.l[4] = 0;
+
+ XSendEvent (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XROOTWIN (window), False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ (XEvent *)&xclient);
+}
+
+static void
+gdk_x11_surface_set_modal_hint (GdkSurface *window,
+ gboolean modal)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ window->modal_hint = modal;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ gdk_wmspec_change_state (modal, window,
+ g_intern_static_string ("_NET_WM_STATE_MODAL"),
+ NULL);
+}
+
+static void
+gdk_x11_surface_set_skip_taskbar_hint (GdkSurface *window,
+ gboolean skips_taskbar)
+{
+ GdkToplevelX11 *toplevel;
+
+ g_return_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+ toplevel->skip_taskbar_hint = skips_taskbar;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ gdk_wmspec_change_state (skips_taskbar, window,
+ g_intern_static_string ("_NET_WM_STATE_SKIP_TASKBAR"),
+ NULL);
+}
+
+static void
+gdk_x11_surface_set_skip_pager_hint (GdkSurface *window,
+ gboolean skips_pager)
+{
+ GdkToplevelX11 *toplevel;
+
+ g_return_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+ toplevel->skip_pager_hint = skips_pager;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ gdk_wmspec_change_state (skips_pager, window,
+ g_intern_static_string ("_NET_WM_STATE_SKIP_PAGER"),
+ NULL);
+}
+
+static void
+gdk_x11_surface_set_urgency_hint (GdkSurface *window,
+ gboolean urgent)
+{
+ GdkToplevelX11 *toplevel;
+
+ g_return_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+ toplevel->urgency_hint = urgent;
+
+ update_wm_hints (window, FALSE);
+}
+
+static void
+gdk_x11_surface_set_geometry_hints (GdkSurface *window,
+ const GdkGeometry *geometry,
+ GdkSurfaceHints geom_mask)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+ XSizeHints size_hints;
+ GdkToplevelX11 *toplevel;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+ if (toplevel)
+ {
+ if (geometry)
+ toplevel->last_geometry_hints = *geometry;
+ toplevel->last_geometry_hints_mask = geom_mask;
+ }
+
+ size_hints.flags = 0;
+
+ if (geom_mask & GDK_HINT_POS)
+ {
+ size_hints.flags |= PPosition;
+ /* We need to initialize the following obsolete fields because KWM
+ * apparently uses these fields if they are non-zero.
+ * #@#!#!$!.
+ */
+ size_hints.x = 0;
+ size_hints.y = 0;
+ }
+
+ if (geom_mask & GDK_HINT_USER_POS)
+ {
+ size_hints.flags |= USPosition;
+ }
+
+ if (geom_mask & GDK_HINT_USER_SIZE)
+ {
+ size_hints.flags |= USSize;
+ }
+
+ if (geom_mask & GDK_HINT_MIN_SIZE)
+ {
+ size_hints.flags |= PMinSize;
+ size_hints.min_width = geometry->min_width * impl->window_scale;
+ size_hints.min_height = geometry->min_height * impl->window_scale;
+ }
+
+ if (geom_mask & GDK_HINT_MAX_SIZE)
+ {
+ size_hints.flags |= PMaxSize;
+ size_hints.max_width = MAX (geometry->max_width, 1) * impl->window_scale;
+ size_hints.max_height = MAX (geometry->max_height, 1) * impl->window_scale;
+ }
+
+ if (geom_mask & GDK_HINT_BASE_SIZE)
+ {
+ size_hints.flags |= PBaseSize;
+ size_hints.base_width = geometry->base_width * impl->window_scale;
+ size_hints.base_height = geometry->base_height * impl->window_scale;
+ }
+
+ if (geom_mask & GDK_HINT_RESIZE_INC)
+ {
+ size_hints.flags |= PResizeInc;
+ size_hints.width_inc = geometry->width_inc * impl->window_scale;
+ size_hints.height_inc = geometry->height_inc * impl->window_scale;
+ }
+ else if (impl->window_scale > 1)
+ {
+ size_hints.flags |= PResizeInc;
+ size_hints.width_inc = impl->window_scale;
+ size_hints.height_inc = impl->window_scale;
+ }
+
+ if (geom_mask & GDK_HINT_ASPECT)
+ {
+ size_hints.flags |= PAspect;
+ if (geometry->min_aspect <= 1)
+ {
+ size_hints.min_aspect.x = 65536 * geometry->min_aspect;
+ size_hints.min_aspect.y = 65536;
+ }
+ else
+ {
+ size_hints.min_aspect.x = 65536;
+ size_hints.min_aspect.y = 65536 / geometry->min_aspect;;
+ }
+ if (geometry->max_aspect <= 1)
+ {
+ size_hints.max_aspect.x = 65536 * geometry->max_aspect;
+ size_hints.max_aspect.y = 65536;
+ }
+ else
+ {
+ size_hints.max_aspect.x = 65536;
+ size_hints.max_aspect.y = 65536 / geometry->max_aspect;;
+ }
+ }
+
+ if (geom_mask & GDK_HINT_WIN_GRAVITY)
+ {
+ size_hints.flags |= PWinGravity;
+ size_hints.win_gravity = geometry->win_gravity;
+ }
+
+ /* FIXME: Would it be better to delete this property if
+ * geom_mask == 0? It would save space on the server
+ */
+ XSetWMNormalHints (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ &size_hints);
+}
+
+static void
+gdk_surface_get_geometry_hints (GdkSurface *window,
+ GdkGeometry *geometry,
+ GdkSurfaceHints *geom_mask)
+{
+ GdkSurfaceImplX11 *impl;
+ XSizeHints *size_hints;
+ glong junk_supplied_mask = 0;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (geometry != NULL);
+ g_return_if_fail (geom_mask != NULL);
+
+ *geom_mask = 0;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ size_hints = XAllocSizeHints ();
+ if (!size_hints)
+ return;
+
+ if (!XGetWMNormalHints (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ size_hints,
+ &junk_supplied_mask))
+ size_hints->flags = 0;
+
+ if (size_hints->flags & PMinSize)
+ {
+ *geom_mask |= GDK_HINT_MIN_SIZE;
+ geometry->min_width = size_hints->min_width / impl->window_scale;
+ geometry->min_height = size_hints->min_height / impl->window_scale;
+ }
+
+ if (size_hints->flags & PMaxSize)
+ {
+ *geom_mask |= GDK_HINT_MAX_SIZE;
+ geometry->max_width = MAX (size_hints->max_width, 1) / impl->window_scale;
+ geometry->max_height = MAX (size_hints->max_height, 1) / impl->window_scale;
+ }
+
+ if (size_hints->flags & PResizeInc)
+ {
+ *geom_mask |= GDK_HINT_RESIZE_INC;
+ geometry->width_inc = size_hints->width_inc / impl->window_scale;
+ geometry->height_inc = size_hints->height_inc / impl->window_scale;
+ }
+
+ if (size_hints->flags & PAspect)
+ {
+ *geom_mask |= GDK_HINT_ASPECT;
+
+ geometry->min_aspect = (gdouble) size_hints->min_aspect.x / (gdouble) size_hints->min_aspect.y;
+ geometry->max_aspect = (gdouble) size_hints->max_aspect.x / (gdouble) size_hints->max_aspect.y;
+ }
+
+ if (size_hints->flags & PWinGravity)
+ {
+ *geom_mask |= GDK_HINT_WIN_GRAVITY;
+ geometry->win_gravity = size_hints->win_gravity;
+ }
+
+ XFree (size_hints);
+}
+
+static gboolean
+utf8_is_latin1 (const gchar *str)
+{
+ const char *p = str;
+
+ while (*p)
+ {
+ gunichar ch = g_utf8_get_char (p);
+
+ if (ch > 0xff)
+ return FALSE;
+
+ p = g_utf8_next_char (p);
+ }
+
+ return TRUE;
+}
+
+/* Set the property to @utf8_str as STRING if the @utf8_str is fully
+ * convertable to STRING, otherwise, set it as compound text
+ */
+static void
+set_text_property (GdkDisplay *display,
+ Window xwindow,
+ Atom property,
+ const gchar *utf8_str)
+{
+ gchar *prop_text = NULL;
+ Atom prop_type;
+ gint prop_length;
+ gint prop_format;
+ gboolean is_compound_text;
+
+ if (utf8_is_latin1 (utf8_str))
+ {
+ prop_type = XA_STRING;
+ prop_text = _gdk_x11_display_utf8_to_string_target (display, utf8_str);
+ prop_length = prop_text ? strlen (prop_text) : 0;
+ prop_format = 8;
+ is_compound_text = FALSE;
+ }
+ else
+ {
+ GdkAtom gdk_type;
+
+ gdk_x11_display_utf8_to_compound_text (display,
+ utf8_str, &gdk_type, &prop_format,
+ (guchar **)&prop_text, &prop_length);
+ prop_type = gdk_x11_atom_to_xatom_for_display (display, gdk_type);
+ is_compound_text = TRUE;
+ }
+
+ if (prop_text)
+ {
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+ xwindow,
+ property,
+ prop_type, prop_format,
+ PropModeReplace, (guchar *)prop_text,
+ prop_length);
+
+ if (is_compound_text)
+ gdk_x11_free_compound_text ((guchar *)prop_text);
+ else
+ g_free (prop_text);
+ }
+}
+
+/* Set WM_NAME and _NET_WM_NAME
+ */
+static void
+set_wm_name (GdkDisplay *display,
+ Window xwindow,
+ const gchar *name)
+{
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME"),
+ gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+ PropModeReplace, (guchar *)name, strlen (name));
+
+ set_text_property (display, xwindow,
+ gdk_x11_get_xatom_by_name_for_display (display, "WM_NAME"),
+ name);
+}
+
+static void
+gdk_x11_surface_set_title (GdkSurface *window,
+ const gchar *title)
+{
+ GdkDisplay *display;
+ Display *xdisplay;
+ Window xwindow;
+
+ g_return_if_fail (title != NULL);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ display = gdk_surface_get_display (window);
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+ xwindow = GDK_SURFACE_XID (window);
+
+ set_wm_name (display, xwindow, title);
+
+ if (!gdk_surface_icon_name_set (window))
+ {
+ XChangeProperty (xdisplay, xwindow,
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
+ gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+ PropModeReplace, (guchar *)title, strlen (title));
+
+ set_text_property (display, xwindow,
+ gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
+ title);
+ }
+}
+
+static void
+gdk_x11_surface_set_role (GdkSurface *window,
+ const gchar *role)
+{
+ GdkDisplay *display;
+
+ display = gdk_surface_get_display (window);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (role)
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE"),
+ XA_STRING, 8, PropModeReplace, (guchar *)role, strlen (role));
+ else
+ XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE"));
+}
+
+static void
+gdk_x11_surface_set_startup_id (GdkSurface *window,
+ const gchar *startup_id)
+{
+ GdkDisplay *display;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ display = gdk_surface_get_display (window);
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (startup_id)
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
+ gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+ PropModeReplace, (unsigned char *)startup_id, strlen (startup_id));
+ else
+ XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"));
+}
+
+static void
+gdk_x11_surface_set_transient_for (GdkSurface *window,
+ GdkSurface *parent)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ /* XSetTransientForHint() doesn't allow unsetting, so do it manually */
+ if (parent && !GDK_SURFACE_DESTROYED (parent))
+ XSetTransientForHint (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ GDK_SURFACE_XID (parent));
+ else
+ XDeleteProperty (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (window), "WM_TRANSIENT_FOR"));
+}
+
+GdkCursor *
+_gdk_x11_surface_get_cursor (GdkSurface *window)
+{
+ GdkSurfaceImplX11 *impl;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
+
+ impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ return impl->cursor;
+}
+
+static void
+gdk_surface_x11_get_geometry (GdkSurface *window,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height)
+{
+ GdkSurfaceImplX11 *impl;
+ Window root;
+ gint tx;
+ gint ty;
+ guint twidth;
+ guint theight;
+ guint tborder_width;
+ guint tdepth;
+
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ XGetGeometry (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
+
+ if (x)
+ *x = tx / impl->window_scale;
+ if (y)
+ *y = ty / impl->window_scale;
+ if (width)
+ *width = twidth / impl->window_scale;
+ if (height)
+ *height = theight / impl->window_scale;
+ }
+}
+
+static void
+gdk_surface_x11_get_root_coords (GdkSurface *window,
+ gint x,
+ gint y,
+ gint *root_x,
+ gint *root_y)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+ Window child;
+ gint tx;
+ gint ty;
+
+ XTranslateCoordinates (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ GDK_SURFACE_XROOTWIN (window),
+ x * impl->window_scale, y * impl->window_scale, &tx, &ty,
+ &child);
+
+ if (root_x)
+ *root_x = tx / impl->window_scale;
+ if (root_y)
+ *root_y = ty / impl->window_scale;
+}
+
+static void
+gdk_x11_surface_get_frame_extents (GdkSurface *window,
+ GdkRectangle *rect)
+{
+ GdkDisplay *display;
+ GdkSurfaceImplX11 *impl;
+ Window xwindow;
+ Window xparent;
+ Window root;
+ Window child;
+ Window *children;
+ guchar *data;
+ Window *vroots;
+ Atom type_return;
+ guint nchildren;
+ guint nvroots;
+ gulong nitems_return;
+ gulong bytes_after_return;
+ gint format_return;
+ gint i;
+ guint ww, wh, wb, wd;
+ gint wx, wy;
+ gboolean got_frame_extents = FALSE;
+
+ g_return_if_fail (rect != NULL);
+
+ rect->x = 0;
+ rect->y = 0;
+ rect->width = 1;
+ rect->height = 1;
+
+ while (window->parent && (window->parent)->parent)
+ window = window->parent;
+
+ impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ /* Refine our fallback answer a bit using local information */
+ rect->x = window->x * impl->window_scale;
+ rect->y = window->y * impl->window_scale;
+ rect->width = window->width * impl->window_scale;
+ rect->height = window->height * impl->window_scale;
+
+ if (GDK_SURFACE_DESTROYED (window) || impl->override_redirect)
+ return;
+
+ nvroots = 0;
+ vroots = NULL;
+
+ display = gdk_surface_get_display (window);
+
+ gdk_x11_display_error_trap_push (display);
+
+ xwindow = GDK_SURFACE_XID (window);
+
+ /* first try: use _NET_FRAME_EXTENTS */
+ if (gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
+ g_intern_static_string ("_NET_FRAME_EXTENTS")) &&
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
+ gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_FRAME_EXTENTS"),
+ 0, G_MAXLONG, False, XA_CARDINAL, &type_return,
+ &format_return, &nitems_return, &bytes_after_return,
+ &data)
+ == Success)
+ {
+ if ((type_return == XA_CARDINAL) && (format_return == 32) &&
+ (nitems_return == 4) && (data))
+ {
+ gulong *ldata = (gulong *) data;
+ got_frame_extents = TRUE;
+
+ /* try to get the real client window geometry */
+ if (XGetGeometry (GDK_DISPLAY_XDISPLAY (display), xwindow,
+ &root, &wx, &wy, &ww, &wh, &wb, &wd) &&
+ XTranslateCoordinates (GDK_DISPLAY_XDISPLAY (display),
+ xwindow, root, 0, 0, &wx, &wy, &child))
+ {
+ rect->x = wx;
+ rect->y = wy;
+ rect->width = ww;
+ rect->height = wh;
+ }
+
+ /* _NET_FRAME_EXTENTS format is left, right, top, bottom */
+ rect->x -= ldata[0];
+ rect->y -= ldata[2];
+ rect->width += ldata[0] + ldata[1];
+ rect->height += ldata[2] + ldata[3];
+ }
+
+ if (data)
+ XFree (data);
+ }
+
+ if (got_frame_extents)
+ goto out;
+
+ /* no frame extents property available, which means we either have a WM that
+ is not EWMH compliant or is broken - try fallback and walk up the window
+ tree to get our window's parent which hopefully is the window frame */
+
+ /* use NETWM_VIRTUAL_ROOTS if available */
+ root = GDK_SURFACE_XROOTWIN (window);
+
+ if (gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
+ g_intern_static_string ("_NET_VIRTUAL_ROOTS")) &&
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), root,
+ gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_VIRTUAL_ROOTS"),
+ 0, G_MAXLONG, False, XA_WINDOW, &type_return,
+ &format_return, &nitems_return, &bytes_after_return,
+ &data)
+ == Success)
+ {
+ if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
+ {
+ nvroots = nitems_return;
+ vroots = (Window *)data;
+ }
+ }
+
+ xparent = GDK_SURFACE_XID (window);
+
+ do
+ {
+ xwindow = xparent;
+
+ if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xwindow,
+ &root, &xparent,
+ &children, &nchildren))
+ goto out;
+
+ if (children)
+ XFree (children);
+
+ /* check virtual roots */
+ for (i = 0; i < nvroots; i++)
+ {
+ if (xparent == vroots[i])
+ {
+ root = xparent;
+ break;
+ }
+ }
+ }
+ while (xparent != root);
+
+ if (XGetGeometry (GDK_DISPLAY_XDISPLAY (display), xwindow,
+ &root, &wx, &wy, &ww, &wh, &wb, &wd))
+ {
+ rect->x = wx;
+ rect->y = wy;
+ rect->width = ww;
+ rect->height = wh;
+ }
+
+ out:
+ if (vroots)
+ XFree (vroots);
+
+ /* Here we extend the size to include the extra pixels if we round x/y down
+ as well as round the size up when we divide by scale so that the returned
+ size is guaranteed to cover the real pixels, but it may overshoot a bit
+ in case the window is not positioned/sized according to the scale */
+ rect->width = (rect->width + rect->x % impl->window_scale + impl->window_scale - 1) / impl->window_scale;
+ rect->height = (rect->height + rect->y % impl->window_scale + impl->window_scale - 1) / impl->window_scale;
+ rect->x = rect->x / impl->window_scale;
+ rect->y = rect->y / impl->window_scale;
+ gdk_x11_display_error_trap_pop_ignored (display);
+}
+
+static gboolean
+gdk_surface_x11_get_device_state (GdkSurface *window,
+ GdkDevice *device,
+ gdouble *x,
+ gdouble *y,
+ GdkModifierType *mask)
+{
+ GdkSurface *child;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return FALSE;
+
+ /*HIDPI: handle coords here?*/
+ GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
+ &child,
+ NULL, NULL,
+ x, y, mask);
+ return child != NULL;
+}
+
+static GdkEventMask
+gdk_surface_x11_get_events (GdkSurface *window)
+{
+ XWindowAttributes attrs;
+ GdkEventMask event_mask;
+ GdkEventMask filtered;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return 0;
+ else
+ {
+ XGetWindowAttributes (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ &attrs);
+ event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
+ /* if property change was filtered out before, keep it filtered out */
+ filtered = GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK;
+ window->event_mask = event_mask & ((window->event_mask & filtered) | ~filtered);
+
+ return event_mask;
+ }
+}
+static void
+gdk_surface_x11_set_events (GdkSurface *window,
+ GdkEventMask event_mask)
+{
+ long xevent_mask = 0;
+
+ if (!GDK_SURFACE_DESTROYED (window))
+ {
+ GdkX11Display *display_x11;
+
+ if (GDK_SURFACE_XID (window) != GDK_SURFACE_XROOTWIN (window))
+ xevent_mask = StructureNotifyMask | PropertyChangeMask;
+
+ display_x11 = GDK_X11_DISPLAY (gdk_surface_get_display (window));
+ gdk_x11_event_source_select_events ((GdkEventSource *) display_x11->event_source,
+ GDK_SURFACE_XID (window), event_mask,
+ xevent_mask);
+ }
+}
+
+static inline void
+do_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y,
+ gint shape)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (shape_region == NULL)
+ {
+ /* Use NULL mask to unset the shape */
+ if (shape == ShapeBounding
+ ? gdk_display_supports_shapes (GDK_SURFACE_DISPLAY (window))
+ : gdk_display_supports_input_shapes (GDK_SURFACE_DISPLAY (window)))
+ {
+ XShapeCombineMask (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ shape,
+ 0, 0,
+ None,
+ ShapeSet);
+ }
+ return;
+ }
+
+ if (shape == ShapeBounding
+ ? gdk_display_supports_shapes (GDK_SURFACE_DISPLAY (window))
+ : gdk_display_supports_input_shapes (GDK_SURFACE_DISPLAY (window)))
+ {
+ gint n_rects = 0;
+ XRectangle *xrects = NULL;
+
+ _gdk_x11_region_get_xrectangles (shape_region,
+ 0, 0, impl->window_scale,
+ &xrects, &n_rects);
+
+ XShapeCombineRectangles (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ shape,
+ offset_x * impl->window_scale,
+ offset_y * impl->window_scale,
+ xrects, n_rects,
+ ShapeSet,
+ YXBanded);
+
+ g_free (xrects);
+ }
+}
+
+static void
+gdk_surface_x11_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+ do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeBounding);
+}
+
+static void
+gdk_surface_x11_input_shape_combine_region (GdkSurface *window,
+ const cairo_region_t *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+#ifdef ShapeInput
+ do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeInput);
+#endif
+}
+
+static void
+gdk_x11_surface_set_accept_focus (GdkSurface *window,
+ gboolean accept_focus)
+{
+ accept_focus = accept_focus != FALSE;
+
+ if (window->accept_focus != accept_focus)
+ {
+ window->accept_focus = accept_focus;
+
+ if (!GDK_SURFACE_DESTROYED (window) &&
+ WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ update_wm_hints (window, FALSE);
+ }
+}
+
+static void
+gdk_x11_surface_set_focus_on_map (GdkSurface *window,
+ gboolean focus_on_map)
+{
+ focus_on_map = focus_on_map != FALSE;
+
+ if (window->focus_on_map != focus_on_map)
+ {
+ window->focus_on_map = focus_on_map;
+
+ if ((!GDK_SURFACE_DESTROYED (window)) &&
+ (!window->focus_on_map) &&
+ WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ gdk_x11_surface_set_user_time (window, 0);
+ }
+}
+
+/**
+ * gdk_x11_surface_set_user_time:
+ * @window: (type GdkX11Surface): A toplevel #GdkSurface
+ * @timestamp: An XServer timestamp to which the property should be set
+ *
+ * The application can use this call to update the _NET_WM_USER_TIME
+ * property on a toplevel window. This property stores an Xserver
+ * time which represents the time of the last user input event
+ * received for this window. This property may be used by the window
+ * manager to alter the focus, stacking, and/or placement behavior of
+ * windows when they are mapped depending on whether the new window
+ * was created by a user action or is a "pop-up" window activated by a
+ * timer or some other event.
+ *
+ * Note that this property is automatically updated by GDK, so this
+ * function should only be used by applications which handle input
+ * events bypassing GDK.
+ **/
+void
+gdk_x11_surface_set_user_time (GdkSurface *window,
+ guint32 timestamp)
+{
+ GdkDisplay *display;
+ GdkX11Display *display_x11;
+ GdkToplevelX11 *toplevel;
+ glong timestamp_long = (glong)timestamp;
+ Window xid;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ display = gdk_surface_get_display (window);
+ display_x11 = GDK_X11_DISPLAY (display);
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+
+ if (!toplevel)
+ {
+ g_warning ("gdk_surface_set_user_time called on non-toplevel\n");
+ return;
+ }
+
+ if (toplevel->focus_window != None &&
+ gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
+ g_intern_static_string ("_NET_WM_USER_TIME_WINDOW")))
+ xid = toplevel->focus_window;
+ else
+ xid = GDK_SURFACE_XID (window);
+
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xid,
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_USER_TIME"),
+ XA_CARDINAL, 32, PropModeReplace,
+ (guchar *)×tamp_long, 1);
+
+ if (timestamp_long != GDK_CURRENT_TIME &&
+ (display_x11->user_time == GDK_CURRENT_TIME ||
+ XSERVER_TIME_IS_LATER (timestamp_long, display_x11->user_time)))
+ display_x11->user_time = timestamp_long;
+
+ if (toplevel)
+ toplevel->user_time = timestamp_long;
+}
+
+/**
+ * gdk_x11_surface_set_utf8_property:
+ * @window: (type GdkX11Surface): a #GdkSurface
+ * @name: Property name, will be interned as an X atom
+ * @value: (allow-none): Property value, or %NULL to delete
+ *
+ * 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.
+ */
+void
+gdk_x11_surface_set_utf8_property (GdkSurface *window,
+ const gchar *name,
+ const gchar *value)
+{
+ GdkDisplay *display;
+
+ if (!WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ display = gdk_surface_get_display (window);
+
+ if (value != NULL)
+ {
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SURFACE_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_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, name));
+ }
+}
+
+static void
+gdk_x11_surface_set_shadow_width (GdkSurface *window,
+ int left,
+ int right,
+ int top,
+ int bottom)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+ Atom frame_extents;
+ gulong data[4] = {
+ left * impl->window_scale,
+ right * impl->window_scale,
+ top * impl->window_scale,
+ bottom * impl->window_scale
+ };
+
+ frame_extents = gdk_x11_get_xatom_by_name_for_display (gdk_surface_get_display (window),
+ "_GTK_FRAME_EXTENTS");
+ XChangeProperty (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ frame_extents, XA_CARDINAL,
+ 32, PropModeReplace,
+ (guchar *) &data, 4);
+}
+
+/**
+ * gdk_x11_surface_set_theme_variant:
+ * @window: (type GdkX11Surface): a #GdkSurface
+ * @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.
+ */
+void
+gdk_x11_surface_set_theme_variant (GdkSurface *window,
+ const char *variant)
+{
+ gdk_x11_surface_set_utf8_property (window, "_GTK_THEME_VARIANT",
+ variant ? variant : "");
+}
+
+#define GDK_SELECTION_MAX_SIZE(display) \
+ MIN(262144, \
+ XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0 \
+ ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100 \
+ : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
+
+static void
+gdk_surface_update_icon (GdkSurface *window,
+ GList *icon_list)
+{
+ GdkToplevelX11 *toplevel;
+ GdkTexture *best_icon;
+ GList *tmp_list;
+ int best_size;
+
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+
+ if (toplevel->icon_pixmap != NULL)
+ {
+ cairo_surface_destroy (toplevel->icon_pixmap);
+ toplevel->icon_pixmap = NULL;
+ }
+
+ if (toplevel->icon_mask != NULL)
+ {
+ cairo_surface_destroy (toplevel->icon_mask);
+ toplevel->icon_mask = NULL;
+ }
+
+#define IDEAL_SIZE 48
+
+ best_size = G_MAXINT;
+ best_icon = NULL;
+ for (tmp_list = icon_list; tmp_list; tmp_list = tmp_list->next)
+ {
+ GdkTexture *texture = tmp_list->data;
+ int this;
+
+ /* average width and height - if someone passes in a rectangular
+ * icon they deserve what they get.
+ */
+ this = gdk_texture_get_width (texture) + gdk_texture_get_height (texture);
+ this /= 2;
+
+ if (best_icon == NULL)
+ {
+ best_icon = texture;
+ best_size = this;
+ }
+ else
+ {
+ /* icon is better if it's 32 pixels or larger, and closer to
+ * the ideal size than the current best.
+ */
+ if (this >= 32 &&
+ (ABS (best_size - IDEAL_SIZE) <
+ ABS (this - IDEAL_SIZE)))
+ {
+ best_icon = texture;
+ best_size = this;
+ }
+ }
+ }
+
+ if (best_icon)
+ {
+ int width = gdk_texture_get_width (best_icon);
+ int height = gdk_texture_get_height (best_icon);
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ toplevel->icon_pixmap = gdk_x11_surface_create_pixmap_surface (window, width, height);
+
+ surface = gdk_texture_download_surface (best_icon);
+
+ cr = cairo_create (toplevel->icon_pixmap);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ if (cairo_surface_get_content (surface) == CAIRO_CONTENT_COLOR_ALPHA)
+ {
+ /* Saturate the image, so it has bilevel alpha */
+ cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
+ cairo_paint (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE);
+ cairo_paint (cr);
+ cairo_pop_group_to_source (cr);
+ }
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ if (cairo_surface_get_content (surface) == CAIRO_CONTENT_COLOR_ALPHA)
+ {
+ GdkDisplay *display = gdk_surface_get_display (window);
+
+ toplevel->icon_mask = _gdk_x11_display_create_bitmap_surface (display, width, height);
+
+ cr = cairo_create (toplevel->icon_mask);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+ }
+
+ cairo_surface_destroy (surface);
+ }
+
+ update_wm_hints (window, FALSE);
+}
+
+static void
+gdk_x11_surface_set_icon_list (GdkSurface *window,
+ GList *textures)
+{
+ gulong *data;
+ gulong *p;
+ gint size;
+ GList *l;
+ gint width, height;
+ GdkTexture *texture;
+ GdkDisplay *display;
+ gint i, n;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ display = gdk_surface_get_display (window);
+
+ size = 0;
+ n = 0;
+ for (l = textures; l != NULL; l = l->next)
+ {
+ texture = l->data;
+
+ width = gdk_texture_get_width (texture);
+ height = gdk_texture_get_height (texture);
+
+ /* silently ignore overlarge icons */
+ if (size + 2 + width * height > GDK_SELECTION_MAX_SIZE(display))
+ break;
+
+ n++;
+ size += 2 + width * height;
+ }
+
+ data = g_malloc (size * sizeof (gulong));
+
+ p = data;
+ for (l = textures; l != NULL && n > 0; l = l->next)
+ {
+ texture = l->data;
+
+ width = gdk_texture_get_width (texture);
+ height = gdk_texture_get_height (texture);
+
+ *p++ = width;
+ *p++ = height;
+
+ gdk_texture_download (texture, (guchar *) p, width * 4);
+ if (sizeof (gulong) > 4)
+ {
+ i = width * height;
+ while (i-- > 0)
+ p[i] = ((guint32 *) p)[i];
+ }
+
+ p += width * height;
+ n--;
+ }
+
+ if (size > 0)
+ {
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"),
+ XA_CARDINAL, 32,
+ PropModeReplace,
+ (guchar*) data, size);
+ }
+ else
+ {
+ XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"));
+ }
+
+ g_free (data);
+
+ gdk_surface_update_icon (window, textures);
+}
+
+static gboolean
+gdk_surface_icon_name_set (GdkSurface *window)
+{
+ return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (window),
+ g_quark_from_static_string ("gdk-icon-name-set")));
+}
+
+static void
+gdk_x11_surface_set_icon_name (GdkSurface *window,
+ const gchar *name)
+{
+ GdkDisplay *display;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ display = gdk_surface_get_display (window);
+
+ g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"),
+ GUINT_TO_POINTER (name != NULL));
+
+ if (name != NULL)
+ {
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
+ gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+ PropModeReplace, (guchar *)name, strlen (name));
+
+ set_text_property (display, GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
+ name);
+ }
+ else
+ {
+ XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"));
+ XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"));
+ }
+}
+
+static void
+gdk_x11_surface_iconify (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ XIconifyWindow (GDK_SURFACE_XDISPLAY (window),
+ GDK_SURFACE_XID (window),
+ gdk_x11_screen_get_screen_number (GDK_SURFACE_SCREEN (window)));
+ }
+ else
+ {
+ /* Flip our client side flag, the real work happens on map. */
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_SURFACE_STATE_ICONIFIED);
+ gdk_wmspec_change_state (TRUE, window,
+ g_intern_static_string ("_NET_WM_STATE_HIDDEN"),
+ NULL);
+ }
+}
+
+static void
+gdk_x11_surface_deiconify (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ gdk_surface_show (window);
+ gdk_wmspec_change_state (FALSE, window,
+ g_intern_static_string ("_NET_WM_STATE_HIDDEN"),
+ NULL);
+ }
+ else
+ {
+ /* Flip our client side flag, the real work happens on map. */
+ gdk_synthesize_window_state (window,
+ GDK_SURFACE_STATE_ICONIFIED,
+ 0);
+ gdk_wmspec_change_state (FALSE, window,
+ g_intern_static_string ("_NET_WM_STATE_HIDDEN"),
+ NULL);
+ }
+}
+
+static void
+gdk_x11_surface_stick (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ /* "stick" means stick to all desktops _and_ do not scroll with the
+ * viewport. i.e. glue to the monitor glass in all cases.
+ */
+
+ XClientMessageEvent xclient;
+
+ /* Request stick during viewport scroll */
+ gdk_wmspec_change_state (TRUE, window,
+ g_intern_static_string ("_NET_WM_STATE_STICKY"),
+ NULL);
+
+ /* Request desktop 0xFFFFFFFF */
+ memset (&xclient, 0, sizeof (xclient));
+ xclient.type = ClientMessage;
+ xclient.window = GDK_SURFACE_XID (window);
+ xclient.display = GDK_SURFACE_XDISPLAY (window);
+ xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (window),
+ "_NET_WM_DESKTOP");
+ xclient.format = 32;
+
+ xclient.data.l[0] = 0xFFFFFFFF;
+ xclient.data.l[1] = 0;
+ xclient.data.l[2] = 0;
+ xclient.data.l[3] = 0;
+ xclient.data.l[4] = 0;
+
+ XSendEvent (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XROOTWIN (window), False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ (XEvent *)&xclient);
+ }
+ else
+ {
+ /* Flip our client side flag, the real work happens on map. */
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_SURFACE_STATE_STICKY);
+ }
+}
+
+static void
+gdk_x11_surface_unstick (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ /* Request unstick from viewport */
+ gdk_wmspec_change_state (FALSE, window,
+ g_intern_static_string ("_NET_WM_STATE_STICKY"),
+ NULL);
+
+ move_to_current_desktop (window);
+ }
+ else
+ {
+ /* Flip our client side flag, the real work happens on map. */
+ gdk_synthesize_window_state (window,
+ GDK_SURFACE_STATE_STICKY,
+ 0);
+
+ }
+}
+
+static void
+gdk_x11_surface_maximize (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ gdk_wmspec_change_state (TRUE, window,
+ g_intern_static_string ("_NET_WM_STATE_MAXIMIZED_VERT"),
+ g_intern_static_string ("_NET_WM_STATE_MAXIMIZED_HORZ"));
+ else
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_SURFACE_STATE_MAXIMIZED);
+}
+
+static void
+gdk_x11_surface_unmaximize (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ gdk_wmspec_change_state (FALSE, window,
+ g_intern_static_string ("_NET_WM_STATE_MAXIMIZED_VERT"),
+ g_intern_static_string ("_NET_WM_STATE_MAXIMIZED_HORZ"));
+ else
+ gdk_synthesize_window_state (window,
+ GDK_SURFACE_STATE_MAXIMIZED,
+ 0);
+}
+
+static void
+gdk_x11_surface_apply_fullscreen_mode (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ /* _NET_WM_FULLSCREEN_MONITORS gives an indication to the window manager as
+ * to which monitors so span across when the window is fullscreen, but it's
+ * not a state in itself so this would have no effect if the window is not
+ * mapped.
+ */
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ XClientMessageEvent xclient;
+ gint monitors[4];
+ gint i;
+
+ memset (&xclient, 0, sizeof (xclient));
+ xclient.type = ClientMessage;
+ xclient.window = GDK_SURFACE_XID (window);
+ xclient.display = GDK_SURFACE_XDISPLAY (window);
+ xclient.format = 32;
+
+ switch (window->fullscreen_mode)
+ {
+ case GDK_FULLSCREEN_ON_CURRENT_MONITOR:
+
+ /* FIXME: This is not part of the EWMH spec!
+ *
+ * There is no documented mechanism to remove the property
+ * _NET_WM_FULLSCREEN_MONITORS once set, so we use use a set of
+ * invalid, largest possible value.
+ *
+ * When given values larger than actual possible monitor values, most
+ * window managers who support the _NET_WM_FULLSCREEN_MONITORS spec
+ * will simply unset _NET_WM_FULLSCREEN_MONITORS and revert to their
+ * default behavior.
+ *
+ * Successfully tested on mutter/metacity, kwin, compiz and xfwm4.
+ *
+ * Note, this (non documented) mechanism is unlikely to be an issue
+ * as it's used only for transitionning back from "all monitors" to
+ * "current monitor" mode.
+ *
+ * Applications who don't change the default mode won't trigger this
+ * mechanism.
+ */
+ for (i = 0; i < 4; ++i)
+ xclient.data.l[i] = G_MAXLONG;
+
+ break;
+
+ case GDK_FULLSCREEN_ON_ALL_MONITORS:
+
+ _gdk_x11_screen_get_edge_monitors (GDK_SURFACE_SCREEN (window),
+ &monitors[0],
+ &monitors[1],
+ &monitors[2],
+ &monitors[3]);
+ /* Translate all 4 monitors from the GDK set into XINERAMA indices */
+ for (i = 0; i < 4; ++i)
+ {
+ xclient.data.l[i] = monitors[i];
+ /* Sanity check, if XINERAMA is not available, we could have invalid
+ * negative values for the XINERAMA indices.
+ */
+ if (xclient.data.l[i] < 0)
+ {
+ g_warning ("gdk_x11_surface_apply_fullscreen_mode: Invalid XINERAMA monitor index");
+ return;
+ }
+ }
+ break;
+
+ default:
+ g_warning ("gdk_x11_surface_apply_fullscreen_mode: Unhandled fullscreen mode %d",
+ window->fullscreen_mode);
+ return;
+ }
+
+ /* Send fullscreen monitors client message */
+ xclient.data.l[4] = 1; /* source indication */
+ xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (window),
+ "_NET_WM_FULLSCREEN_MONITORS");
+ XSendEvent (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XROOTWIN (window), False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ (XEvent *)&xclient);
+ }
+}
+
+static void
+gdk_x11_surface_fullscreen (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ gdk_wmspec_change_state (TRUE, window,
+ g_intern_static_string ("_NET_WM_STATE_FULLSCREEN"),
+ NULL);
+ /* Actual XRandR layout may have change since we computed the fullscreen
+ * monitors in GDK_FULLSCREEN_ON_ALL_MONITORS mode.
+ */
+ if (window->fullscreen_mode == GDK_FULLSCREEN_ON_ALL_MONITORS)
+ gdk_x11_surface_apply_fullscreen_mode (window);
+ }
+ else
+ gdk_synthesize_window_state (window,
+ 0,
+ GDK_SURFACE_STATE_FULLSCREEN);
+}
+
+static void
+gdk_x11_surface_fullscreen_on_monitor (GdkSurface *window,
+ GdkMonitor *monitor)
+{
+ GdkRectangle geom;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ gdk_monitor_get_geometry (monitor, &geom);
+ gdk_surface_move (window, geom.x, geom.y);
+
+ gdk_surface_set_fullscreen_mode (window, GDK_FULLSCREEN_ON_CURRENT_MONITOR);
+ gdk_x11_surface_fullscreen (window);
+}
+
+static void
+gdk_x11_surface_unfullscreen (GdkSurface *window)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ gdk_wmspec_change_state (FALSE, window,
+ g_intern_static_string ("_NET_WM_STATE_FULLSCREEN"),
+ NULL);
+
+ else
+ gdk_synthesize_window_state (window,
+ GDK_SURFACE_STATE_FULLSCREEN,
+ 0);
+}
+
+static void
+gdk_x11_surface_set_keep_above (GdkSurface *window,
+ gboolean setting)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ if (setting)
+ gdk_wmspec_change_state (FALSE, window,
+ g_intern_static_string ("_NET_WM_STATE_BELOW"),
+ NULL);
+ gdk_wmspec_change_state (setting, window,
+ g_intern_static_string ("_NET_WM_STATE_ABOVE"),
+ NULL);
+ }
+ else
+ gdk_synthesize_window_state (window,
+ setting ? GDK_SURFACE_STATE_BELOW : GDK_SURFACE_STATE_ABOVE,
+ setting ? GDK_SURFACE_STATE_ABOVE : 0);
+}
+
+static void
+gdk_x11_surface_set_keep_below (GdkSurface *window, gboolean setting)
+{
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ if (GDK_SURFACE_IS_MAPPED (window))
+ {
+ if (setting)
+ gdk_wmspec_change_state (FALSE, window,
+ g_intern_static_string ("_NET_WM_STATE_ABOVE"),
+ NULL);
+ gdk_wmspec_change_state (setting, window,
+ g_intern_static_string ("_NET_WM_STATE_BELOW"),
+ NULL);
+ }
+ else
+ gdk_synthesize_window_state (window,
+ setting ? GDK_SURFACE_STATE_ABOVE : GDK_SURFACE_STATE_BELOW,
+ setting ? GDK_SURFACE_STATE_BELOW : 0);
+}
+
+static GdkSurface *
+gdk_x11_surface_get_group (GdkSurface *window)
+{
+ GdkToplevelX11 *toplevel;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return NULL;
+
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+
+ return toplevel->group_leader;
+}
+
+static void
+gdk_x11_surface_set_group (GdkSurface *window,
+ GdkSurface *leader)
+{
+ GdkToplevelX11 *toplevel;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+ g_return_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD);
+ g_return_if_fail (leader == NULL || GDK_IS_SURFACE (leader));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ (leader != NULL && GDK_SURFACE_DESTROYED (leader)) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ toplevel = _gdk_x11_surface_get_toplevel (window);
+
+ if (leader == NULL)
+ leader = gdk_display_get_default_group (gdk_surface_get_display (window));
+
+ if (toplevel->group_leader != leader)
+ {
+ if (toplevel->group_leader)
+ g_object_unref (toplevel->group_leader);
+ toplevel->group_leader = g_object_ref (leader);
+ (_gdk_x11_surface_get_toplevel (leader))->is_leader = TRUE;
+ }
+
+ update_wm_hints (window, FALSE);
+}
+
+static MotifWmHints *
+gdk_surface_get_mwm_hints (GdkSurface *window)
+{
+ GdkDisplay *display;
+ Atom hints_atom = None;
+ guchar *data;
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return NULL;
+
+ display = gdk_surface_get_display (window);
+
+ hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
+
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
+ hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
+ False, AnyPropertyType, &type, &format, &nitems,
+ &bytes_after, &data);
+
+ if (type == None)
+ return NULL;
+
+ return (MotifWmHints *)data;
+}
+
+static void
+gdk_surface_set_mwm_hints (GdkSurface *window,
+ MotifWmHints *new_hints)
+{
+ GdkDisplay *display;
+ Atom hints_atom = None;
+ guchar *data;
+ MotifWmHints *hints;
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ display = gdk_surface_get_display (window);
+
+ hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
+
+ XGetWindowProperty (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XID (window),
+ hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
+ False, AnyPropertyType, &type, &format, &nitems,
+ &bytes_after, &data);
+
+ if (type == None)
+ hints = new_hints;
+ else
+ {
+ hints = (MotifWmHints *)data;
+
+ if (new_hints->flags & MWM_HINTS_FUNCTIONS)
+ {
+ hints->flags |= MWM_HINTS_FUNCTIONS;
+ hints->functions = new_hints->functions;
+ }
+ if (new_hints->flags & MWM_HINTS_DECORATIONS)
+ {
+ hints->flags |= MWM_HINTS_DECORATIONS;
+ hints->decorations = new_hints->decorations;
+ }
+ }
+
+ XChangeProperty (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XID (window),
+ hints_atom, hints_atom, 32, PropModeReplace,
+ (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
+
+ if (hints != new_hints)
+ XFree (hints);
+}
+
+static void
+gdk_x11_surface_set_decorations (GdkSurface *window,
+ GdkWMDecoration decorations)
+{
+ MotifWmHints hints;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ /* initialize to zero to avoid writing uninitialized data to socket */
+ memset(&hints, 0, sizeof(hints));
+ hints.flags = MWM_HINTS_DECORATIONS;
+ hints.decorations = decorations;
+
+ gdk_surface_set_mwm_hints (window, &hints);
+}
+
+static gboolean
+gdk_x11_surface_get_decorations(GdkSurface *window,
+ GdkWMDecoration *decorations)
+{
+ MotifWmHints *hints;
+ gboolean result = FALSE;
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return FALSE;
+
+ hints = gdk_surface_get_mwm_hints (window);
+
+ if (hints)
+ {
+ if (hints->flags & MWM_HINTS_DECORATIONS)
+ {
+ if (decorations)
+ *decorations = hints->decorations;
+ result = TRUE;
+ }
+
+ XFree (hints);
+ }
+
+ return result;
+}
+
+static void
+gdk_x11_surface_set_functions (GdkSurface *window,
+ GdkWMFunction functions)
+{
+ MotifWmHints hints;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ /* initialize to zero to avoid writing uninitialized data to socket */
+ memset(&hints, 0, sizeof(hints));
+ hints.flags = MWM_HINTS_FUNCTIONS;
+ hints.functions = functions;
+
+ gdk_surface_set_mwm_hints (window, &hints);
+}
+
+cairo_region_t *
+_gdk_x11_xwindow_get_shape (Display *xdisplay,
+ Window window,
+ gint scale,
+ gint shape_type)
+{
+ cairo_region_t *shape;
+ GdkRectangle *rl;
+ XRectangle *xrl;
+ gint rn, ord, i;
+
+ shape = NULL;
+ rn = 0;
+
+ /* 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 (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
+ */
+ g_warning ("non YXBanded shape masks not supported");
+ XFree (xrl);
+ return NULL;
+ }
+
+ /* NOTE: The scale divisions here may lose some precision if someone
+ else set the shape to be non-scale precision */
+ rl = g_new (GdkRectangle, rn);
+ for (i = 0; i < rn; i++)
+ {
+ rl[i].x = xrl[i].x / scale;
+ rl[i].y = xrl[i].y / scale;
+ rl[i].width = xrl[i].width / scale;
+ rl[i].height = xrl[i].height / scale;
+ }
+ XFree (xrl);
+
+ shape = cairo_region_create_rectangles (rl, rn);
+ g_free (rl);
+
+ return shape;
+}
+
+/* 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_send_message (GdkDisplay *display,
+ GdkSurface *window,
+ gint root_x,
+ gint root_y,
+ gint action,
+ gint button)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+ XClientMessageEvent xclient;
+
+ memset (&xclient, 0, sizeof (xclient));
+ xclient.type = ClientMessage;
+ xclient.window = GDK_SURFACE_XID (window);
+ xclient.message_type =
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_MOVERESIZE");
+ xclient.format = 32;
+ xclient.data.l[0] = root_x * impl->window_scale;
+ xclient.data.l[1] = root_y * impl->window_scale;
+ xclient.data.l[2] = action;
+ xclient.data.l[3] = button;
+ xclient.data.l[4] = 1; /* source indication */
+
+ XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XROOTWIN (window), False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ (XEvent *)&xclient);
+}
+
+static void
+handle_wmspec_button_release (GdkDisplay *display,
+ const XEvent *xevent)
+{
+ GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+ GdkSurface *window;
+
+#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_surface_lookup_for_display (display, xidev->event);
+ else
+#endif
+ window = gdk_x11_surface_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);
+ }
+ }
+}
+
+static void
+wmspec_moveresize (GdkSurface *window,
+ gint direction,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
+
+ if (button != 0)
+ gdk_seat_ungrab (gdk_device_get_seat (device)); /* Release passive grab */
+ GDK_X11_DISPLAY (display)->wm_moveresize_button = button;
+
+ wmspec_send_message (display, window, root_x, root_y, direction, button);
+}
+
+static void
+wmspec_resize_drag (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ gint direction;
+
+ if (button == 0)
+ direction = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
+ else
+ switch (edge)
+ {
+ /* Let the compiler turn a switch into a table, instead
+ * of doing the table manually, this way is easier to verify.
+ */
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
+ break;
+
+ case GDK_SURFACE_EDGE_NORTH:
+ direction = _NET_WM_MOVERESIZE_SIZE_TOP;
+ break;
+
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
+ break;
+
+ case GDK_SURFACE_EDGE_WEST:
+ direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
+ break;
+
+ case GDK_SURFACE_EDGE_EAST:
+ direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
+ break;
+
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
+ break;
+
+ case GDK_SURFACE_EDGE_SOUTH:
+ direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
+ break;
+
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
+ break;
+
+ default:
+ g_warning ("gdk_surface_begin_resize_drag: bad resize edge %d!",
+ edge);
+ return;
+ }
+
+ wmspec_moveresize (window, direction, device, button, root_x, root_y, timestamp);
+}
+
+typedef struct _MoveResizeData MoveResizeData;
+
+struct _MoveResizeData
+{
+ GdkDisplay *display;
+
+ GdkSurface *moveresize_window;
+ GdkSurface *moveresize_emulation_window;
+ gboolean is_resize;
+ GdkSurfaceEdge 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;
+ GdkSurfaceHints moveresize_geom_mask;
+ GdkGeometry moveresize_geometry;
+ Time moveresize_process_time;
+ XEvent *moveresize_pending_event;
+};
+
+static MoveResizeData *
+get_move_resize_data (GdkDisplay *display,
+ gboolean create)
+{
+ MoveResizeData *mv_resize;
+ static GQuark move_resize_quark = 0;
+
+ if (!move_resize_quark)
+ move_resize_quark = g_quark_from_static_string ("gdk-window-moveresize");
+
+ mv_resize = g_object_get_qdata (G_OBJECT (display), move_resize_quark);
+
+ if (!mv_resize && create)
+ {
+ mv_resize = g_new0 (MoveResizeData, 1);
+ mv_resize->display = display;
+
+ g_object_set_qdata (G_OBJECT (display), move_resize_quark, mv_resize);
+ }
+
+ return mv_resize;
+}
+
+static void
+check_maximize (MoveResizeData *mv_resize,
+ gdouble x_root,
+ gdouble y_root)
+{
+ GdkSurfaceState state;
+ gint y;
+
+ if (mv_resize->is_resize)
+ return;
+
+ state = gdk_surface_get_state (mv_resize->moveresize_window);
+
+ if (state & GDK_SURFACE_STATE_MAXIMIZED)
+ return;
+
+ y = mv_resize->moveresize_orig_y + (y_root - mv_resize->moveresize_y);
+
+ if (y < 10)
+ gdk_surface_maximize (mv_resize->moveresize_window);
+}
+
+static void
+check_unmaximize (MoveResizeData *mv_resize,
+ gdouble x_root,
+ gdouble y_root)
+{
+ GdkSurfaceState state;
+ gint dx, dy;
+
+ if (mv_resize->is_resize)
+ return;
+
+ state = gdk_surface_get_state (mv_resize->moveresize_window);
+
+ if ((state & (GDK_SURFACE_STATE_MAXIMIZED | GDK_SURFACE_STATE_TILED)) == 0)
+ return;
+
+ dx = x_root - mv_resize->moveresize_x;
+ dy = y_root - mv_resize->moveresize_y;
+
+ if (ABS (dx) > 20 || ABS (dy) > 20)
+ gdk_surface_unmaximize (mv_resize->moveresize_window);
+}
+
+static void
+update_pos (MoveResizeData *mv_resize,
+ gint new_root_x,
+ gint new_root_y)
+{
+ gint dx, dy;
+
+ check_unmaximize (mv_resize, new_root_x, new_root_y);
+ dx = new_root_x - mv_resize->moveresize_x;
+ dy = new_root_y - mv_resize->moveresize_y;
+
+ if (mv_resize->is_resize)
+ {
+ gint x, y, w, h;
+
+ x = mv_resize->moveresize_orig_x;
+ y = mv_resize->moveresize_orig_y;
+
+ w = mv_resize->moveresize_orig_width;
+ h = mv_resize->moveresize_orig_height;
+
+ switch (mv_resize->resize_edge)
+ {
+ case GDK_SURFACE_EDGE_NORTH_WEST:
+ x += dx;
+ y += dy;
+ w -= dx;
+ h -= dy;
+ break;
+ case GDK_SURFACE_EDGE_NORTH:
+ y += dy;
+ h -= dy;
+ break;
+ case GDK_SURFACE_EDGE_NORTH_EAST:
+ y += dy;
+ h -= dy;
+ w += dx;
+ break;
+ case GDK_SURFACE_EDGE_SOUTH_WEST:
+ h += dy;
+ x += dx;
+ w -= dx;
+ break;
+ case GDK_SURFACE_EDGE_SOUTH_EAST:
+ w += dx;
+ h += dy;
+ break;
+ case GDK_SURFACE_EDGE_SOUTH:
+ h += dy;
+ break;
+ case GDK_SURFACE_EDGE_EAST:
+ w += dx;
+ break;
+ case GDK_SURFACE_EDGE_WEST:
+ x += dx;
+ w -= dx;
+ break;
+ default:
+ break;
+ }
+
+ x = MAX (x, 0);
+ y = MAX (y, 0);
+ w = MAX (w, 1);
+ h = MAX (h, 1);
+
+ if (mv_resize->moveresize_geom_mask)
+ {
+ gdk_surface_constrain_size (&mv_resize->moveresize_geometry,
+ mv_resize->moveresize_geom_mask,
+ w, h, &w, &h);
+ }
+
+ gdk_surface_move_resize (mv_resize->moveresize_window, x, y, w, h);
+ }
+ else
+ {
+ gint x, y;
+
+ x = mv_resize->moveresize_orig_x + dx;
+ y = mv_resize->moveresize_orig_y + dy;
+
+ gdk_surface_move (mv_resize->moveresize_window, x, y);
+ }
+}
+
+static void
+finish_drag (MoveResizeData *mv_resize)
+{
+ gdk_surface_destroy (mv_resize->moveresize_emulation_window);
+ mv_resize->moveresize_emulation_window = NULL;
+ g_clear_object (&mv_resize->moveresize_window);
+ g_clear_pointer (&mv_resize->moveresize_pending_event, g_free);
+}
+
+static int
+lookahead_motion_predicate (Display *xdisplay,
+ XEvent *event,
+ XPointer arg)
+{
+ gboolean *seen_release = (gboolean *)arg;
+ GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
+ MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
+
+ if (*seen_release)
+ return False;
+
+ switch (event->xany.type)
+ {
+ case ButtonRelease:
+ *seen_release = TRUE;
+ break;
+ case MotionNotify:
+ mv_resize->moveresize_process_time = event->xmotion.time;
+ break;
+ default:
+ break;
+ }
+
+ return False;
+}
+
+static gboolean
+moveresize_lookahead (MoveResizeData *mv_resize,
+ const XEvent *event)
+{
+ XEvent tmp_event;
+ gboolean seen_release = FALSE;
+
+ if (mv_resize->moveresize_process_time)
+ {
+ if (event->xmotion.time == mv_resize->moveresize_process_time)
+ {
+ mv_resize->moveresize_process_time = 0;
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+
+ XCheckIfEvent (event->xany.display, &tmp_event,
+ lookahead_motion_predicate, (XPointer) & seen_release);
+
+ return mv_resize->moveresize_process_time == 0;
+}
+
+gboolean
+_gdk_x11_moveresize_handle_event (const XEvent *event)
+{
+ guint button_mask = 0;
+ GdkDisplay *display = gdk_x11_lookup_xdisplay (event->xany.display);
+ MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
+ GdkSurfaceImplX11 *impl;
+
+ if (!mv_resize || !mv_resize->moveresize_window)
+ {
+ handle_wmspec_button_release (display, event);
+ return FALSE;
+ }
+
+ impl = GDK_SURFACE_IMPL_X11 (mv_resize->moveresize_window->impl);
+
+ if (mv_resize->moveresize_button != 0)
+ button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1);
+
+ switch (event->xany.type)
+ {
+ case MotionNotify:
+ if (mv_resize->moveresize_window->resize_count > 0)
+ {
+ if (mv_resize->moveresize_pending_event)
+ *mv_resize->moveresize_pending_event = *event;
+ else
+ mv_resize->moveresize_pending_event =
+ g_memdup (event, sizeof (XEvent));
+
+ break;
+ }
+ if (!moveresize_lookahead (mv_resize, event))
+ break;
+
+ update_pos (mv_resize,
+ event->xmotion.x_root / impl->window_scale,
+ event->xmotion.y_root / impl->window_scale);
+
+ /* This should never be triggered in normal cases, but in the
+ * case where the drag started without an implicit grab being
+ * in effect, we could miss the release if it occurs before
+ * we grab the pointer; this ensures that we will never
+ * get a permanently stuck grab.
+ */
+ if ((event->xmotion.state & button_mask) == 0)
+ {
+ check_maximize (mv_resize,
+ event->xmotion.x_root / impl->window_scale,
+ event->xmotion.y_root / impl->window_scale);
+ finish_drag (mv_resize);
+ }
+ break;
+
+ case ButtonRelease:
+ update_pos (mv_resize,
+ event->xbutton.x_root / impl->window_scale,
+ event->xbutton.y_root / impl->window_scale);
+
+ if (event->xbutton.button == mv_resize->moveresize_button)
+ {
+ check_maximize (mv_resize,
+ event->xmotion.x_root / impl->window_scale,
+ event->xmotion.y_root / impl->window_scale);
+ 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 / impl->window_scale, xev->root_y / impl->window_scale);
+ state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
+ if ((state & button_mask) == 0)
+ {
+ check_maximize (mv_resize,
+ xev->root_x / impl->window_scale,
+ xev->root_y / impl->window_scale);
+ finish_drag (mv_resize);
+ }
+ break;
+
+ case XI_ButtonRelease:
+ update_pos (mv_resize, xev->root_x / impl->window_scale, xev->root_y / impl->window_scale);
+ if (xev->detail == mv_resize->moveresize_button)
+ {
+ check_maximize (mv_resize,
+ xev->root_x / impl->window_scale,
+ xev->root_y / impl->window_scale);
+ finish_drag (mv_resize);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+#endif
+
+ default:
+ break;
+
+ }
+ return TRUE;
+}
+
+gboolean
+_gdk_x11_moveresize_configure_done (GdkDisplay *display,
+ GdkSurface *window)
+{
+ XEvent *tmp_event;
+ MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
+
+ if (!mv_resize || window != mv_resize->moveresize_window)
+ return FALSE;
+
+ if (mv_resize->moveresize_pending_event)
+ {
+ tmp_event = mv_resize->moveresize_pending_event;
+ mv_resize->moveresize_pending_event = NULL;
+ _gdk_x11_moveresize_handle_event (tmp_event);
+ g_free (tmp_event);
+ }
+
+ return TRUE;
+}
+
+static void
+create_moveresize_window (MoveResizeData *mv_resize,
+ guint32 timestamp)
+{
+ GdkGrabStatus status;
+
+ g_assert (mv_resize->moveresize_emulation_window == NULL);
+
+ mv_resize->moveresize_emulation_window = gdk_surface_new_temp (mv_resize->display);
+ gdk_surface_show (mv_resize->moveresize_emulation_window);
+
+ status = gdk_seat_grab (gdk_device_get_seat (mv_resize->device),
+ mv_resize->moveresize_emulation_window,
+ GDK_SEAT_CAPABILITY_POINTER, FALSE,
+ NULL, NULL, NULL, NULL);
+
+ if (status != GDK_GRAB_SUCCESS)
+ {
+ /* If this fails, some other client has grabbed the window
+ * already.
+ */
+ finish_drag (mv_resize);
+ }
+
+ mv_resize->moveresize_process_time = 0;
+}
+
+/*
+ Calculate mv_resize->moveresize_orig_x and mv_resize->moveresize_orig_y
+ so that calling XMoveWindow with these coordinates will not move the
+ window.
+ Note that this depends on the WM to implement ICCCM-compliant reference
+ point handling.
+*/
+static void
+calculate_unmoving_origin (MoveResizeData *mv_resize)
+{
+ GdkRectangle rect;
+ gint width, height;
+
+ if (mv_resize->moveresize_geom_mask & GDK_HINT_WIN_GRAVITY &&
+ mv_resize->moveresize_geometry.win_gravity == GDK_GRAVITY_STATIC)
+ {
+ gdk_surface_get_origin (mv_resize->moveresize_window,
+ &mv_resize->moveresize_orig_x,
+ &mv_resize->moveresize_orig_y);
+ }
+ else
+ {
+ gdk_surface_get_frame_extents (mv_resize->moveresize_window, &rect);
+ gdk_surface_get_geometry (mv_resize->moveresize_window,
+ NULL, NULL, &width, &height);
+
+ switch (mv_resize->moveresize_geometry.win_gravity)
+ {
+ case GDK_GRAVITY_NORTH_WEST:
+ mv_resize->moveresize_orig_x = rect.x;
+ mv_resize->moveresize_orig_y = rect.y;
+ break;
+ case GDK_GRAVITY_NORTH:
+ mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
+ mv_resize->moveresize_orig_y = rect.y;
+ break;
+ case GDK_GRAVITY_NORTH_EAST:
+ mv_resize->moveresize_orig_x = rect.x + rect.width - width;
+ mv_resize->moveresize_orig_y = rect.y;
+ break;
+ case GDK_GRAVITY_WEST:
+ mv_resize->moveresize_orig_x = rect.x;
+ mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
+ break;
+ case GDK_GRAVITY_CENTER:
+ mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
+ mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
+ break;
+ case GDK_GRAVITY_EAST:
+ mv_resize->moveresize_orig_x = rect.x + rect.width - width;
+ mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
+ break;
+ case GDK_GRAVITY_SOUTH_WEST:
+ mv_resize->moveresize_orig_x = rect.x;
+ mv_resize->moveresize_orig_y = rect.y + rect.height - height;
+ break;
+ case GDK_GRAVITY_SOUTH:
+ mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
+ mv_resize->moveresize_orig_y = rect.y + rect.height - height;
+ break;
+ case GDK_GRAVITY_SOUTH_EAST:
+ mv_resize->moveresize_orig_x = rect.x + rect.width - width;
+ mv_resize->moveresize_orig_y = rect.y + rect.height - height;
+ break;
+ case GDK_GRAVITY_STATIC:
+ default:
+ mv_resize->moveresize_orig_x = rect.x;
+ mv_resize->moveresize_orig_y = rect.y;
+ break;
+ }
+ }
+}
+
+static void
+emulate_resize_drag (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ MoveResizeData *mv_resize = get_move_resize_data (GDK_SURFACE_DISPLAY (window), TRUE);
+
+ if (mv_resize->moveresize_window != NULL)
+ return; /* already a drag operation in progress */
+
+ mv_resize->is_resize = TRUE;
+ mv_resize->moveresize_button = button;
+ mv_resize->resize_edge = edge;
+ mv_resize->device = device;
+ mv_resize->moveresize_x = root_x;
+ mv_resize->moveresize_y = root_y;
+ mv_resize->moveresize_window = g_object_ref (window);
+
+ mv_resize->moveresize_orig_width = gdk_surface_get_width (window);
+ mv_resize->moveresize_orig_height = gdk_surface_get_height (window);
+
+ mv_resize->moveresize_geom_mask = 0;
+ gdk_surface_get_geometry_hints (window,
+ &mv_resize->moveresize_geometry,
+ &mv_resize->moveresize_geom_mask);
+
+ calculate_unmoving_origin (mv_resize);
+
+ create_moveresize_window (mv_resize, timestamp);
+}
+
+static void
+emulate_move_drag (GdkSurface *window,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ MoveResizeData *mv_resize = get_move_resize_data (GDK_SURFACE_DISPLAY (window), TRUE);
+
+ if (mv_resize->moveresize_window != NULL)
+ return; /* already a drag operation in progress */
+
+ mv_resize->is_resize = FALSE;
+ mv_resize->device = device;
+ mv_resize->moveresize_button = button;
+ mv_resize->moveresize_x = root_x;
+ mv_resize->moveresize_y = root_y;
+
+ mv_resize->moveresize_window = g_object_ref (window);
+
+ calculate_unmoving_origin (mv_resize);
+
+ create_moveresize_window (mv_resize, timestamp);
+}
+
+static gboolean
+_should_perform_ewmh_drag (GdkSurface *window,
+ GdkDevice *device)
+{
+ GdkPointerSurfaceInfo *info;
+ GdkDisplay *display;
+
+ display = gdk_surface_get_display (window);
+ info = _gdk_display_get_pointer_info (display, device);
+
+ if ((!info->last_slave || gdk_device_get_source (info->last_slave) != GDK_SOURCE_TOUCHSCREEN) &&
+ gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
+ g_intern_static_string ("_NET_WM_MOVERESIZE")))
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+gdk_x11_surface_begin_resize_drag (GdkSurface *window,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
+ return;
+
+ /* Avoid EWMH for touch devices */
+ if (_should_perform_ewmh_drag (window, device))
+ wmspec_resize_drag (window, edge, device, button, root_x, root_y, timestamp);
+ else
+ emulate_resize_drag (window, edge, device, button, root_x, root_y, timestamp);
+}
+
+static void
+gdk_x11_surface_begin_move_drag (GdkSurface *window,
+ GdkDevice *device,
+ gint button,
+ gint root_x,
+ gint root_y,
+ guint32 timestamp)
+{
+ gint direction;
+
+ if (GDK_SURFACE_DESTROYED (window) || !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ if (button == 0)
+ direction = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
+ else
+ direction = _NET_WM_MOVERESIZE_MOVE;
+
+ /* Avoid EWMH for touch devices */
+ if (_should_perform_ewmh_drag (window, device))
+ wmspec_moveresize (window, direction, device, button, root_x, root_y, timestamp);
+ else
+ emulate_move_drag (window, device, button, root_x, root_y, timestamp);
+}
+
+static gboolean
+gdk_x11_surface_beep (GdkSurface *window)
+{
+ GdkDisplay *display;
+
+ display = GDK_SURFACE_DISPLAY (window);
+
+#ifdef HAVE_XKB
+ if (GDK_X11_DISPLAY (display)->use_xkb)
+ {
+ XkbBell (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SURFACE_XID (window),
+ 0,
+ None);
+ return TRUE;
+ }
+#endif
+
+ return FALSE;
+}
+
+static void
+gdk_x11_surface_set_opacity (GdkSurface *window,
+ gdouble opacity)
+{
+ GdkDisplay *display;
+ gulong cardinal;
+
+ g_return_if_fail (GDK_IS_SURFACE (window));
+
+ if (GDK_SURFACE_DESTROYED (window) ||
+ !WINDOW_IS_TOPLEVEL (window))
+ return;
+
+ display = gdk_surface_get_display (window);
+
+ if (opacity < 0)
+ opacity = 0;
+ else if (opacity > 1)
+ opacity = 1;
+
+ cardinal = opacity * 0xffffffff;
+
+ if (cardinal == 0xffffffff)
+ XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_OPACITY"));
+ else
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_OPACITY"),
+ XA_CARDINAL, 32,
+ PropModeReplace,
+ (guchar *) &cardinal, 1);
+}
+
+static Bool
+timestamp_predicate (Display *display,
+ XEvent *xevent,
+ XPointer arg)
+{
+ Window xwindow = GPOINTER_TO_UINT (arg);
+ GdkDisplay *gdk_display = gdk_x11_lookup_xdisplay (display);
+
+ if (xevent->type == PropertyNotify &&
+ xevent->xproperty.window == xwindow &&
+ xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (gdk_display,
+ "GDK_TIMESTAMP_PROP"))
+ return True;
+
+ return False;
+}
+
+/**
+ * gdk_x11_get_server_time:
+ * @window: (type GdkX11Surface): a #GdkSurface, used for communication
+ * with the server. The window must have
+ * GDK_PROPERTY_CHANGE_MASK in its events mask or a hang will
+ * result.
+ *
+ * Routine to get the current X server time stamp.
+ *
+ * Returns: the time stamp.
+ **/
+guint32
+gdk_x11_get_server_time (GdkSurface *window)
+{
+ Display *xdisplay;
+ Window xwindow;
+ guchar c = 'a';
+ XEvent xevent;
+ Atom timestamp_prop_atom;
+
+ g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
+ g_return_val_if_fail (!GDK_SURFACE_DESTROYED (window), 0);
+
+ xdisplay = GDK_SURFACE_XDISPLAY (window);
+ xwindow = GDK_SURFACE_XID (window);
+ timestamp_prop_atom =
+ gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (window),
+ "GDK_TIMESTAMP_PROP");
+
+ XChangeProperty (xdisplay, xwindow, timestamp_prop_atom,
+ timestamp_prop_atom,
+ 8, PropModeReplace, &c, 1);
+
+ XIfEvent (xdisplay, &xevent,
+ timestamp_predicate, GUINT_TO_POINTER(xwindow));
+
+ return xevent.xproperty.time;
+}
+
+/**
+ * gdk_x11_surface_get_xid:
+ * @window: (type GdkX11Surface): a native #GdkSurface.
+ *
+ * Returns the X resource (window) belonging to a #GdkSurface.
+ *
+ * Returns: the ID of @drawable’s X resource.
+ **/
+XID
+gdk_x11_surface_get_xid (GdkSurface *window)
+{
+ if (!GDK_SURFACE_IS_X11 (window) ||
+ !_gdk_surface_has_impl (window))
+ {
+ g_warning (G_STRLOC " drawable is not a native X11 window");
+ return None;
+ }
+
+ return GDK_SURFACE_IMPL_X11 (window->impl)->xid;
+}
+
+static gint
+gdk_x11_surface_get_scale_factor (GdkSurface *window)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return 1;
+
+ return impl->window_scale;
+}
+
+/**
+ * gdk_x11_surface_set_frame_sync_enabled:
+ * @window: (type GdkX11Surface): a native #GdkSurface
+ * @frame_sync_enabled: whether frame-synchronization should be enabled
+ *
+ * This function can be used to disable frame synchronization for a window.
+ * Normally frame synchronziation will be enabled or disabled based on whether
+ * the system has a compositor that supports frame synchronization, but if
+ * the window is not directly managed by the window manager, then frame
+ * synchronziation may need to be disabled. This is the case for a window
+ * embedded via the XEMBED protocol.
+ */
+void
+gdk_x11_surface_set_frame_sync_enabled (GdkSurface *window,
+ gboolean frame_sync_enabled)
+{
+ if (!GDK_SURFACE_IS_X11 (window) ||
+ !_gdk_surface_has_impl (window))
+ {
+ g_warning (G_STRLOC " drawable is not a native X11 window");
+ return;
+ }
+
+ GDK_SURFACE_IMPL_X11 (window->impl)->frame_sync_enabled = FALSE;
+}
+
+static void
+gdk_x11_surface_set_opaque_region (GdkSurface *window,
+ cairo_region_t *region)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+ GdkDisplay *display;
+ int nitems;
+ gulong *data;
+
+ if (GDK_SURFACE_DESTROYED (window))
+ return;
+
+ if (region != NULL)
+ {
+ int i, nrects;
+
+ nrects = cairo_region_num_rectangles (region);
+ nitems = nrects * 4;
+ data = g_new (gulong, nitems);
+
+ for (i = 0; i < nrects; i++)
+ {
+ cairo_rectangle_int_t rect;
+ cairo_region_get_rectangle (region, i, &rect);
+ data[i*4+0] = rect.x * impl->window_scale;
+ data[i*4+1] = rect.y * impl->window_scale;
+ data[i*4+2] = rect.width * impl->window_scale;
+ data[i*4+3] = rect.height * impl->window_scale;
+ }
+ }
+ else
+ {
+ nitems = 0;
+ data = NULL;
+ }
+
+ display = gdk_surface_get_display (window);
+
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_SURFACE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_OPAQUE_REGION"),
+ XA_CARDINAL, 32, PropModeReplace,
+ (guchar *) data, nitems);
+
+ g_free (data);
+}
+
+static gboolean
+gdk_x11_surface_show_window_menu (GdkSurface *window,
+ GdkEvent *event)
+{
+ GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
+ GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
+ GdkDevice *device;
+ int device_id;
+ double x_root, y_root;
+ XClientMessageEvent xclient = { 0 };
+
+ switch ((guint) event->any.type)
+ {
+ case GDK_BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (!gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
+ g_intern_static_string ("_GTK_SHOW_WINDOW_MENU")))
+ return FALSE;
+
+ gdk_event_get_root_coords (event, &x_root, &y_root);
+ device = gdk_event_get_device (event);
+ g_object_get (G_OBJECT (device),
+ "device-id", &device_id,
+ NULL);
+
+ /* Ungrab the implicit grab */
+ gdk_seat_ungrab (gdk_device_get_seat (device));
+
+ xclient.type = ClientMessage;
+ xclient.window = GDK_SURFACE_XID (window);
+ xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_GTK_SHOW_WINDOW_MENU");
+ xclient.data.l[0] = device_id;
+ xclient.data.l[1] = x_root * impl->window_scale;
+ xclient.data.l[2] = y_root * impl->window_scale;
+ xclient.format = 32;
+
+ XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XROOTWIN (window), False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ (XEvent *)&xclient);
+
+ return TRUE;
+}
+
+static void
+gdk_surface_impl_x11_class_init (GdkSurfaceImplX11Class *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_CLASS (klass);
+
+ object_class->finalize = gdk_surface_impl_x11_finalize;
+
+ impl_class->ref_cairo_surface = gdk_x11_ref_cairo_surface;
+ impl_class->show = gdk_surface_x11_show;
+ impl_class->hide = gdk_surface_x11_hide;
+ impl_class->withdraw = gdk_surface_x11_withdraw;
+ impl_class->set_events = gdk_surface_x11_set_events;
+ impl_class->get_events = gdk_surface_x11_get_events;
+ impl_class->raise = gdk_surface_x11_raise;
+ impl_class->lower = gdk_surface_x11_lower;
+ impl_class->restack_toplevel = gdk_surface_x11_restack_toplevel;
+ impl_class->move_resize = gdk_surface_x11_move_resize;
+ impl_class->get_geometry = gdk_surface_x11_get_geometry;
+ impl_class->get_root_coords = gdk_surface_x11_get_root_coords;
+ impl_class->get_device_state = gdk_surface_x11_get_device_state;
+ impl_class->shape_combine_region = gdk_surface_x11_shape_combine_region;
+ impl_class->input_shape_combine_region = gdk_surface_x11_input_shape_combine_region;
+ impl_class->queue_antiexpose = _gdk_x11_surface_queue_antiexpose;
+ impl_class->destroy = gdk_x11_surface_destroy;
+ impl_class->beep = gdk_x11_surface_beep;
+
+ impl_class->focus = gdk_x11_surface_focus;
+ impl_class->set_type_hint = gdk_x11_surface_set_type_hint;
+ impl_class->get_type_hint = gdk_x11_surface_get_type_hint;
+ impl_class->set_modal_hint = gdk_x11_surface_set_modal_hint;
+ impl_class->set_skip_taskbar_hint = gdk_x11_surface_set_skip_taskbar_hint;
+ impl_class->set_skip_pager_hint = gdk_x11_surface_set_skip_pager_hint;
+ impl_class->set_urgency_hint = gdk_x11_surface_set_urgency_hint;
+ impl_class->set_geometry_hints = gdk_x11_surface_set_geometry_hints;
+ impl_class->set_title = gdk_x11_surface_set_title;
+ impl_class->set_role = gdk_x11_surface_set_role;
+ impl_class->set_startup_id = gdk_x11_surface_set_startup_id;
+ impl_class->set_transient_for = gdk_x11_surface_set_transient_for;
+ impl_class->get_frame_extents = gdk_x11_surface_get_frame_extents;
+ impl_class->set_accept_focus = gdk_x11_surface_set_accept_focus;
+ impl_class->set_focus_on_map = gdk_x11_surface_set_focus_on_map;
+ impl_class->set_icon_list = gdk_x11_surface_set_icon_list;
+ impl_class->set_icon_name = gdk_x11_surface_set_icon_name;
+ impl_class->iconify = gdk_x11_surface_iconify;
+ impl_class->deiconify = gdk_x11_surface_deiconify;
+ impl_class->stick = gdk_x11_surface_stick;
+ impl_class->unstick = gdk_x11_surface_unstick;
+ impl_class->maximize = gdk_x11_surface_maximize;
+ impl_class->unmaximize = gdk_x11_surface_unmaximize;
+ impl_class->fullscreen = gdk_x11_surface_fullscreen;
+ impl_class->fullscreen_on_monitor = gdk_x11_surface_fullscreen_on_monitor;
+ impl_class->apply_fullscreen_mode = gdk_x11_surface_apply_fullscreen_mode;
+ impl_class->unfullscreen = gdk_x11_surface_unfullscreen;
+ impl_class->set_keep_above = gdk_x11_surface_set_keep_above;
+ impl_class->set_keep_below = gdk_x11_surface_set_keep_below;
+ impl_class->get_group = gdk_x11_surface_get_group;
+ impl_class->set_group = gdk_x11_surface_set_group;
+ impl_class->set_decorations = gdk_x11_surface_set_decorations;
+ impl_class->get_decorations = gdk_x11_surface_get_decorations;
+ impl_class->set_functions = gdk_x11_surface_set_functions;
+ impl_class->begin_resize_drag = gdk_x11_surface_begin_resize_drag;
+ impl_class->begin_move_drag = gdk_x11_surface_begin_move_drag;
+ impl_class->set_opacity = gdk_x11_surface_set_opacity;
+ impl_class->destroy_notify = gdk_x11_surface_destroy_notify;
+ impl_class->register_dnd = _gdk_x11_surface_register_dnd;
+ impl_class->drag_begin = _gdk_x11_surface_drag_begin;
+ impl_class->get_scale_factor = gdk_x11_surface_get_scale_factor;
+ impl_class->set_opaque_region = gdk_x11_surface_set_opaque_region;
+ impl_class->set_shadow_width = gdk_x11_surface_set_shadow_width;
+ impl_class->show_window_menu = gdk_x11_surface_show_window_menu;
+ impl_class->create_gl_context = gdk_x11_surface_create_gl_context;
+ impl_class->get_unscaled_size = gdk_x11_surface_get_unscaled_size;
+ impl_class->supports_edge_constraints = gdk_x11_surface_supports_edge_constraints;
+}
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GDK_SURFACE_X11_H__
+#define __GDK_SURFACE_X11_H__
+
+#include "gdk/x11/gdkprivate-x11.h"
+#include "gdk/gdksurfaceimpl.h"
+
+#include <X11/Xlib.h>
+
+#ifdef HAVE_XDAMAGE
+#include <X11/extensions/Xdamage.h>
+#endif
+
+#ifdef HAVE_XSYNC
+#include <X11/Xlib.h>
+#include <X11/extensions/sync.h>
+#endif
+
+G_BEGIN_DECLS
+
+typedef struct _GdkToplevelX11 GdkToplevelX11;
+typedef struct _GdkSurfaceImplX11 GdkSurfaceImplX11;
+typedef struct _GdkSurfaceImplX11Class GdkSurfaceImplX11Class;
+typedef struct _GdkXPositionInfo GdkXPositionInfo;
+
+/* Window implementation for X11
+ */
+
+#define GDK_TYPE_SURFACE_IMPL_X11 (gdk_surface_impl_x11_get_type ())
+#define GDK_SURFACE_IMPL_X11(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL_X11, GdkSurfaceImplX11))
+#define GDK_SURFACE_IMPL_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL_X11, GdkSurfaceImplX11Class))
+#define GDK_IS_SURFACE_IMPL_X11(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL_X11))
+#define GDK_IS_SURFACE_IMPL_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL_X11))
+#define GDK_SURFACE_IMPL_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL_X11, GdkSurfaceImplX11Class))
+
+struct _GdkSurfaceImplX11
+{
+ GdkSurfaceImpl parent_instance;
+
+ GdkSurface *wrapper;
+
+ Window xid;
+
+ GdkToplevelX11 *toplevel; /* Toplevel-specific information */
+ GdkCursor *cursor;
+
+ guint no_bg : 1; /* Set when the window background is temporarily
+ * unset during resizing and scaling */
+ guint override_redirect : 1;
+ guint frame_clock_connected : 1;
+ guint frame_sync_enabled : 1;
+ guint tracking_damage: 1;
+
+ gint window_scale;
+
+ /* Width and height not divided by window_scale - this matters in the
+ * corner-case where the window manager assigns us a size that isn't
+ * a multiple of window_scale - for example for a maximized window
+ * with an odd-sized title-bar.
+ */
+ gint unscaled_width;
+ gint unscaled_height;
+
+ cairo_surface_t *cairo_surface;
+
+#if defined (HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
+ Damage damage;
+#endif
+};
+
+struct _GdkSurfaceImplX11Class
+{
+ GdkSurfaceImplClass parent_class;
+};
+
+struct _GdkToplevelX11
+{
+
+ /* Set if the window, or any descendent of it, is the server's focus window
+ */
+ guint has_focus_window : 1;
+
+ /* Set if window->has_focus_window and the focus isn't grabbed elsewhere.
+ */
+ guint has_focus : 1;
+
+ /* Set if the pointer is inside this window. (This is needed for
+ * for focus tracking)
+ */
+ guint has_pointer : 1;
+
+ /* Set if the window is a descendent of the focus window and the pointer is
+ * inside it. (This is the case where the window will receive keystroke
+ * events even window->has_focus_window is FALSE)
+ */
+ guint has_pointer_focus : 1;
+
+ /* Set if we are requesting these hints */
+ guint skip_taskbar_hint : 1;
+ guint skip_pager_hint : 1;
+ guint urgency_hint : 1;
+
+ guint on_all_desktops : 1; /* _NET_WM_STICKY == 0xFFFFFFFF */
+
+ guint have_sticky : 1; /* _NET_WM_STATE_STICKY */
+ guint have_maxvert : 1; /* _NET_WM_STATE_MAXIMIZED_VERT */
+ guint have_maxhorz : 1; /* _NET_WM_STATE_MAXIMIZED_HORZ */
+ guint have_fullscreen : 1; /* _NET_WM_STATE_FULLSCREEN */
+ guint have_hidden : 1; /* _NET_WM_STATE_HIDDEN */
+
+ guint is_leader : 1;
+
+ /* Set if the WM is presenting us as focused, i.e. with active decorations
+ */
+ guint have_focused : 1;
+
+ guint in_frame : 1;
+
+ /* If we're expecting a response from the compositor after painting a frame */
+ guint frame_pending : 1;
+
+ /* Whether pending_counter_value/configure_counter_value are updates
+ * to the extended update counter */
+ guint pending_counter_value_is_extended : 1;
+ guint configure_counter_value_is_extended : 1;
+
+ gulong map_serial; /* Serial of last transition from unmapped */
+
+ cairo_surface_t *icon_pixmap;
+ cairo_surface_t *icon_mask;
+ GdkSurface *group_leader;
+
+ /* Time of most recent user interaction. */
+ gulong user_time;
+
+ /* We use an extra X window for toplevel windows that we XSetInputFocus()
+ * to in order to avoid getting keyboard events redirected to subwindows
+ * that might not even be part of this app
+ */
+ Window focus_window;
+
+ GdkSurfaceHints last_geometry_hints_mask;
+ GdkGeometry last_geometry_hints;
+
+ /* Constrained edge information */
+ guint edge_constraints;
+
+#ifdef HAVE_XSYNC
+ XID update_counter;
+ XID extended_update_counter;
+ gint64 pending_counter_value; /* latest _NET_WM_SYNC_REQUEST value received */
+ gint64 configure_counter_value; /* Latest _NET_WM_SYNC_REQUEST value received
+ * where we have also seen the corresponding
+ * ConfigureNotify
+ */
+ gint64 current_counter_value;
+
+ /* After a _NET_WM_FRAME_DRAWN message, this is the soonest that we think
+ * frame after will be presented */
+ gint64 throttled_presentation_time;
+#endif
+};
+
+GType gdk_surface_impl_x11_get_type (void);
+
+GdkToplevelX11 *_gdk_x11_surface_get_toplevel (GdkSurface *window);
+
+GdkCursor *_gdk_x11_surface_get_cursor (GdkSurface *window);
+
+void _gdk_x11_surface_update_size (GdkSurfaceImplX11 *impl);
+void _gdk_x11_surface_set_window_scale (GdkSurface *window,
+ int scale);
+
+G_END_DECLS
+
+#endif /* __GDK_SURFACE_X11_H__ */
#include "gdkinternals.h"
#include "gdkdisplay-x11.h"
-#include "gdkwindow-x11.h"
+#include "gdksurface-x11.h"
G_DEFINE_TYPE (GdkX11VulkanContext, gdk_x11_vulkan_context, GDK_TYPE_VULKAN_CONTEXT)
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-2007 Peter Mattis, Spencer Kimball,
- * Josh MacDonald, Ryan Lortie
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#include "config.h"
-
-#include "gdkwindow-x11.h"
-
-#include "gdkwindow.h"
-#include "gdkwindowimpl.h"
-#include "gdkvisual-x11.h"
-#include "gdkinternals.h"
-#include "gdkdeviceprivate.h"
-#include "gdkframeclockprivate.h"
-#include "gdkasync.h"
-#include "gdkeventsource.h"
-#include "gdkdisplay-x11.h"
-#include "gdkglcontext-x11.h"
-#include "gdkprivate-x11.h"
-#include "gdktextureprivate.h"
-#include "gdk-private.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include <cairo-xlib.h>
-
-#include "MwmUtil.h"
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xatom.h>
-
-#include <X11/extensions/shape.h>
-
-#ifdef HAVE_XKB
-#include <X11/XKBlib.h>
-#endif
-
-#ifdef HAVE_XCOMPOSITE
-#include <X11/extensions/Xcomposite.h>
-#endif
-
-#ifdef HAVE_XFIXES
-#include <X11/extensions/Xfixes.h>
-#endif
-
-#ifdef HAVE_XDAMAGE
-#include <X11/extensions/Xdamage.h>
-#endif
-
-const int _gdk_x11_event_mask_table[21] =
-{
- ExposureMask,
- PointerMotionMask,
- PointerMotionHintMask,
- ButtonMotionMask,
- Button1MotionMask,
- Button2MotionMask,
- Button3MotionMask,
- ButtonPressMask,
- ButtonReleaseMask,
- KeyPressMask,
- KeyReleaseMask,
- EnterWindowMask,
- LeaveWindowMask,
- FocusChangeMask,
- StructureNotifyMask,
- PropertyChangeMask,
- VisibilityChangeMask,
- 0, /* PROXIMITY_IN */
- 0, /* PROXIMTY_OUT */
- SubstructureNotifyMask,
- ButtonPressMask /* SCROLL; on X mouse wheel events is treated as mouse button 4/5 */
-};
-
-const gint _gdk_x11_event_mask_table_size = G_N_ELEMENTS (_gdk_x11_event_mask_table);
-
-/* Forward declarations */
-static void gdk_x11_surface_apply_fullscreen_mode (GdkSurface *window);
-static gboolean gdk_surface_icon_name_set (GdkSurface *window);
-static void set_wm_name (GdkDisplay *display,
- Window xwindow,
- const gchar *name);
-static void move_to_current_desktop (GdkSurface *window);
-
-static void gdk_surface_impl_x11_finalize (GObject *object);
-
-#define WINDOW_IS_TOPLEVEL_OR_FOREIGN(window) \
- (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL || \
- GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP || \
- GDK_SURFACE_TYPE (window) == GDK_SURFACE_FOREIGN)
-
-#define WINDOW_IS_TOPLEVEL(window) \
- (GDK_SURFACE_TYPE (window) == GDK_SURFACE_TOPLEVEL || \
- GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP)
-
-/* Return whether time1 is considered later than time2 as far as xserver
- * time is concerned. Accounts for wraparound.
- */
-#define XSERVER_TIME_IS_LATER(time1, time2) \
- ( (( time1 > time2 ) && ( time1 - time2 < ((guint32)-1)/2 )) || \
- (( time1 < time2 ) && ( time2 - time1 > ((guint32)-1)/2 )) \
- )
-
-struct _GdkX11Surface {
- GdkSurface parent;
-};
-
-struct _GdkX11SurfaceClass {
- GdkSurfaceClass parent_class;
-};
-
-G_DEFINE_TYPE (GdkX11Surface, gdk_x11_surface, GDK_TYPE_SURFACE)
-
-static void
-gdk_x11_surface_class_init (GdkX11SurfaceClass *x11_surface_class)
-{
-}
-
-static void
-gdk_x11_surface_init (GdkX11Surface *x11_surface)
-{
-}
-
-
-G_DEFINE_TYPE (GdkSurfaceImplX11, gdk_surface_impl_x11, GDK_TYPE_SURFACE_IMPL)
-
-static void
-gdk_surface_impl_x11_init (GdkSurfaceImplX11 *impl)
-{
- impl->window_scale = 1;
- impl->frame_sync_enabled = TRUE;
-}
-
-GdkToplevelX11 *
-_gdk_x11_surface_get_toplevel (GdkSurface *window)
-{
- GdkSurfaceImplX11 *impl;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- if (!WINDOW_IS_TOPLEVEL (window))
- return NULL;
-
- impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (!impl->toplevel)
- {
- impl->toplevel = g_new0 (GdkToplevelX11, 1);
- impl->toplevel->have_focused = FALSE;
- }
-
- return impl->toplevel;
-}
-
-/**
- * _gdk_x11_surface_update_size:
- * @impl: a #GdkSurfaceImplX11.
- *
- * Updates the state of the window (in particular the drawable's
- * cairo surface) when its size has changed.
- **/
-void
-_gdk_x11_surface_update_size (GdkSurfaceImplX11 *impl)
-{
- if (impl->cairo_surface)
- {
- cairo_xlib_surface_set_size (impl->cairo_surface,
- impl->unscaled_width, impl->unscaled_height);
- }
-}
-
-static void
-gdk_x11_surface_get_unscaled_size (GdkSurface *window,
- int *unscaled_width,
- int *unscaled_height)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (unscaled_width)
- *unscaled_width = impl->unscaled_width;
-
- if (unscaled_height)
- *unscaled_height = impl->unscaled_height;
-}
-
-static gboolean
-gdk_x11_surface_supports_edge_constraints (GdkSurface *window)
-{
- return gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
- g_intern_static_string ("_GTK_EDGE_CONSTRAINTS"));
-}
-
-static void
-set_sync_counter(Display *display,
- XSyncCounter counter,
- gint64 value)
-{
- XSyncValue sync_value;
-
- XSyncIntsToValue (&sync_value,
- value & G_GINT64_CONSTANT(0xFFFFFFFF),
- value >> 32);
- XSyncSetCounter (display, counter, sync_value);
-}
-
-static void
-window_pre_damage (GdkSurface *window)
-{
- GdkSurface *toplevel_window = gdk_surface_get_toplevel (window);
- GdkSurfaceImplX11 *impl;
-
- if (!toplevel_window || !WINDOW_IS_TOPLEVEL (toplevel_window))
- return;
-
- impl = GDK_SURFACE_IMPL_X11 (toplevel_window->impl);
-
- if (impl->toplevel->in_frame &&
- impl->toplevel->current_counter_value % 2 == 0)
- {
- impl->toplevel->current_counter_value += 1;
- set_sync_counter (GDK_SURFACE_XDISPLAY (impl->wrapper),
- impl->toplevel->extended_update_counter,
- impl->toplevel->current_counter_value);
- }
-}
-
-static void
-on_surface_changed (void *data)
-{
- GdkSurface *window = data;
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (impl->tracking_damage)
- window_pre_damage (window);
-}
-
-/* We want to know when cairo drawing causes damage to the window,
- * so we engage in the _NET_WM_FRAME_DRAWN protocol with the
- * window only when there actually is drawing. To do that we use
- * a technique (hack) suggested by Uli Schlachter - if we set
- * a dummy "mime data" on the cairo surface (this facility is
- * used to attach JPEG data to an imager), then cairo wil flush
- * and remove the mime data before making any changes to the window.
- */
-
-static void
-hook_surface_changed (GdkSurface *window)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (impl->cairo_surface)
- {
- cairo_surface_set_mime_data (impl->cairo_surface,
- "x-gdk/change-notify",
- (unsigned char *)"X",
- 1,
- on_surface_changed,
- window);
- impl->tracking_damage = 1;
- }
-}
-
-static void
-unhook_surface_changed (GdkSurface *window)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (impl->cairo_surface)
- {
- impl->tracking_damage = 0;
- cairo_surface_set_mime_data (impl->cairo_surface,
- "x-gdk/change-notify",
- NULL, 0,
- NULL, NULL);
- }
-}
-
-static void
-gdk_x11_surface_predict_presentation_time (GdkSurface *window)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
- GdkFrameClock *clock;
- GdkFrameTimings *timings;
- gint64 presentation_time;
- gint64 refresh_interval;
-
- if (!WINDOW_IS_TOPLEVEL (window))
- return;
-
- clock = gdk_surface_get_frame_clock (window);
-
- timings = gdk_frame_clock_get_current_timings (clock);
-
- gdk_frame_clock_get_refresh_info (clock,
- timings->frame_time,
- &refresh_interval, &presentation_time);
-
- if (presentation_time != 0)
- {
- if (timings->slept_before)
- {
- presentation_time += refresh_interval;
- }
- else
- {
- if (presentation_time < timings->frame_time + refresh_interval / 2)
- presentation_time += refresh_interval;
- }
- }
- else
- {
- if (timings->slept_before)
- presentation_time = timings->frame_time + refresh_interval + refresh_interval / 2;
- else
- presentation_time = timings->frame_time + refresh_interval;
- }
-
- if (presentation_time < impl->toplevel->throttled_presentation_time)
- presentation_time = impl->toplevel->throttled_presentation_time;
-
- timings->predicted_presentation_time = presentation_time;
-}
-
-static void
-gdk_x11_surface_begin_frame (GdkSurface *window,
- gboolean force_frame)
-{
- GdkSurfaceImplX11 *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (!WINDOW_IS_TOPLEVEL (window) ||
- impl->toplevel->extended_update_counter == None)
- return;
-
- impl->toplevel->in_frame = TRUE;
-
- if (impl->toplevel->configure_counter_value != 0 &&
- impl->toplevel->configure_counter_value_is_extended)
- {
- impl->toplevel->current_counter_value = impl->toplevel->configure_counter_value;
- if ((impl->toplevel->current_counter_value % 2) == 1)
- impl->toplevel->current_counter_value += 1;
-
- impl->toplevel->configure_counter_value = 0;
-
- window_pre_damage (window);
- }
- else if (force_frame)
- {
- /* When mapping the window, we really want to freeze the
- rendering of the window by the compositor until we've
- actually painted something into the window's buffer. */
- window_pre_damage (window);
- }
- else
- {
- hook_surface_changed (window);
- }
-}
-
-static void
-gdk_x11_surface_end_frame (GdkSurface *window)
-{
- GdkFrameClock *clock;
- GdkFrameTimings *timings;
- GdkSurfaceImplX11 *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (!WINDOW_IS_TOPLEVEL (window) ||
- impl->toplevel->extended_update_counter == None ||
- !impl->toplevel->in_frame)
- return;
-
- clock = gdk_surface_get_frame_clock (window);
- timings = gdk_frame_clock_get_current_timings (clock);
-
- impl->toplevel->in_frame = FALSE;
-
- if (impl->toplevel->current_counter_value % 2 == 1)
- {
- if (GDK_DISPLAY_DEBUG_CHECK (gdk_surface_get_display (window), FRAMES))
- {
- XImage *image = XGetImage (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- 0, 0, 1, 1,
- (1 << 24) - 1,
- ZPixmap);
- XDestroyImage (image);
- }
-
- /* An increment of 3 means that the frame was not drawn as fast as possible,
- * but rather at a particular time. This can trigger different handling from
- * the compositor.
- */
- if (timings->slept_before)
- impl->toplevel->current_counter_value += 3;
- else
- impl->toplevel->current_counter_value += 1;
-
- set_sync_counter(GDK_SURFACE_XDISPLAY (impl->wrapper),
- impl->toplevel->extended_update_counter,
- impl->toplevel->current_counter_value);
-
- if (impl->frame_sync_enabled &&
- gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
- g_intern_static_string ("_NET_WM_FRAME_DRAWN")))
- {
- impl->toplevel->frame_pending = TRUE;
- _gdk_frame_clock_freeze (gdk_surface_get_frame_clock (window));
- timings->cookie = impl->toplevel->current_counter_value;
- }
- }
-
- unhook_surface_changed (window);
-
- if (impl->toplevel->configure_counter_value != 0 &&
- !impl->toplevel->configure_counter_value_is_extended)
- {
- set_sync_counter (GDK_SURFACE_XDISPLAY (window),
- impl->toplevel->update_counter,
- impl->toplevel->configure_counter_value);
-
- impl->toplevel->configure_counter_value = 0;
- }
-
- if (!impl->toplevel->frame_pending)
- timings->complete = TRUE;
-}
-
-/*****************************************************
- * X11 specific implementations of generic functions *
- *****************************************************/
-
-static cairo_surface_t *
-gdk_x11_create_cairo_surface (GdkSurfaceImplX11 *impl,
- int width,
- int height)
-{
- Visual *visual;
-
- visual = gdk_x11_display_get_window_visual (GDK_X11_DISPLAY (gdk_surface_get_display (impl->wrapper)));
- return cairo_xlib_surface_create (GDK_SURFACE_XDISPLAY (impl->wrapper),
- GDK_SURFACE_IMPL_X11 (impl)->xid,
- visual,
- width, height);
-}
-
-static cairo_surface_t *
-gdk_x11_ref_cairo_surface (GdkSurface *window)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- if (!impl->cairo_surface)
- {
- impl->cairo_surface = gdk_x11_create_cairo_surface (impl,
- gdk_surface_get_width (window) * impl->window_scale,
- gdk_surface_get_height (window) * impl->window_scale);
- cairo_surface_set_device_scale (impl->cairo_surface, impl->window_scale, impl->window_scale);
-
- if (WINDOW_IS_TOPLEVEL (window) && impl->toplevel->in_frame)
- hook_surface_changed (window);
- }
-
- cairo_surface_reference (impl->cairo_surface);
-
- return impl->cairo_surface;
-}
-
-static void
-gdk_surface_impl_x11_finalize (GObject *object)
-{
- GdkSurface *wrapper;
- GdkSurfaceImplX11 *impl;
-
- g_return_if_fail (GDK_IS_SURFACE_IMPL_X11 (object));
-
- impl = GDK_SURFACE_IMPL_X11 (object);
-
- wrapper = impl->wrapper;
-
- if (WINDOW_IS_TOPLEVEL (wrapper) && impl->toplevel->in_frame)
- unhook_surface_changed (wrapper);
-
- _gdk_x11_surface_grab_check_destroy (wrapper);
-
- if (!GDK_SURFACE_DESTROYED (wrapper))
- {
- GdkDisplay *display = GDK_SURFACE_DISPLAY (wrapper);
-
- _gdk_x11_display_remove_window (display, impl->xid);
- if (impl->toplevel && impl->toplevel->focus_window)
- _gdk_x11_display_remove_window (display, impl->toplevel->focus_window);
- }
-
- g_free (impl->toplevel);
-
- if (impl->cursor)
- g_object_unref (impl->cursor);
-
- G_OBJECT_CLASS (gdk_surface_impl_x11_parent_class)->finalize (object);
-}
-
-typedef struct {
- GdkDisplay *display;
- Pixmap pixmap;
-} FreePixmapData;
-
-static void
-free_pixmap (gpointer datap)
-{
- FreePixmapData *data = datap;
-
- if (!gdk_display_is_closed (data->display))
- {
- XFreePixmap (GDK_DISPLAY_XDISPLAY (data->display),
- data->pixmap);
- }
-
- g_object_unref (data->display);
- g_slice_free (FreePixmapData, data);
-}
-
-static void
-attach_free_pixmap_handler (cairo_surface_t *surface,
- GdkDisplay *display,
- Pixmap pixmap)
-{
- static const cairo_user_data_key_t key;
- FreePixmapData *data;
-
- data = g_slice_new (FreePixmapData);
- data->display = g_object_ref (display);
- data->pixmap = pixmap;
-
- cairo_surface_set_user_data (surface, &key, data, free_pixmap);
-}
-
-/* Cairo does not guarantee we get an xlib surface if we call
- * cairo_surface_create_similar(). In some cases however, we must use a
- * pixmap or bitmap in the X11 API.
- * These functions ensure an Xlib surface.
- */
-cairo_surface_t *
-_gdk_x11_display_create_bitmap_surface (GdkDisplay *display,
- int width,
- int height)
-{
- cairo_surface_t *surface;
- Pixmap pixmap;
-
- pixmap = XCreatePixmap (GDK_DISPLAY_XDISPLAY (display),
- GDK_SCREEN_XROOTWIN (GDK_X11_DISPLAY (display)->screen),
- width, height, 1);
- surface = cairo_xlib_surface_create_for_bitmap (GDK_DISPLAY_XDISPLAY (display),
- pixmap,
- GDK_X11_SCREEN (GDK_X11_DISPLAY (display)->screen)->xscreen,
- width, height);
- attach_free_pixmap_handler (surface, display, pixmap);
-
- return surface;
-}
-
-/* Create a surface backed with a pixmap without alpha on the same screen as window */
-static cairo_surface_t *
-gdk_x11_surface_create_pixmap_surface (GdkSurface *window,
- int width,
- int height)
-{
- GdkDisplay *display;
- Display *dpy;
- cairo_surface_t *surface;
- Pixmap pixmap;
-
- display = gdk_surface_get_display (window);
- dpy = GDK_DISPLAY_XDISPLAY (display);
-
- pixmap = XCreatePixmap (dpy,
- GDK_SURFACE_XID (window),
- width, height,
- DefaultDepth (dpy, DefaultScreen (dpy)));
- surface = cairo_xlib_surface_create (dpy,
- pixmap,
- DefaultVisual (dpy, DefaultScreen (dpy)),
- width, height);
- attach_free_pixmap_handler (surface, display, pixmap);
-
- return surface;
-}
-
-static void
-set_wm_protocols (GdkSurface *window)
-{
- GdkDisplay *display = gdk_surface_get_display (window);
- Atom protocols[4];
- int n = 0;
-
- protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW");
- protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS");
- protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING");
-
-#ifdef HAVE_XSYNC
- if (GDK_X11_DISPLAY (display)->use_sync)
- protocols[n++] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST");
-#endif
-
- XSetWMProtocols (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window), protocols, n);
-}
-
-static const gchar *
-get_default_title (void)
-{
- const char *title;
-
- title = g_get_application_name ();
- if (!title)
- title = g_get_prgname ();
- if (!title)
- title = "";
-
- return title;
-}
-
-static void
-check_leader_window_title (GdkDisplay *display)
-{
- GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
-
- if (display_x11->leader_window && !display_x11->leader_window_title_set)
- {
- set_wm_name (display,
- display_x11->leader_window,
- get_default_title ());
-
- display_x11->leader_window_title_set = TRUE;
- }
-}
-
-static Window
-create_focus_window (GdkDisplay *display,
- XID parent)
-{
- GdkX11Display *display_x11;
- GdkEventMask event_mask;
- Display *xdisplay;
- Window focus_window;
- XSetWindowAttributes attrs;
-
- xdisplay = GDK_DISPLAY_XDISPLAY (display);
- display_x11 = GDK_X11_DISPLAY (display);
-
- focus_window = XCreateWindow (xdisplay, parent,
- -1, -1, 1, 1, 0,
- 0, /* depth */
- InputOnly,
- CopyFromParent,
- 0, &attrs);
-
- event_mask = (GDK_KEY_PRESS_MASK |
- GDK_KEY_RELEASE_MASK |
- GDK_FOCUS_CHANGE_MASK);
-
- gdk_x11_event_source_select_events ((GdkEventSource *) display_x11->event_source,
- focus_window,
- event_mask, 0);
-
- XMapWindow (xdisplay, focus_window);
-
- return focus_window;
-}
-
-static void
-ensure_sync_counter (GdkSurface *window)
-{
-#ifdef HAVE_XSYNC
- if (!GDK_SURFACE_DESTROYED (window))
- {
- GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
- GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (window);
-
- if (toplevel &&
- toplevel->update_counter == None &&
- GDK_X11_DISPLAY (display)->use_sync)
- {
- Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
- XSyncValue value;
- Atom atom;
- XID counters[2];
-
- XSyncIntToValue (&value, 0);
-
- toplevel->update_counter = XSyncCreateCounter (xdisplay, value);
- toplevel->extended_update_counter = XSyncCreateCounter (xdisplay, value);
-
- atom = gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_WM_SYNC_REQUEST_COUNTER");
-
- counters[0] = toplevel->update_counter;
- counters[1] = toplevel->extended_update_counter;
- XChangeProperty (xdisplay, GDK_SURFACE_XID (window),
- atom, XA_CARDINAL,
- 32, PropModeReplace,
- (guchar *)counters, 2);
-
- toplevel->current_counter_value = 0;
- }
- }
-#endif
-}
-
-static void
-setup_toplevel_window (GdkSurface *window,
- GdkX11Screen *x11_screen)
-{
- GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (window);
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
- GdkDisplay *display = gdk_surface_get_display (window);
- Display *xdisplay = GDK_SURFACE_XDISPLAY (window);
- XID xid = GDK_SURFACE_XID (window);
- XSizeHints size_hints;
- long pid;
- Window leader_window;
-
- set_wm_protocols (window);
-
- if (!window->input_only)
- {
- /* The focus window is off the visible area, and serves to receive key
- * press events so they don't get sent to child windows.
- */
- toplevel->focus_window = create_focus_window (display, xid);
- _gdk_x11_display_add_window (x11_screen->display,
- &toplevel->focus_window,
- window);
- }
-
- check_leader_window_title (x11_screen->display);
-
- /* FIXME: Is there any point in doing this? Do any WM's pay
- * attention to PSize, and even if they do, is this the
- * correct value???
- */
- size_hints.flags = PSize;
- size_hints.width = window->width * impl->window_scale;
- size_hints.height = window->height * impl->window_scale;
-
- XSetWMNormalHints (xdisplay, xid, &size_hints);
-
- /* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
- XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
-
- pid = getpid ();
- XChangeProperty (xdisplay, xid,
- gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_WM_PID"),
- XA_CARDINAL, 32,
- PropModeReplace,
- (guchar *)&pid, 1);
-
- leader_window = GDK_X11_DISPLAY (x11_screen->display)->leader_window;
- if (!leader_window)
- leader_window = xid;
- XChangeProperty (xdisplay, xid,
- gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "WM_CLIENT_LEADER"),
- XA_WINDOW, 32, PropModeReplace,
- (guchar *) &leader_window, 1);
-
- if (toplevel->focus_window != None)
- XChangeProperty (xdisplay, xid,
- gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_WM_USER_TIME_WINDOW"),
- XA_WINDOW, 32, PropModeReplace,
- (guchar *) &toplevel->focus_window, 1);
-
- if (!window->focus_on_map)
- gdk_x11_surface_set_user_time (window, 0);
- else if (GDK_X11_DISPLAY (x11_screen->display)->user_time != 0)
- gdk_x11_surface_set_user_time (window, GDK_X11_DISPLAY (x11_screen->display)->user_time);
-
- ensure_sync_counter (window);
-
- /* Start off in a frozen state - we'll finish this when we first paint */
- gdk_x11_surface_begin_frame (window, TRUE);
-}
-
-static void
-on_frame_clock_before_paint (GdkFrameClock *clock,
- GdkSurface *window)
-{
- gdk_x11_surface_predict_presentation_time (window);
- gdk_x11_surface_begin_frame (window, FALSE);
-}
-
-static void
-on_frame_clock_after_paint (GdkFrameClock *clock,
- GdkSurface *window)
-{
- gdk_x11_surface_end_frame (window);
-
-}
-
-static void
-connect_frame_clock (GdkSurface *window)
-{
- GdkSurfaceImplX11 *impl;
-
- impl = GDK_SURFACE_IMPL_X11 (window->impl);
- if (WINDOW_IS_TOPLEVEL (window) && !impl->frame_clock_connected)
- {
- GdkFrameClock *frame_clock = gdk_surface_get_frame_clock (window);
-
- g_signal_connect (frame_clock, "before-paint",
- G_CALLBACK (on_frame_clock_before_paint), window);
- g_signal_connect (frame_clock, "after-paint",
- G_CALLBACK (on_frame_clock_after_paint), window);
-
- impl->frame_clock_connected = TRUE;
- }
-}
-
-void
-_gdk_x11_display_create_window_impl (GdkDisplay *display,
- GdkSurface *window,
- GdkSurface *real_parent,
- GdkEventMask event_mask,
- GdkSurfaceAttr *attributes)
-{
- GdkSurfaceImplX11 *impl;
- GdkX11Screen *x11_screen;
- GdkX11Display *display_x11;
-
- Window xparent;
- Visual *xvisual;
- Display *xdisplay;
-
- XSetWindowAttributes xattributes;
- long xattributes_mask;
- XClassHint *class_hint;
-
- unsigned int class;
- int depth;
-
- int abs_x;
- int abs_y;
-
- display_x11 = GDK_X11_DISPLAY (display);
- x11_screen = GDK_X11_SCREEN (display_x11->screen);
- if (real_parent)
- xparent = GDK_SURFACE_XID (real_parent);
- else
- xparent = GDK_SCREEN_XROOTWIN (x11_screen);
-
- impl = g_object_new (GDK_TYPE_SURFACE_IMPL_X11, NULL);
- window->impl = GDK_SURFACE_IMPL (impl);
- impl->wrapper = GDK_SURFACE (window);
- impl->window_scale = x11_screen->window_scale;
-
- xdisplay = x11_screen->xdisplay;
-
- xattributes_mask = 0;
-
- xvisual = gdk_x11_display_get_window_visual (display_x11);
-
- impl->override_redirect = FALSE;
-
- /* Sanity checks */
- switch (window->window_type)
- {
- case GDK_SURFACE_TOPLEVEL:
- case GDK_SURFACE_TEMP:
- if (window->parent)
- {
- /* The common code warns for this case */
- xparent = GDK_SCREEN_XROOTWIN (x11_screen);
- }
- break;
-
- case GDK_SURFACE_CHILD:
- default:
- g_assert_not_reached ();
- break;
- }
-
- if (!window->input_only)
- {
- class = InputOutput;
-
- xattributes.background_pixel = BlackPixel (xdisplay, x11_screen->screen_num);
-
- xattributes.border_pixel = BlackPixel (xdisplay, x11_screen->screen_num);
- xattributes_mask |= CWBorderPixel | CWBackPixel;
-
- xattributes.bit_gravity = NorthWestGravity;
- xattributes_mask |= CWBitGravity;
-
- xattributes.colormap = gdk_x11_display_get_window_colormap (display_x11);
- xattributes_mask |= CWColormap;
-
- if (window->window_type == GDK_SURFACE_TEMP)
- {
- xattributes.save_under = True;
- xattributes.override_redirect = True;
- xattributes.cursor = None;
- xattributes_mask |= CWSaveUnder | CWOverrideRedirect;
-
- impl->override_redirect = TRUE;
- }
-
- depth = gdk_x11_display_get_window_depth (display_x11);
- }
- else
- {
- class = InputOnly;
-
- if (window->window_type == GDK_SURFACE_TEMP)
- {
- xattributes.override_redirect = True;
- xattributes_mask |= CWOverrideRedirect;
-
- impl->override_redirect = TRUE;
- }
-
- depth = 0;
- }
-
- if (window->width * impl->window_scale > 32767 ||
- window->height * impl->window_scale > 32767)
- {
- g_warning ("Native Windows wider or taller than 32767 pixels are not supported");
-
- if (window->width * impl->window_scale > 32767)
- window->width = 32767 / impl->window_scale;
- if (window->height * impl->window_scale > 32767)
- window->height = 32767 / impl->window_scale;
- }
-
- impl->unscaled_width = window->width * impl->window_scale;
- impl->unscaled_height = window->height * impl->window_scale;
-
- if (window->parent)
- {
- abs_x = window->parent->abs_x;
- abs_y = window->parent->abs_y;
- }
- else
- {
- abs_x = 0;
- abs_y = 0;
- }
-
- impl->xid = XCreateWindow (xdisplay, xparent,
- (window->x + abs_x) * impl->window_scale,
- (window->y + abs_y) * impl->window_scale,
- window->width * impl->window_scale, window->height * impl->window_scale,
- 0, depth, class, xvisual,
- xattributes_mask, &xattributes);
-
- g_object_ref (window);
- _gdk_x11_display_add_window (x11_screen->display, &impl->xid, window);
-
- switch (GDK_SURFACE_TYPE (window))
- {
- case GDK_SURFACE_TOPLEVEL:
- case GDK_SURFACE_TEMP:
- gdk_surface_set_title (window, get_default_title ());
-
- class_hint = XAllocClassHint ();
- class_hint->res_name = (char *) g_get_prgname ();
- class_hint->res_class = (char *) display_x11->program_class;
- XSetClassHint (xdisplay, impl->xid, class_hint);
- XFree (class_hint);
-
- setup_toplevel_window (window, x11_screen);
- break;
-
- case GDK_SURFACE_CHILD:
- default:
- break;
- }
-
- gdk_x11_event_source_select_events ((GdkEventSource *) display_x11->event_source,
- GDK_SURFACE_XID (window), event_mask,
- StructureNotifyMask | PropertyChangeMask);
-
- connect_frame_clock (window);
-
- gdk_surface_freeze_toplevel_updates (window);
-}
-
-static GdkEventMask
-x_event_mask_to_gdk_event_mask (long mask)
-{
- GdkEventMask event_mask = 0;
- int i;
-
- for (i = 0; i < _gdk_x11_event_mask_table_size; i++)
- {
- if (mask & _gdk_x11_event_mask_table[i])
- event_mask |= 1 << (i + 1);
- }
-
- return event_mask;
-}
-
-/**
- * gdk_x11_surface_foreign_new_for_display:
- * @display: (type GdkX11Display): the #GdkDisplay where the window handle comes from.
- * @window: an Xlib Window
- *
- * Wraps a native window in a #GdkSurface. The function will try to
- * look up the window using gdk_x11_surface_lookup_for_display() first.
- * If it does not find it there, it will create a new window.
- *
- * This may fail if the window has been destroyed. If the window
- * was already known to GDK, a new reference to the existing
- * #GdkSurface is returned.
- *
- * Returns: (transfer full): a #GdkSurface wrapper for the native
- * window, or %NULL if the window has been destroyed. The wrapper
- * will be newly created, if one doesn’t exist already.
- */
-GdkSurface *
-gdk_x11_surface_foreign_new_for_display (GdkDisplay *display,
- Window window)
-{
- GdkX11Screen *screen;
- GdkSurface *win;
- GdkSurfaceImplX11 *impl;
- GdkX11Display *display_x11;
- XWindowAttributes attrs;
- Window root, parent;
- Window *children = NULL;
- guint nchildren;
- gboolean result;
-
- g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
-
- display_x11 = GDK_X11_DISPLAY (display);
-
- if ((win = gdk_x11_surface_lookup_for_display (display, window)) != NULL)
- return g_object_ref (win);
-
- gdk_x11_display_error_trap_push (display);
- result = XGetWindowAttributes (display_x11->xdisplay, window, &attrs);
- if (gdk_x11_display_error_trap_pop (display) || !result)
- return NULL;
-
- /* FIXME: This is pretty expensive.
- * Maybe the caller should supply the parent
- */
- gdk_x11_display_error_trap_push (display);
- result = XQueryTree (display_x11->xdisplay, window, &root, &parent, &children, &nchildren);
- if (gdk_x11_display_error_trap_pop (display) || !result)
- return NULL;
-
- if (children)
- XFree (children);
-
- screen = _gdk_x11_display_screen_for_xrootwin (display, root);
- if (screen == NULL)
- return NULL;
-
- win = _gdk_display_create_window (display);
- win->impl = g_object_new (GDK_TYPE_SURFACE_IMPL_X11, NULL);
- win->impl_window = win;
-
- impl = GDK_SURFACE_IMPL_X11 (win->impl);
- impl->wrapper = win;
- impl->window_scale = GDK_X11_SCREEN (screen)->window_scale;
-
- /* Always treat foreigns as toplevels */
- win->parent = NULL;
-
- impl->xid = window;
-
- win->x = attrs.x / impl->window_scale;
- win->y = attrs.y / impl->window_scale;
- impl->unscaled_width = attrs.width;
- impl->unscaled_height = attrs.height;
- win->width = attrs.width / impl->window_scale;
- win->height = attrs.height / impl->window_scale;
- win->window_type = GDK_SURFACE_FOREIGN;
- win->destroyed = FALSE;
-
- win->event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
-
- if (attrs.map_state == IsUnmapped)
- win->state = GDK_SURFACE_STATE_WITHDRAWN;
- else
- win->state = 0;
- win->viewable = TRUE;
-
- g_object_ref (win);
- _gdk_x11_display_add_window (display, &GDK_SURFACE_XID (win), win);
-
- /* Update the clip region, etc */
- _gdk_surface_update_size (win);
-
- return win;
-}
-
-static void
-gdk_toplevel_x11_free_contents (GdkDisplay *display,
- GdkToplevelX11 *toplevel)
-{
- if (toplevel->icon_pixmap)
- {
- cairo_surface_destroy (toplevel->icon_pixmap);
- toplevel->icon_pixmap = NULL;
- }
- if (toplevel->icon_mask)
- {
- cairo_surface_destroy (toplevel->icon_mask);
- toplevel->icon_mask = NULL;
- }
- if (toplevel->group_leader)
- {
- g_object_unref (toplevel->group_leader);
- toplevel->group_leader = NULL;
- }
-#ifdef HAVE_XSYNC
- if (toplevel->update_counter != None)
- {
- XSyncDestroyCounter (GDK_DISPLAY_XDISPLAY (display),
- toplevel->update_counter);
- XSyncDestroyCounter (GDK_DISPLAY_XDISPLAY (display),
- toplevel->extended_update_counter);
- toplevel->update_counter = None;
- toplevel->extended_update_counter = None;
-
- toplevel->current_counter_value = 0;
- }
-#endif
-}
-
-static void
-gdk_x11_surface_destroy (GdkSurface *window,
- gboolean recursing,
- gboolean foreign_destroy)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
- GdkToplevelX11 *toplevel;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- toplevel = _gdk_x11_surface_get_toplevel (window);
- if (toplevel)
- gdk_toplevel_x11_free_contents (GDK_SURFACE_DISPLAY (window), toplevel);
-
- unhook_surface_changed (window);
-
- if (impl->cairo_surface)
- {
- cairo_surface_finish (impl->cairo_surface);
- cairo_surface_destroy (impl->cairo_surface);
- impl->cairo_surface = NULL;
- }
-
- if (!recursing && !foreign_destroy)
- XDestroyWindow (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XID (window));
-}
-
-/* This function is called when the XWindow is really gone.
- */
-static void
-gdk_x11_surface_destroy_notify (GdkSurface *window)
-{
- GdkSurfaceImplX11 *window_impl;
-
- window_impl = GDK_SURFACE_IMPL_X11 ((window)->impl);
-
- if (!GDK_SURFACE_DESTROYED (window))
- {
- if (GDK_SURFACE_TYPE(window) != GDK_SURFACE_FOREIGN)
- g_warning ("GdkSurface %#lx unexpectedly destroyed", GDK_SURFACE_XID (window));
-
- _gdk_surface_destroy (window, TRUE);
- }
-
- _gdk_x11_display_remove_window (GDK_SURFACE_DISPLAY (window), GDK_SURFACE_XID (window));
- if (window_impl->toplevel && window_impl->toplevel->focus_window)
- _gdk_x11_display_remove_window (GDK_SURFACE_DISPLAY (window), window_impl->toplevel->focus_window);
-
- _gdk_x11_surface_grab_check_destroy (window);
-
- g_object_unref (window);
-}
-
-static void
-update_wm_hints (GdkSurface *window,
- gboolean force)
-{
- GdkToplevelX11 *toplevel = _gdk_x11_surface_get_toplevel (window);
- GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
- XWMHints wm_hints;
-
- if (!force &&
- !toplevel->is_leader &&
- window->state & GDK_SURFACE_STATE_WITHDRAWN)
- return;
-
- wm_hints.flags = StateHint | InputHint;
- wm_hints.input = window->accept_focus ? True : False;
- wm_hints.initial_state = NormalState;
-
- if (window->state & GDK_SURFACE_STATE_ICONIFIED)
- {
- wm_hints.flags |= StateHint;
- wm_hints.initial_state = IconicState;
- }
-
- if (toplevel->icon_pixmap)
- {
- wm_hints.flags |= IconPixmapHint;
- wm_hints.icon_pixmap = cairo_xlib_surface_get_drawable (toplevel->icon_pixmap);
- }
-
- if (toplevel->icon_mask)
- {
- wm_hints.flags |= IconMaskHint;
- wm_hints.icon_mask = cairo_xlib_surface_get_drawable (toplevel->icon_mask);
- }
-
- wm_hints.flags |= WindowGroupHint;
- if (toplevel->group_leader && !GDK_SURFACE_DESTROYED (toplevel->group_leader))
- {
- wm_hints.flags |= WindowGroupHint;
- wm_hints.window_group = GDK_SURFACE_XID (toplevel->group_leader);
- }
- else
- wm_hints.window_group = GDK_X11_DISPLAY (display)->leader_window;
-
- if (toplevel->urgency_hint)
- wm_hints.flags |= XUrgencyHint;
-
- XSetWMHints (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- &wm_hints);
-}
-
-static void
-set_initial_hints (GdkSurface *window)
-{
- GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
- Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
- Window xwindow = GDK_SURFACE_XID (window);
- GdkToplevelX11 *toplevel;
- Atom atoms[9];
- gint i;
-
- toplevel = _gdk_x11_surface_get_toplevel (window);
-
- if (!toplevel)
- return;
-
- update_wm_hints (window, TRUE);
-
- /* We set the spec hints regardless of whether the spec is supported,
- * since it can't hurt and it's kind of expensive to check whether
- * it's supported.
- */
-
- i = 0;
-
- if (window->state & GDK_SURFACE_STATE_MAXIMIZED)
- {
- atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_WM_STATE_MAXIMIZED_VERT");
- ++i;
- atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_WM_STATE_MAXIMIZED_HORZ");
- ++i;
- toplevel->have_maxhorz = toplevel->have_maxvert = TRUE;
- }
-
- if (window->state & GDK_SURFACE_STATE_ABOVE)
- {
- atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_WM_STATE_ABOVE");
- ++i;
- }
-
- if (window->state & GDK_SURFACE_STATE_BELOW)
- {
- atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_WM_STATE_BELOW");
- ++i;
- }
-
- if (window->state & GDK_SURFACE_STATE_STICKY)
- {
- atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_WM_STATE_STICKY");
- ++i;
- toplevel->have_sticky = TRUE;
- }
-
- if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
- {
- atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_WM_STATE_FULLSCREEN");
- ++i;
- toplevel->have_fullscreen = TRUE;
- }
-
- if (window->modal_hint)
- {
- atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_WM_STATE_MODAL");
- ++i;
- }
-
- if (toplevel->skip_taskbar_hint)
- {
- atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_WM_STATE_SKIP_TASKBAR");
- ++i;
- }
-
- if (toplevel->skip_pager_hint)
- {
- atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_WM_STATE_SKIP_PAGER");
- ++i;
- }
-
- if (window->state & GDK_SURFACE_STATE_ICONIFIED)
- {
- atoms[i] = gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_WM_STATE_HIDDEN");
- ++i;
- toplevel->have_hidden = TRUE;
- }
-
- if (i > 0)
- {
- XChangeProperty (xdisplay,
- xwindow,
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
- XA_ATOM, 32, PropModeReplace,
- (guchar*) atoms, i);
- }
- else
- {
- XDeleteProperty (xdisplay,
- xwindow,
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"));
- }
-
- if (window->state & GDK_SURFACE_STATE_STICKY)
- {
- atoms[0] = 0xFFFFFFFF;
- XChangeProperty (xdisplay,
- xwindow,
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"),
- XA_CARDINAL, 32, PropModeReplace,
- (guchar*) atoms, 1);
- toplevel->on_all_desktops = TRUE;
- }
- else
- {
- XDeleteProperty (xdisplay,
- xwindow,
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"));
- }
-
- toplevel->map_serial = NextRequest (xdisplay);
-}
-
-static void
-gdk_surface_x11_show (GdkSurface *window, gboolean already_mapped)
-{
- GdkDisplay *display;
- GdkX11Display *display_x11;
- GdkToplevelX11 *toplevel;
- Display *xdisplay = GDK_SURFACE_XDISPLAY (window);
- Window xwindow = GDK_SURFACE_XID (window);
-
- if (!already_mapped)
- set_initial_hints (window);
-
- if (WINDOW_IS_TOPLEVEL (window))
- {
- display = gdk_surface_get_display (window);
- display_x11 = GDK_X11_DISPLAY (display);
- toplevel = _gdk_x11_surface_get_toplevel (window);
-
- if (toplevel->user_time != 0 &&
- display_x11->user_time != 0 &&
- XSERVER_TIME_IS_LATER (display_x11->user_time, toplevel->user_time))
- gdk_x11_surface_set_user_time (window, display_x11->user_time);
- }
-
- XMapWindow (xdisplay, xwindow);
-
- /* Fullscreen on current monitor is the default, no need to apply this mode
- * when mapping a window. This also ensures that the default behavior remains
- * consistent with pre-fullscreen mode implementation.
- */
- if (window->fullscreen_mode != GDK_FULLSCREEN_ON_CURRENT_MONITOR)
- gdk_x11_surface_apply_fullscreen_mode (window);
-}
-
-static void
-gdk_surface_x11_hide (GdkSurface *window)
-{
- /* We'll get the unmap notify eventually, and handle it then,
- * but checking here makes things more consistent if we are
- * just doing stuff ourself.
- */
- _gdk_x11_surface_grab_check_unmap (window,
- NextRequest (GDK_SURFACE_XDISPLAY (window)));
-
- /* You can't simply unmap toplevel windows. */
- switch (window->window_type)
- {
- case GDK_SURFACE_TOPLEVEL:
- case GDK_SURFACE_TEMP: /* ? */
- gdk_surface_withdraw (window);
- return;
-
- case GDK_SURFACE_FOREIGN:
- case GDK_SURFACE_CHILD:
- default:
- break;
- }
-
- _gdk_surface_clear_update_area (window);
-
- XUnmapWindow (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window));
-}
-
-static void
-gdk_surface_x11_withdraw (GdkSurface *window)
-{
- if (!window->destroyed)
- {
- if (GDK_SURFACE_IS_MAPPED (window))
- gdk_synthesize_window_state (window,
- 0,
- GDK_SURFACE_STATE_WITHDRAWN);
-
- g_assert (!GDK_SURFACE_IS_MAPPED (window));
-
- XWithdrawWindow (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window), 0);
- }
-}
-
-static inline void
-window_x11_move (GdkSurface *window,
- gint x,
- gint y)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- XMoveWindow (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- x * impl->window_scale, y * impl->window_scale);
-
- if (impl->override_redirect)
- {
- window->x = x;
- window->y = y;
- }
-}
-
-static inline void
-window_x11_resize (GdkSurface *window,
- gint width,
- gint height)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (width < 1)
- width = 1;
-
- if (height < 1)
- height = 1;
-
- window_pre_damage (window);
-
- XResizeWindow (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- width * impl->window_scale, height * impl->window_scale);
-
- if (impl->override_redirect)
- {
- impl->unscaled_width = width * impl->window_scale;
- impl->unscaled_height = height * impl->window_scale;
- window->width = width;
- window->height = height;
- _gdk_x11_surface_update_size (GDK_SURFACE_IMPL_X11 (window->impl));
- }
- else
- {
- if (width * impl->window_scale != impl->unscaled_width || height * impl->window_scale != impl->unscaled_height)
- window->resize_count += 1;
- }
-}
-
-static inline void
-window_x11_move_resize (GdkSurface *window,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (width < 1)
- width = 1;
-
- if (height < 1)
- height = 1;
-
- window_pre_damage (window);
-
- XMoveResizeWindow (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- x * impl->window_scale, y * impl->window_scale,
- width * impl->window_scale, height * impl->window_scale);
-
- if (impl->override_redirect)
- {
- window->x = x;
- window->y = y;
-
- impl->unscaled_width = width * impl->window_scale;
- impl->unscaled_height = height * impl->window_scale;
- window->width = width;
- window->height = height;
-
- _gdk_x11_surface_update_size (GDK_SURFACE_IMPL_X11 (window->impl));
- }
- else
- {
- if (width * impl->window_scale != impl->unscaled_width || height * impl->window_scale != impl->unscaled_height)
- window->resize_count += 1;
- }
-}
-
-static void
-gdk_surface_x11_move_resize (GdkSurface *window,
- gboolean with_move,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- if (with_move && (width < 0 && height < 0))
- window_x11_move (window, x, y);
- else
- {
- if (with_move)
- window_x11_move_resize (window, x, y, width, height);
- else
- window_x11_resize (window, width, height);
- }
-}
-
-void
-_gdk_x11_surface_set_window_scale (GdkSurface *window,
- int scale)
-{
- GdkSurfaceImplX11 *impl;
- GdkToplevelX11 *toplevel;
- GdkSurfaceHints geom_mask;
-
- impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- impl->window_scale = scale;
- if (impl->cairo_surface)
- cairo_surface_set_device_scale (impl->cairo_surface, impl->window_scale, impl->window_scale);
- _gdk_surface_update_size (window);
-
- toplevel = _gdk_x11_surface_get_toplevel (window);
- if (toplevel && window->window_type != GDK_SURFACE_FOREIGN)
- {
- /* These are affected by window scale: */
- geom_mask = toplevel->last_geometry_hints_mask &
- (GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE | GDK_HINT_BASE_SIZE | GDK_HINT_RESIZE_INC);
- if (geom_mask)
- gdk_surface_set_geometry_hints (window,
- &toplevel->last_geometry_hints,
- geom_mask);
- }
-
- if (window->window_type == GDK_SURFACE_FOREIGN)
- XMoveWindow (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- window->x * impl->window_scale,
- window->y * impl->window_scale);
- else
- {
- if (impl->override_redirect)
- {
- impl->unscaled_width = window->width * impl->window_scale;
- impl->unscaled_height = window->height * impl->window_scale;
- }
-
- XResizeWindow (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- window->width * impl->window_scale,
- window->height * impl->window_scale);
- }
-
- gdk_surface_invalidate_rect (window, NULL, TRUE);
-}
-
-static void
-gdk_surface_x11_raise (GdkSurface *window)
-{
- XRaiseWindow (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XID (window));
-}
-
-static void
-gdk_surface_x11_restack_toplevel (GdkSurface *window,
- GdkSurface *sibling,
- gboolean above)
-{
- XWindowChanges changes;
-
- changes.sibling = GDK_SURFACE_XID (sibling);
- changes.stack_mode = above ? Above : Below;
- XReconfigureWMWindow (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- gdk_x11_screen_get_screen_number (GDK_SURFACE_SCREEN (window)),
- CWStackMode | CWSibling, &changes);
-}
-
-static void
-gdk_surface_x11_lower (GdkSurface *window)
-{
- XLowerWindow (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XID (window));
-}
-
-/**
- * gdk_x11_surface_move_to_current_desktop:
- * @window: (type GdkX11Surface): a #GdkSurface
- *
- * Moves the window to the correct workspace when running under a
- * window manager that supports multiple workspaces, as described
- * in the [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
- * Will not do anything if the window is already on all workspaces.
- */
-void
-gdk_x11_surface_move_to_current_desktop (GdkSurface *window)
-{
- GdkToplevelX11 *toplevel;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD);
-
- toplevel = _gdk_x11_surface_get_toplevel (window);
-
- if (toplevel->on_all_desktops)
- return;
-
- move_to_current_desktop (window);
-}
-
-static void
-move_to_current_desktop (GdkSurface *window)
-{
- guint32 desktop;
-
- desktop = gdk_x11_screen_get_current_desktop (GDK_SURFACE_SCREEN (window));
- gdk_x11_surface_move_to_desktop (window, desktop);
-}
-
-static guint32
-get_netwm_cardinal_property (GdkSurface *window,
- const gchar *name)
-{
- GdkX11Screen *x11_screen = GDK_SURFACE_SCREEN (window);
- GdkAtom atom;
- guint32 prop = 0;
- Atom type;
- gint format;
- gulong nitems;
- gulong bytes_after;
- guchar *data;
-
- atom = g_intern_static_string (name);
-
- if (!gdk_x11_screen_supports_net_wm_hint (x11_screen, atom))
- return 0;
-
- XGetWindowProperty (x11_screen->xdisplay,
- GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (window), name),
- 0, G_MAXLONG,
- False, XA_CARDINAL, &type, &format, &nitems,
- &bytes_after, &data);
- if (type == XA_CARDINAL)
- {
- prop = *(gulong *)data;
- XFree (data);
- }
-
- return prop;
-}
-
-/**
- * gdk_x11_surface_get_desktop:
- * @window: (type GdkX11Surface): a #GdkSurface
- *
- * Gets the number of the workspace @window is on.
- *
- * Returns: the current workspace of @window
- */
-guint32
-gdk_x11_surface_get_desktop (GdkSurface *window)
-{
- g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
-
- return get_netwm_cardinal_property (window, "_NET_WM_DESKTOP");
-}
-
-/**
- * gdk_x11_surface_move_to_desktop:
- * @window: (type GdkX11Surface): a #GdkSurface
- * @desktop: the number of the workspace to move the window to
- *
- * Moves the window to the given workspace when running unde a
- * window manager that supports multiple workspaces, as described
- * in the [Extended Window Manager Hints](http://www.freedesktop.org/Standards/wm-spec) specification.
- */
-void
-gdk_x11_surface_move_to_desktop (GdkSurface *window,
- guint32 desktop)
-{
- GdkAtom atom;
- XClientMessageEvent xclient;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- atom = g_intern_static_string ("_NET_WM_DESKTOP");
- if (!gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window), atom))
- return;
-
- memset (&xclient, 0, sizeof (xclient));
- xclient.type = ClientMessage;
- xclient.serial = 0;
- xclient.send_event = True;
- xclient.window = GDK_SURFACE_XID (window);
- xclient.message_type = gdk_x11_atom_to_xatom_for_display (GDK_SURFACE_DISPLAY (window), atom);
- xclient.format = 32;
-
- xclient.data.l[0] = desktop;
- xclient.data.l[1] = 1; /* source indication */
- xclient.data.l[2] = 0;
- xclient.data.l[3] = 0;
- xclient.data.l[4] = 0;
-
- XSendEvent (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XROOTWIN (window),
- False,
- SubstructureRedirectMask | SubstructureNotifyMask,
- (XEvent *)&xclient);
-}
-
-static void
-gdk_x11_surface_focus (GdkSurface *window,
- guint32 timestamp)
-{
- GdkDisplay *display;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- display = GDK_SURFACE_DISPLAY (window);
-
- if (gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
- g_intern_static_string ("_NET_ACTIVE_WINDOW")))
- {
- XClientMessageEvent xclient;
-
- memset (&xclient, 0, sizeof (xclient));
- xclient.type = ClientMessage;
- xclient.window = GDK_SURFACE_XID (window);
- xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display,
- "_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[2] = None; /* currently active window */
- xclient.data.l[3] = 0;
- xclient.data.l[4] = 0;
-
- XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XROOTWIN (window), False,
- SubstructureRedirectMask | SubstructureNotifyMask,
- (XEvent *)&xclient);
- }
- else
- {
- XRaiseWindow (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window));
-
- /* There is no way of knowing reliably whether we are viewable;
- * so trap errors asynchronously around the XSetInputFocus call
- */
- gdk_x11_display_error_trap_push (display);
- XSetInputFocus (GDK_DISPLAY_XDISPLAY (display),
- GDK_SURFACE_XID (window),
- RevertToParent,
- timestamp);
- gdk_x11_display_error_trap_pop_ignored (display);
- }
-}
-
-static void
-gdk_x11_surface_set_type_hint (GdkSurface *window,
- GdkSurfaceTypeHint hint)
-{
- GdkDisplay *display;
- Atom atom;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- display = gdk_surface_get_display (window);
-
- switch (hint)
- {
- case GDK_SURFACE_TYPE_HINT_DIALOG:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DIALOG");
- break;
- case GDK_SURFACE_TYPE_HINT_MENU:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_MENU");
- break;
- case GDK_SURFACE_TYPE_HINT_TOOLBAR:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR");
- break;
- case GDK_SURFACE_TYPE_HINT_UTILITY:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_UTILITY");
- break;
- case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_SPLASH");
- break;
- case GDK_SURFACE_TYPE_HINT_DOCK:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DOCK");
- break;
- case GDK_SURFACE_TYPE_HINT_DESKTOP:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DESKTOP");
- break;
- case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU");
- break;
- case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_POPUP_MENU");
- break;
- case GDK_SURFACE_TYPE_HINT_TOOLTIP:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLTIP");
- break;
- case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NOTIFICATION");
- break;
- case GDK_SURFACE_TYPE_HINT_COMBO:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_COMBO");
- break;
- case GDK_SURFACE_TYPE_HINT_DND:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DND");
- break;
- default:
- g_warning ("Unknown hint %d passed to gdk_surface_set_type_hint", hint);
- /* Fall thru */
- case GDK_SURFACE_TYPE_HINT_NORMAL:
- atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NORMAL");
- break;
- }
-
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
- XA_ATOM, 32, PropModeReplace,
- (guchar *)&atom, 1);
-}
-
-static GdkSurfaceTypeHint
-gdk_x11_surface_get_type_hint (GdkSurface *window)
-{
- GdkDisplay *display;
- GdkSurfaceTypeHint type;
- Atom type_return;
- gint format_return;
- gulong nitems_return;
- gulong bytes_after_return;
- guchar *data = NULL;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), GDK_SURFACE_TYPE_HINT_NORMAL);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return GDK_SURFACE_TYPE_HINT_NORMAL;
-
- type = GDK_SURFACE_TYPE_HINT_NORMAL;
-
- display = gdk_surface_get_display (window);
-
- if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
- 0, G_MAXLONG, False, XA_ATOM, &type_return,
- &format_return, &nitems_return, &bytes_after_return,
- &data) == Success)
- {
- if ((type_return == XA_ATOM) && (format_return == 32) &&
- (data) && (nitems_return == 1))
- {
- Atom atom = *(Atom*)data;
-
- if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DIALOG"))
- type = GDK_SURFACE_TYPE_HINT_DIALOG;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_MENU"))
- type = GDK_SURFACE_TYPE_HINT_MENU;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLBAR"))
- type = GDK_SURFACE_TYPE_HINT_TOOLBAR;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_UTILITY"))
- type = GDK_SURFACE_TYPE_HINT_UTILITY;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_SPLASH"))
- type = GDK_SURFACE_TYPE_HINT_SPLASHSCREEN;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DOCK"))
- type = GDK_SURFACE_TYPE_HINT_DOCK;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DESKTOP"))
- type = GDK_SURFACE_TYPE_HINT_DESKTOP;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"))
- type = GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_POPUP_MENU"))
- type = GDK_SURFACE_TYPE_HINT_POPUP_MENU;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_TOOLTIP"))
- type = GDK_SURFACE_TYPE_HINT_TOOLTIP;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_NOTIFICATION"))
- type = GDK_SURFACE_TYPE_HINT_NOTIFICATION;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_COMBO"))
- type = GDK_SURFACE_TYPE_HINT_COMBO;
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE_DND"))
- type = GDK_SURFACE_TYPE_HINT_DND;
- }
-
- if (type_return != None && data != NULL)
- XFree (data);
- }
-
- return type;
-}
-
-static void
-gdk_wmspec_change_state (gboolean add,
- GdkSurface *window,
- GdkAtom state1,
- GdkAtom state2)
-{
- GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
- XClientMessageEvent xclient;
-
-#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
-#define _NET_WM_STATE_ADD 1 /* add/set property */
-#define _NET_WM_STATE_TOGGLE 2 /* toggle property */
-
- memset (&xclient, 0, sizeof (xclient));
- xclient.type = ClientMessage;
- xclient.window = GDK_SURFACE_XID (window);
- xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE");
- xclient.format = 32;
- 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] = 1; /* source indication */
- xclient.data.l[4] = 0;
-
- XSendEvent (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XROOTWIN (window), False,
- SubstructureRedirectMask | SubstructureNotifyMask,
- (XEvent *)&xclient);
-}
-
-static void
-gdk_x11_surface_set_modal_hint (GdkSurface *window,
- gboolean modal)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- window->modal_hint = modal;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- gdk_wmspec_change_state (modal, window,
- g_intern_static_string ("_NET_WM_STATE_MODAL"),
- NULL);
-}
-
-static void
-gdk_x11_surface_set_skip_taskbar_hint (GdkSurface *window,
- gboolean skips_taskbar)
-{
- GdkToplevelX11 *toplevel;
-
- g_return_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- toplevel = _gdk_x11_surface_get_toplevel (window);
- toplevel->skip_taskbar_hint = skips_taskbar;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- gdk_wmspec_change_state (skips_taskbar, window,
- g_intern_static_string ("_NET_WM_STATE_SKIP_TASKBAR"),
- NULL);
-}
-
-static void
-gdk_x11_surface_set_skip_pager_hint (GdkSurface *window,
- gboolean skips_pager)
-{
- GdkToplevelX11 *toplevel;
-
- g_return_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- toplevel = _gdk_x11_surface_get_toplevel (window);
- toplevel->skip_pager_hint = skips_pager;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- gdk_wmspec_change_state (skips_pager, window,
- g_intern_static_string ("_NET_WM_STATE_SKIP_PAGER"),
- NULL);
-}
-
-static void
-gdk_x11_surface_set_urgency_hint (GdkSurface *window,
- gboolean urgent)
-{
- GdkToplevelX11 *toplevel;
-
- g_return_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- toplevel = _gdk_x11_surface_get_toplevel (window);
- toplevel->urgency_hint = urgent;
-
- update_wm_hints (window, FALSE);
-}
-
-static void
-gdk_x11_surface_set_geometry_hints (GdkSurface *window,
- const GdkGeometry *geometry,
- GdkSurfaceHints geom_mask)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
- XSizeHints size_hints;
- GdkToplevelX11 *toplevel;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- toplevel = _gdk_x11_surface_get_toplevel (window);
- if (toplevel)
- {
- if (geometry)
- toplevel->last_geometry_hints = *geometry;
- toplevel->last_geometry_hints_mask = geom_mask;
- }
-
- size_hints.flags = 0;
-
- if (geom_mask & GDK_HINT_POS)
- {
- size_hints.flags |= PPosition;
- /* We need to initialize the following obsolete fields because KWM
- * apparently uses these fields if they are non-zero.
- * #@#!#!$!.
- */
- size_hints.x = 0;
- size_hints.y = 0;
- }
-
- if (geom_mask & GDK_HINT_USER_POS)
- {
- size_hints.flags |= USPosition;
- }
-
- if (geom_mask & GDK_HINT_USER_SIZE)
- {
- size_hints.flags |= USSize;
- }
-
- if (geom_mask & GDK_HINT_MIN_SIZE)
- {
- size_hints.flags |= PMinSize;
- size_hints.min_width = geometry->min_width * impl->window_scale;
- size_hints.min_height = geometry->min_height * impl->window_scale;
- }
-
- if (geom_mask & GDK_HINT_MAX_SIZE)
- {
- size_hints.flags |= PMaxSize;
- size_hints.max_width = MAX (geometry->max_width, 1) * impl->window_scale;
- size_hints.max_height = MAX (geometry->max_height, 1) * impl->window_scale;
- }
-
- if (geom_mask & GDK_HINT_BASE_SIZE)
- {
- size_hints.flags |= PBaseSize;
- size_hints.base_width = geometry->base_width * impl->window_scale;
- size_hints.base_height = geometry->base_height * impl->window_scale;
- }
-
- if (geom_mask & GDK_HINT_RESIZE_INC)
- {
- size_hints.flags |= PResizeInc;
- size_hints.width_inc = geometry->width_inc * impl->window_scale;
- size_hints.height_inc = geometry->height_inc * impl->window_scale;
- }
- else if (impl->window_scale > 1)
- {
- size_hints.flags |= PResizeInc;
- size_hints.width_inc = impl->window_scale;
- size_hints.height_inc = impl->window_scale;
- }
-
- if (geom_mask & GDK_HINT_ASPECT)
- {
- size_hints.flags |= PAspect;
- if (geometry->min_aspect <= 1)
- {
- size_hints.min_aspect.x = 65536 * geometry->min_aspect;
- size_hints.min_aspect.y = 65536;
- }
- else
- {
- size_hints.min_aspect.x = 65536;
- size_hints.min_aspect.y = 65536 / geometry->min_aspect;;
- }
- if (geometry->max_aspect <= 1)
- {
- size_hints.max_aspect.x = 65536 * geometry->max_aspect;
- size_hints.max_aspect.y = 65536;
- }
- else
- {
- size_hints.max_aspect.x = 65536;
- size_hints.max_aspect.y = 65536 / geometry->max_aspect;;
- }
- }
-
- if (geom_mask & GDK_HINT_WIN_GRAVITY)
- {
- size_hints.flags |= PWinGravity;
- size_hints.win_gravity = geometry->win_gravity;
- }
-
- /* FIXME: Would it be better to delete this property if
- * geom_mask == 0? It would save space on the server
- */
- XSetWMNormalHints (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- &size_hints);
-}
-
-static void
-gdk_surface_get_geometry_hints (GdkSurface *window,
- GdkGeometry *geometry,
- GdkSurfaceHints *geom_mask)
-{
- GdkSurfaceImplX11 *impl;
- XSizeHints *size_hints;
- glong junk_supplied_mask = 0;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (geometry != NULL);
- g_return_if_fail (geom_mask != NULL);
-
- *geom_mask = 0;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- size_hints = XAllocSizeHints ();
- if (!size_hints)
- return;
-
- if (!XGetWMNormalHints (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- size_hints,
- &junk_supplied_mask))
- size_hints->flags = 0;
-
- if (size_hints->flags & PMinSize)
- {
- *geom_mask |= GDK_HINT_MIN_SIZE;
- geometry->min_width = size_hints->min_width / impl->window_scale;
- geometry->min_height = size_hints->min_height / impl->window_scale;
- }
-
- if (size_hints->flags & PMaxSize)
- {
- *geom_mask |= GDK_HINT_MAX_SIZE;
- geometry->max_width = MAX (size_hints->max_width, 1) / impl->window_scale;
- geometry->max_height = MAX (size_hints->max_height, 1) / impl->window_scale;
- }
-
- if (size_hints->flags & PResizeInc)
- {
- *geom_mask |= GDK_HINT_RESIZE_INC;
- geometry->width_inc = size_hints->width_inc / impl->window_scale;
- geometry->height_inc = size_hints->height_inc / impl->window_scale;
- }
-
- if (size_hints->flags & PAspect)
- {
- *geom_mask |= GDK_HINT_ASPECT;
-
- geometry->min_aspect = (gdouble) size_hints->min_aspect.x / (gdouble) size_hints->min_aspect.y;
- geometry->max_aspect = (gdouble) size_hints->max_aspect.x / (gdouble) size_hints->max_aspect.y;
- }
-
- if (size_hints->flags & PWinGravity)
- {
- *geom_mask |= GDK_HINT_WIN_GRAVITY;
- geometry->win_gravity = size_hints->win_gravity;
- }
-
- XFree (size_hints);
-}
-
-static gboolean
-utf8_is_latin1 (const gchar *str)
-{
- const char *p = str;
-
- while (*p)
- {
- gunichar ch = g_utf8_get_char (p);
-
- if (ch > 0xff)
- return FALSE;
-
- p = g_utf8_next_char (p);
- }
-
- return TRUE;
-}
-
-/* Set the property to @utf8_str as STRING if the @utf8_str is fully
- * convertable to STRING, otherwise, set it as compound text
- */
-static void
-set_text_property (GdkDisplay *display,
- Window xwindow,
- Atom property,
- const gchar *utf8_str)
-{
- gchar *prop_text = NULL;
- Atom prop_type;
- gint prop_length;
- gint prop_format;
- gboolean is_compound_text;
-
- if (utf8_is_latin1 (utf8_str))
- {
- prop_type = XA_STRING;
- prop_text = _gdk_x11_display_utf8_to_string_target (display, utf8_str);
- prop_length = prop_text ? strlen (prop_text) : 0;
- prop_format = 8;
- is_compound_text = FALSE;
- }
- else
- {
- GdkAtom gdk_type;
-
- gdk_x11_display_utf8_to_compound_text (display,
- utf8_str, &gdk_type, &prop_format,
- (guchar **)&prop_text, &prop_length);
- prop_type = gdk_x11_atom_to_xatom_for_display (display, gdk_type);
- is_compound_text = TRUE;
- }
-
- if (prop_text)
- {
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
- xwindow,
- property,
- prop_type, prop_format,
- PropModeReplace, (guchar *)prop_text,
- prop_length);
-
- if (is_compound_text)
- gdk_x11_free_compound_text ((guchar *)prop_text);
- else
- g_free (prop_text);
- }
-}
-
-/* Set WM_NAME and _NET_WM_NAME
- */
-static void
-set_wm_name (GdkDisplay *display,
- Window xwindow,
- const gchar *name)
-{
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME"),
- gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
- PropModeReplace, (guchar *)name, strlen (name));
-
- set_text_property (display, xwindow,
- gdk_x11_get_xatom_by_name_for_display (display, "WM_NAME"),
- name);
-}
-
-static void
-gdk_x11_surface_set_title (GdkSurface *window,
- const gchar *title)
-{
- GdkDisplay *display;
- Display *xdisplay;
- Window xwindow;
-
- g_return_if_fail (title != NULL);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- display = gdk_surface_get_display (window);
- xdisplay = GDK_DISPLAY_XDISPLAY (display);
- xwindow = GDK_SURFACE_XID (window);
-
- set_wm_name (display, xwindow, title);
-
- if (!gdk_surface_icon_name_set (window))
- {
- XChangeProperty (xdisplay, xwindow,
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
- gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
- PropModeReplace, (guchar *)title, strlen (title));
-
- set_text_property (display, xwindow,
- gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
- title);
- }
-}
-
-static void
-gdk_x11_surface_set_role (GdkSurface *window,
- const gchar *role)
-{
- GdkDisplay *display;
-
- display = gdk_surface_get_display (window);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (role)
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE"),
- XA_STRING, 8, PropModeReplace, (guchar *)role, strlen (role));
- else
- XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "WM_WINDOW_ROLE"));
-}
-
-static void
-gdk_x11_surface_set_startup_id (GdkSurface *window,
- const gchar *startup_id)
-{
- GdkDisplay *display;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- display = gdk_surface_get_display (window);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (startup_id)
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
- gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
- PropModeReplace, (unsigned char *)startup_id, strlen (startup_id));
- else
- XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"));
-}
-
-static void
-gdk_x11_surface_set_transient_for (GdkSurface *window,
- GdkSurface *parent)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- /* XSetTransientForHint() doesn't allow unsetting, so do it manually */
- if (parent && !GDK_SURFACE_DESTROYED (parent))
- XSetTransientForHint (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- GDK_SURFACE_XID (parent));
- else
- XDeleteProperty (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (window), "WM_TRANSIENT_FOR"));
-}
-
-GdkCursor *
-_gdk_x11_surface_get_cursor (GdkSurface *window)
-{
- GdkSurfaceImplX11 *impl;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), NULL);
-
- impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- return impl->cursor;
-}
-
-static void
-gdk_surface_x11_get_geometry (GdkSurface *window,
- gint *x,
- gint *y,
- gint *width,
- gint *height)
-{
- GdkSurfaceImplX11 *impl;
- Window root;
- gint tx;
- gint ty;
- guint twidth;
- guint theight;
- guint tborder_width;
- guint tdepth;
-
- if (!GDK_SURFACE_DESTROYED (window))
- {
- impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- XGetGeometry (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
-
- if (x)
- *x = tx / impl->window_scale;
- if (y)
- *y = ty / impl->window_scale;
- if (width)
- *width = twidth / impl->window_scale;
- if (height)
- *height = theight / impl->window_scale;
- }
-}
-
-static void
-gdk_surface_x11_get_root_coords (GdkSurface *window,
- gint x,
- gint y,
- gint *root_x,
- gint *root_y)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
- Window child;
- gint tx;
- gint ty;
-
- XTranslateCoordinates (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- GDK_SURFACE_XROOTWIN (window),
- x * impl->window_scale, y * impl->window_scale, &tx, &ty,
- &child);
-
- if (root_x)
- *root_x = tx / impl->window_scale;
- if (root_y)
- *root_y = ty / impl->window_scale;
-}
-
-static void
-gdk_x11_surface_get_frame_extents (GdkSurface *window,
- GdkRectangle *rect)
-{
- GdkDisplay *display;
- GdkSurfaceImplX11 *impl;
- Window xwindow;
- Window xparent;
- Window root;
- Window child;
- Window *children;
- guchar *data;
- Window *vroots;
- Atom type_return;
- guint nchildren;
- guint nvroots;
- gulong nitems_return;
- gulong bytes_after_return;
- gint format_return;
- gint i;
- guint ww, wh, wb, wd;
- gint wx, wy;
- gboolean got_frame_extents = FALSE;
-
- g_return_if_fail (rect != NULL);
-
- rect->x = 0;
- rect->y = 0;
- rect->width = 1;
- rect->height = 1;
-
- while (window->parent && (window->parent)->parent)
- window = window->parent;
-
- impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- /* Refine our fallback answer a bit using local information */
- rect->x = window->x * impl->window_scale;
- rect->y = window->y * impl->window_scale;
- rect->width = window->width * impl->window_scale;
- rect->height = window->height * impl->window_scale;
-
- if (GDK_SURFACE_DESTROYED (window) || impl->override_redirect)
- return;
-
- nvroots = 0;
- vroots = NULL;
-
- display = gdk_surface_get_display (window);
-
- gdk_x11_display_error_trap_push (display);
-
- xwindow = GDK_SURFACE_XID (window);
-
- /* first try: use _NET_FRAME_EXTENTS */
- if (gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
- g_intern_static_string ("_NET_FRAME_EXTENTS")) &&
- XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xwindow,
- gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_FRAME_EXTENTS"),
- 0, G_MAXLONG, False, XA_CARDINAL, &type_return,
- &format_return, &nitems_return, &bytes_after_return,
- &data)
- == Success)
- {
- if ((type_return == XA_CARDINAL) && (format_return == 32) &&
- (nitems_return == 4) && (data))
- {
- gulong *ldata = (gulong *) data;
- got_frame_extents = TRUE;
-
- /* try to get the real client window geometry */
- if (XGetGeometry (GDK_DISPLAY_XDISPLAY (display), xwindow,
- &root, &wx, &wy, &ww, &wh, &wb, &wd) &&
- XTranslateCoordinates (GDK_DISPLAY_XDISPLAY (display),
- xwindow, root, 0, 0, &wx, &wy, &child))
- {
- rect->x = wx;
- rect->y = wy;
- rect->width = ww;
- rect->height = wh;
- }
-
- /* _NET_FRAME_EXTENTS format is left, right, top, bottom */
- rect->x -= ldata[0];
- rect->y -= ldata[2];
- rect->width += ldata[0] + ldata[1];
- rect->height += ldata[2] + ldata[3];
- }
-
- if (data)
- XFree (data);
- }
-
- if (got_frame_extents)
- goto out;
-
- /* no frame extents property available, which means we either have a WM that
- is not EWMH compliant or is broken - try fallback and walk up the window
- tree to get our window's parent which hopefully is the window frame */
-
- /* use NETWM_VIRTUAL_ROOTS if available */
- root = GDK_SURFACE_XROOTWIN (window);
-
- if (gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
- g_intern_static_string ("_NET_VIRTUAL_ROOTS")) &&
- XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), root,
- gdk_x11_get_xatom_by_name_for_display (display,
- "_NET_VIRTUAL_ROOTS"),
- 0, G_MAXLONG, False, XA_WINDOW, &type_return,
- &format_return, &nitems_return, &bytes_after_return,
- &data)
- == Success)
- {
- if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
- {
- nvroots = nitems_return;
- vroots = (Window *)data;
- }
- }
-
- xparent = GDK_SURFACE_XID (window);
-
- do
- {
- xwindow = xparent;
-
- if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xwindow,
- &root, &xparent,
- &children, &nchildren))
- goto out;
-
- if (children)
- XFree (children);
-
- /* check virtual roots */
- for (i = 0; i < nvroots; i++)
- {
- if (xparent == vroots[i])
- {
- root = xparent;
- break;
- }
- }
- }
- while (xparent != root);
-
- if (XGetGeometry (GDK_DISPLAY_XDISPLAY (display), xwindow,
- &root, &wx, &wy, &ww, &wh, &wb, &wd))
- {
- rect->x = wx;
- rect->y = wy;
- rect->width = ww;
- rect->height = wh;
- }
-
- out:
- if (vroots)
- XFree (vroots);
-
- /* Here we extend the size to include the extra pixels if we round x/y down
- as well as round the size up when we divide by scale so that the returned
- size is guaranteed to cover the real pixels, but it may overshoot a bit
- in case the window is not positioned/sized according to the scale */
- rect->width = (rect->width + rect->x % impl->window_scale + impl->window_scale - 1) / impl->window_scale;
- rect->height = (rect->height + rect->y % impl->window_scale + impl->window_scale - 1) / impl->window_scale;
- rect->x = rect->x / impl->window_scale;
- rect->y = rect->y / impl->window_scale;
- gdk_x11_display_error_trap_pop_ignored (display);
-}
-
-static gboolean
-gdk_surface_x11_get_device_state (GdkSurface *window,
- GdkDevice *device,
- gdouble *x,
- gdouble *y,
- GdkModifierType *mask)
-{
- GdkSurface *child;
-
- if (GDK_SURFACE_DESTROYED (window))
- return FALSE;
-
- /*HIDPI: handle coords here?*/
- GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
- &child,
- NULL, NULL,
- x, y, mask);
- return child != NULL;
-}
-
-static GdkEventMask
-gdk_surface_x11_get_events (GdkSurface *window)
-{
- XWindowAttributes attrs;
- GdkEventMask event_mask;
- GdkEventMask filtered;
-
- if (GDK_SURFACE_DESTROYED (window))
- return 0;
- else
- {
- XGetWindowAttributes (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- &attrs);
- event_mask = x_event_mask_to_gdk_event_mask (attrs.your_event_mask);
- /* if property change was filtered out before, keep it filtered out */
- filtered = GDK_STRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK;
- window->event_mask = event_mask & ((window->event_mask & filtered) | ~filtered);
-
- return event_mask;
- }
-}
-static void
-gdk_surface_x11_set_events (GdkSurface *window,
- GdkEventMask event_mask)
-{
- long xevent_mask = 0;
-
- if (!GDK_SURFACE_DESTROYED (window))
- {
- GdkX11Display *display_x11;
-
- if (GDK_SURFACE_XID (window) != GDK_SURFACE_XROOTWIN (window))
- xevent_mask = StructureNotifyMask | PropertyChangeMask;
-
- display_x11 = GDK_X11_DISPLAY (gdk_surface_get_display (window));
- gdk_x11_event_source_select_events ((GdkEventSource *) display_x11->event_source,
- GDK_SURFACE_XID (window), event_mask,
- xevent_mask);
- }
-}
-
-static inline void
-do_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y,
- gint shape)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (shape_region == NULL)
- {
- /* Use NULL mask to unset the shape */
- if (shape == ShapeBounding
- ? gdk_display_supports_shapes (GDK_SURFACE_DISPLAY (window))
- : gdk_display_supports_input_shapes (GDK_SURFACE_DISPLAY (window)))
- {
- XShapeCombineMask (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- shape,
- 0, 0,
- None,
- ShapeSet);
- }
- return;
- }
-
- if (shape == ShapeBounding
- ? gdk_display_supports_shapes (GDK_SURFACE_DISPLAY (window))
- : gdk_display_supports_input_shapes (GDK_SURFACE_DISPLAY (window)))
- {
- gint n_rects = 0;
- XRectangle *xrects = NULL;
-
- _gdk_x11_region_get_xrectangles (shape_region,
- 0, 0, impl->window_scale,
- &xrects, &n_rects);
-
- XShapeCombineRectangles (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- shape,
- offset_x * impl->window_scale,
- offset_y * impl->window_scale,
- xrects, n_rects,
- ShapeSet,
- YXBanded);
-
- g_free (xrects);
- }
-}
-
-static void
-gdk_surface_x11_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
- do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeBounding);
-}
-
-static void
-gdk_surface_x11_input_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
-#ifdef ShapeInput
- do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeInput);
-#endif
-}
-
-static void
-gdk_x11_surface_set_accept_focus (GdkSurface *window,
- gboolean accept_focus)
-{
- accept_focus = accept_focus != FALSE;
-
- if (window->accept_focus != accept_focus)
- {
- window->accept_focus = accept_focus;
-
- if (!GDK_SURFACE_DESTROYED (window) &&
- WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- update_wm_hints (window, FALSE);
- }
-}
-
-static void
-gdk_x11_surface_set_focus_on_map (GdkSurface *window,
- gboolean focus_on_map)
-{
- focus_on_map = focus_on_map != FALSE;
-
- if (window->focus_on_map != focus_on_map)
- {
- window->focus_on_map = focus_on_map;
-
- if ((!GDK_SURFACE_DESTROYED (window)) &&
- (!window->focus_on_map) &&
- WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- gdk_x11_surface_set_user_time (window, 0);
- }
-}
-
-/**
- * gdk_x11_surface_set_user_time:
- * @window: (type GdkX11Surface): A toplevel #GdkSurface
- * @timestamp: An XServer timestamp to which the property should be set
- *
- * The application can use this call to update the _NET_WM_USER_TIME
- * property on a toplevel window. This property stores an Xserver
- * time which represents the time of the last user input event
- * received for this window. This property may be used by the window
- * manager to alter the focus, stacking, and/or placement behavior of
- * windows when they are mapped depending on whether the new window
- * was created by a user action or is a "pop-up" window activated by a
- * timer or some other event.
- *
- * Note that this property is automatically updated by GDK, so this
- * function should only be used by applications which handle input
- * events bypassing GDK.
- **/
-void
-gdk_x11_surface_set_user_time (GdkSurface *window,
- guint32 timestamp)
-{
- GdkDisplay *display;
- GdkX11Display *display_x11;
- GdkToplevelX11 *toplevel;
- glong timestamp_long = (glong)timestamp;
- Window xid;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- display = gdk_surface_get_display (window);
- display_x11 = GDK_X11_DISPLAY (display);
- toplevel = _gdk_x11_surface_get_toplevel (window);
-
- if (!toplevel)
- {
- g_warning ("gdk_surface_set_user_time called on non-toplevel\n");
- return;
- }
-
- if (toplevel->focus_window != None &&
- gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
- g_intern_static_string ("_NET_WM_USER_TIME_WINDOW")))
- xid = toplevel->focus_window;
- else
- xid = GDK_SURFACE_XID (window);
-
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display), xid,
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_USER_TIME"),
- XA_CARDINAL, 32, PropModeReplace,
- (guchar *)×tamp_long, 1);
-
- if (timestamp_long != GDK_CURRENT_TIME &&
- (display_x11->user_time == GDK_CURRENT_TIME ||
- XSERVER_TIME_IS_LATER (timestamp_long, display_x11->user_time)))
- display_x11->user_time = timestamp_long;
-
- if (toplevel)
- toplevel->user_time = timestamp_long;
-}
-
-/**
- * gdk_x11_surface_set_utf8_property:
- * @window: (type GdkX11Surface): a #GdkSurface
- * @name: Property name, will be interned as an X atom
- * @value: (allow-none): Property value, or %NULL to delete
- *
- * 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.
- */
-void
-gdk_x11_surface_set_utf8_property (GdkSurface *window,
- const gchar *name,
- const gchar *value)
-{
- GdkDisplay *display;
-
- if (!WINDOW_IS_TOPLEVEL (window))
- return;
-
- display = gdk_surface_get_display (window);
-
- if (value != NULL)
- {
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
- GDK_SURFACE_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_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, name));
- }
-}
-
-static void
-gdk_x11_surface_set_shadow_width (GdkSurface *window,
- int left,
- int right,
- int top,
- int bottom)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
- Atom frame_extents;
- gulong data[4] = {
- left * impl->window_scale,
- right * impl->window_scale,
- top * impl->window_scale,
- bottom * impl->window_scale
- };
-
- frame_extents = gdk_x11_get_xatom_by_name_for_display (gdk_surface_get_display (window),
- "_GTK_FRAME_EXTENTS");
- XChangeProperty (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- frame_extents, XA_CARDINAL,
- 32, PropModeReplace,
- (guchar *) &data, 4);
-}
-
-/**
- * gdk_x11_surface_set_theme_variant:
- * @window: (type GdkX11Surface): a #GdkSurface
- * @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.
- */
-void
-gdk_x11_surface_set_theme_variant (GdkSurface *window,
- const char *variant)
-{
- gdk_x11_surface_set_utf8_property (window, "_GTK_THEME_VARIANT",
- variant ? variant : "");
-}
-
-#define GDK_SELECTION_MAX_SIZE(display) \
- MIN(262144, \
- XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0 \
- ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100 \
- : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
-
-static void
-gdk_surface_update_icon (GdkSurface *window,
- GList *icon_list)
-{
- GdkToplevelX11 *toplevel;
- GdkTexture *best_icon;
- GList *tmp_list;
- int best_size;
-
- toplevel = _gdk_x11_surface_get_toplevel (window);
-
- if (toplevel->icon_pixmap != NULL)
- {
- cairo_surface_destroy (toplevel->icon_pixmap);
- toplevel->icon_pixmap = NULL;
- }
-
- if (toplevel->icon_mask != NULL)
- {
- cairo_surface_destroy (toplevel->icon_mask);
- toplevel->icon_mask = NULL;
- }
-
-#define IDEAL_SIZE 48
-
- best_size = G_MAXINT;
- best_icon = NULL;
- for (tmp_list = icon_list; tmp_list; tmp_list = tmp_list->next)
- {
- GdkTexture *texture = tmp_list->data;
- int this;
-
- /* average width and height - if someone passes in a rectangular
- * icon they deserve what they get.
- */
- this = gdk_texture_get_width (texture) + gdk_texture_get_height (texture);
- this /= 2;
-
- if (best_icon == NULL)
- {
- best_icon = texture;
- best_size = this;
- }
- else
- {
- /* icon is better if it's 32 pixels or larger, and closer to
- * the ideal size than the current best.
- */
- if (this >= 32 &&
- (ABS (best_size - IDEAL_SIZE) <
- ABS (this - IDEAL_SIZE)))
- {
- best_icon = texture;
- best_size = this;
- }
- }
- }
-
- if (best_icon)
- {
- int width = gdk_texture_get_width (best_icon);
- int height = gdk_texture_get_height (best_icon);
- cairo_surface_t *surface;
- cairo_t *cr;
-
- toplevel->icon_pixmap = gdk_x11_surface_create_pixmap_surface (window, width, height);
-
- surface = gdk_texture_download_surface (best_icon);
-
- cr = cairo_create (toplevel->icon_pixmap);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source_surface (cr, surface, 0, 0);
- if (cairo_surface_get_content (surface) == CAIRO_CONTENT_COLOR_ALPHA)
- {
- /* Saturate the image, so it has bilevel alpha */
- cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
- cairo_paint (cr);
- cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE);
- cairo_paint (cr);
- cairo_pop_group_to_source (cr);
- }
- cairo_paint (cr);
- cairo_destroy (cr);
-
- if (cairo_surface_get_content (surface) == CAIRO_CONTENT_COLOR_ALPHA)
- {
- GdkDisplay *display = gdk_surface_get_display (window);
-
- toplevel->icon_mask = _gdk_x11_display_create_bitmap_surface (display, width, height);
-
- cr = cairo_create (toplevel->icon_mask);
- cairo_set_source_surface (cr, surface, 0, 0);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint (cr);
- cairo_destroy (cr);
- }
-
- cairo_surface_destroy (surface);
- }
-
- update_wm_hints (window, FALSE);
-}
-
-static void
-gdk_x11_surface_set_icon_list (GdkSurface *window,
- GList *textures)
-{
- gulong *data;
- gulong *p;
- gint size;
- GList *l;
- gint width, height;
- GdkTexture *texture;
- GdkDisplay *display;
- gint i, n;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- display = gdk_surface_get_display (window);
-
- size = 0;
- n = 0;
- for (l = textures; l != NULL; l = l->next)
- {
- texture = l->data;
-
- width = gdk_texture_get_width (texture);
- height = gdk_texture_get_height (texture);
-
- /* silently ignore overlarge icons */
- if (size + 2 + width * height > GDK_SELECTION_MAX_SIZE(display))
- break;
-
- n++;
- size += 2 + width * height;
- }
-
- data = g_malloc (size * sizeof (gulong));
-
- p = data;
- for (l = textures; l != NULL && n > 0; l = l->next)
- {
- texture = l->data;
-
- width = gdk_texture_get_width (texture);
- height = gdk_texture_get_height (texture);
-
- *p++ = width;
- *p++ = height;
-
- gdk_texture_download (texture, (guchar *) p, width * 4);
- if (sizeof (gulong) > 4)
- {
- i = width * height;
- while (i-- > 0)
- p[i] = ((guint32 *) p)[i];
- }
-
- p += width * height;
- n--;
- }
-
- if (size > 0)
- {
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
- GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"),
- XA_CARDINAL, 32,
- PropModeReplace,
- (guchar*) data, size);
- }
- else
- {
- XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
- GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON"));
- }
-
- g_free (data);
-
- gdk_surface_update_icon (window, textures);
-}
-
-static gboolean
-gdk_surface_icon_name_set (GdkSurface *window)
-{
- return GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (window),
- g_quark_from_static_string ("gdk-icon-name-set")));
-}
-
-static void
-gdk_x11_surface_set_icon_name (GdkSurface *window,
- const gchar *name)
-{
- GdkDisplay *display;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- display = gdk_surface_get_display (window);
-
- g_object_set_qdata (G_OBJECT (window), g_quark_from_static_string ("gdk-icon-name-set"),
- GUINT_TO_POINTER (name != NULL));
-
- if (name != NULL)
- {
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
- GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"),
- gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
- PropModeReplace, (guchar *)name, strlen (name));
-
- set_text_property (display, GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"),
- name);
- }
- else
- {
- XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
- GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_ICON_NAME"));
- XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
- GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "WM_ICON_NAME"));
- }
-}
-
-static void
-gdk_x11_surface_iconify (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- XIconifyWindow (GDK_SURFACE_XDISPLAY (window),
- GDK_SURFACE_XID (window),
- gdk_x11_screen_get_screen_number (GDK_SURFACE_SCREEN (window)));
- }
- else
- {
- /* Flip our client side flag, the real work happens on map. */
- gdk_synthesize_window_state (window,
- 0,
- GDK_SURFACE_STATE_ICONIFIED);
- gdk_wmspec_change_state (TRUE, window,
- g_intern_static_string ("_NET_WM_STATE_HIDDEN"),
- NULL);
- }
-}
-
-static void
-gdk_x11_surface_deiconify (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- gdk_surface_show (window);
- gdk_wmspec_change_state (FALSE, window,
- g_intern_static_string ("_NET_WM_STATE_HIDDEN"),
- NULL);
- }
- else
- {
- /* Flip our client side flag, the real work happens on map. */
- gdk_synthesize_window_state (window,
- GDK_SURFACE_STATE_ICONIFIED,
- 0);
- gdk_wmspec_change_state (FALSE, window,
- g_intern_static_string ("_NET_WM_STATE_HIDDEN"),
- NULL);
- }
-}
-
-static void
-gdk_x11_surface_stick (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- /* "stick" means stick to all desktops _and_ do not scroll with the
- * viewport. i.e. glue to the monitor glass in all cases.
- */
-
- XClientMessageEvent xclient;
-
- /* Request stick during viewport scroll */
- gdk_wmspec_change_state (TRUE, window,
- g_intern_static_string ("_NET_WM_STATE_STICKY"),
- NULL);
-
- /* Request desktop 0xFFFFFFFF */
- memset (&xclient, 0, sizeof (xclient));
- xclient.type = ClientMessage;
- xclient.window = GDK_SURFACE_XID (window);
- xclient.display = GDK_SURFACE_XDISPLAY (window);
- xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (window),
- "_NET_WM_DESKTOP");
- xclient.format = 32;
-
- xclient.data.l[0] = 0xFFFFFFFF;
- xclient.data.l[1] = 0;
- xclient.data.l[2] = 0;
- xclient.data.l[3] = 0;
- xclient.data.l[4] = 0;
-
- XSendEvent (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XROOTWIN (window), False,
- SubstructureRedirectMask | SubstructureNotifyMask,
- (XEvent *)&xclient);
- }
- else
- {
- /* Flip our client side flag, the real work happens on map. */
- gdk_synthesize_window_state (window,
- 0,
- GDK_SURFACE_STATE_STICKY);
- }
-}
-
-static void
-gdk_x11_surface_unstick (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- /* Request unstick from viewport */
- gdk_wmspec_change_state (FALSE, window,
- g_intern_static_string ("_NET_WM_STATE_STICKY"),
- NULL);
-
- move_to_current_desktop (window);
- }
- else
- {
- /* Flip our client side flag, the real work happens on map. */
- gdk_synthesize_window_state (window,
- GDK_SURFACE_STATE_STICKY,
- 0);
-
- }
-}
-
-static void
-gdk_x11_surface_maximize (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- gdk_wmspec_change_state (TRUE, window,
- g_intern_static_string ("_NET_WM_STATE_MAXIMIZED_VERT"),
- g_intern_static_string ("_NET_WM_STATE_MAXIMIZED_HORZ"));
- else
- gdk_synthesize_window_state (window,
- 0,
- GDK_SURFACE_STATE_MAXIMIZED);
-}
-
-static void
-gdk_x11_surface_unmaximize (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- gdk_wmspec_change_state (FALSE, window,
- g_intern_static_string ("_NET_WM_STATE_MAXIMIZED_VERT"),
- g_intern_static_string ("_NET_WM_STATE_MAXIMIZED_HORZ"));
- else
- gdk_synthesize_window_state (window,
- GDK_SURFACE_STATE_MAXIMIZED,
- 0);
-}
-
-static void
-gdk_x11_surface_apply_fullscreen_mode (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- /* _NET_WM_FULLSCREEN_MONITORS gives an indication to the window manager as
- * to which monitors so span across when the window is fullscreen, but it's
- * not a state in itself so this would have no effect if the window is not
- * mapped.
- */
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- XClientMessageEvent xclient;
- gint monitors[4];
- gint i;
-
- memset (&xclient, 0, sizeof (xclient));
- xclient.type = ClientMessage;
- xclient.window = GDK_SURFACE_XID (window);
- xclient.display = GDK_SURFACE_XDISPLAY (window);
- xclient.format = 32;
-
- switch (window->fullscreen_mode)
- {
- case GDK_FULLSCREEN_ON_CURRENT_MONITOR:
-
- /* FIXME: This is not part of the EWMH spec!
- *
- * There is no documented mechanism to remove the property
- * _NET_WM_FULLSCREEN_MONITORS once set, so we use use a set of
- * invalid, largest possible value.
- *
- * When given values larger than actual possible monitor values, most
- * window managers who support the _NET_WM_FULLSCREEN_MONITORS spec
- * will simply unset _NET_WM_FULLSCREEN_MONITORS and revert to their
- * default behavior.
- *
- * Successfully tested on mutter/metacity, kwin, compiz and xfwm4.
- *
- * Note, this (non documented) mechanism is unlikely to be an issue
- * as it's used only for transitionning back from "all monitors" to
- * "current monitor" mode.
- *
- * Applications who don't change the default mode won't trigger this
- * mechanism.
- */
- for (i = 0; i < 4; ++i)
- xclient.data.l[i] = G_MAXLONG;
-
- break;
-
- case GDK_FULLSCREEN_ON_ALL_MONITORS:
-
- _gdk_x11_screen_get_edge_monitors (GDK_SURFACE_SCREEN (window),
- &monitors[0],
- &monitors[1],
- &monitors[2],
- &monitors[3]);
- /* Translate all 4 monitors from the GDK set into XINERAMA indices */
- for (i = 0; i < 4; ++i)
- {
- xclient.data.l[i] = monitors[i];
- /* Sanity check, if XINERAMA is not available, we could have invalid
- * negative values for the XINERAMA indices.
- */
- if (xclient.data.l[i] < 0)
- {
- g_warning ("gdk_x11_surface_apply_fullscreen_mode: Invalid XINERAMA monitor index");
- return;
- }
- }
- break;
-
- default:
- g_warning ("gdk_x11_surface_apply_fullscreen_mode: Unhandled fullscreen mode %d",
- window->fullscreen_mode);
- return;
- }
-
- /* Send fullscreen monitors client message */
- xclient.data.l[4] = 1; /* source indication */
- xclient.message_type = gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (window),
- "_NET_WM_FULLSCREEN_MONITORS");
- XSendEvent (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XROOTWIN (window), False,
- SubstructureRedirectMask | SubstructureNotifyMask,
- (XEvent *)&xclient);
- }
-}
-
-static void
-gdk_x11_surface_fullscreen (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- gdk_wmspec_change_state (TRUE, window,
- g_intern_static_string ("_NET_WM_STATE_FULLSCREEN"),
- NULL);
- /* Actual XRandR layout may have change since we computed the fullscreen
- * monitors in GDK_FULLSCREEN_ON_ALL_MONITORS mode.
- */
- if (window->fullscreen_mode == GDK_FULLSCREEN_ON_ALL_MONITORS)
- gdk_x11_surface_apply_fullscreen_mode (window);
- }
- else
- gdk_synthesize_window_state (window,
- 0,
- GDK_SURFACE_STATE_FULLSCREEN);
-}
-
-static void
-gdk_x11_surface_fullscreen_on_monitor (GdkSurface *window,
- GdkMonitor *monitor)
-{
- GdkRectangle geom;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- gdk_monitor_get_geometry (monitor, &geom);
- gdk_surface_move (window, geom.x, geom.y);
-
- gdk_surface_set_fullscreen_mode (window, GDK_FULLSCREEN_ON_CURRENT_MONITOR);
- gdk_x11_surface_fullscreen (window);
-}
-
-static void
-gdk_x11_surface_unfullscreen (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- gdk_wmspec_change_state (FALSE, window,
- g_intern_static_string ("_NET_WM_STATE_FULLSCREEN"),
- NULL);
-
- else
- gdk_synthesize_window_state (window,
- GDK_SURFACE_STATE_FULLSCREEN,
- 0);
-}
-
-static void
-gdk_x11_surface_set_keep_above (GdkSurface *window,
- gboolean setting)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- if (setting)
- gdk_wmspec_change_state (FALSE, window,
- g_intern_static_string ("_NET_WM_STATE_BELOW"),
- NULL);
- gdk_wmspec_change_state (setting, window,
- g_intern_static_string ("_NET_WM_STATE_ABOVE"),
- NULL);
- }
- else
- gdk_synthesize_window_state (window,
- setting ? GDK_SURFACE_STATE_BELOW : GDK_SURFACE_STATE_ABOVE,
- setting ? GDK_SURFACE_STATE_ABOVE : 0);
-}
-
-static void
-gdk_x11_surface_set_keep_below (GdkSurface *window, gboolean setting)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- if (setting)
- gdk_wmspec_change_state (FALSE, window,
- g_intern_static_string ("_NET_WM_STATE_ABOVE"),
- NULL);
- gdk_wmspec_change_state (setting, window,
- g_intern_static_string ("_NET_WM_STATE_BELOW"),
- NULL);
- }
- else
- gdk_synthesize_window_state (window,
- setting ? GDK_SURFACE_STATE_ABOVE : GDK_SURFACE_STATE_BELOW,
- setting ? GDK_SURFACE_STATE_BELOW : 0);
-}
-
-static GdkSurface *
-gdk_x11_surface_get_group (GdkSurface *window)
-{
- GdkToplevelX11 *toplevel;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return NULL;
-
- toplevel = _gdk_x11_surface_get_toplevel (window);
-
- return toplevel->group_leader;
-}
-
-static void
-gdk_x11_surface_set_group (GdkSurface *window,
- GdkSurface *leader)
-{
- GdkToplevelX11 *toplevel;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (GDK_SURFACE_TYPE (window) != GDK_SURFACE_CHILD);
- g_return_if_fail (leader == NULL || GDK_IS_SURFACE (leader));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- (leader != NULL && GDK_SURFACE_DESTROYED (leader)) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- toplevel = _gdk_x11_surface_get_toplevel (window);
-
- if (leader == NULL)
- leader = gdk_display_get_default_group (gdk_surface_get_display (window));
-
- if (toplevel->group_leader != leader)
- {
- if (toplevel->group_leader)
- g_object_unref (toplevel->group_leader);
- toplevel->group_leader = g_object_ref (leader);
- (_gdk_x11_surface_get_toplevel (leader))->is_leader = TRUE;
- }
-
- update_wm_hints (window, FALSE);
-}
-
-static MotifWmHints *
-gdk_surface_get_mwm_hints (GdkSurface *window)
-{
- GdkDisplay *display;
- Atom hints_atom = None;
- guchar *data;
- Atom type;
- gint format;
- gulong nitems;
- gulong bytes_after;
-
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- display = gdk_surface_get_display (window);
-
- hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
-
- XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XID (window),
- hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
- False, AnyPropertyType, &type, &format, &nitems,
- &bytes_after, &data);
-
- if (type == None)
- return NULL;
-
- return (MotifWmHints *)data;
-}
-
-static void
-gdk_surface_set_mwm_hints (GdkSurface *window,
- MotifWmHints *new_hints)
-{
- GdkDisplay *display;
- Atom hints_atom = None;
- guchar *data;
- MotifWmHints *hints;
- Atom type;
- gint format;
- gulong nitems;
- gulong bytes_after;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- display = gdk_surface_get_display (window);
-
- hints_atom = gdk_x11_get_xatom_by_name_for_display (display, _XA_MOTIF_WM_HINTS);
-
- XGetWindowProperty (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XID (window),
- hints_atom, 0, sizeof (MotifWmHints)/sizeof (long),
- False, AnyPropertyType, &type, &format, &nitems,
- &bytes_after, &data);
-
- if (type == None)
- hints = new_hints;
- else
- {
- hints = (MotifWmHints *)data;
-
- if (new_hints->flags & MWM_HINTS_FUNCTIONS)
- {
- hints->flags |= MWM_HINTS_FUNCTIONS;
- hints->functions = new_hints->functions;
- }
- if (new_hints->flags & MWM_HINTS_DECORATIONS)
- {
- hints->flags |= MWM_HINTS_DECORATIONS;
- hints->decorations = new_hints->decorations;
- }
- }
-
- XChangeProperty (GDK_SURFACE_XDISPLAY (window), GDK_SURFACE_XID (window),
- hints_atom, hints_atom, 32, PropModeReplace,
- (guchar *)hints, sizeof (MotifWmHints)/sizeof (long));
-
- if (hints != new_hints)
- XFree (hints);
-}
-
-static void
-gdk_x11_surface_set_decorations (GdkSurface *window,
- GdkWMDecoration decorations)
-{
- MotifWmHints hints;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- /* initialize to zero to avoid writing uninitialized data to socket */
- memset(&hints, 0, sizeof(hints));
- hints.flags = MWM_HINTS_DECORATIONS;
- hints.decorations = decorations;
-
- gdk_surface_set_mwm_hints (window, &hints);
-}
-
-static gboolean
-gdk_x11_surface_get_decorations(GdkSurface *window,
- GdkWMDecoration *decorations)
-{
- MotifWmHints *hints;
- gboolean result = FALSE;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return FALSE;
-
- hints = gdk_surface_get_mwm_hints (window);
-
- if (hints)
- {
- if (hints->flags & MWM_HINTS_DECORATIONS)
- {
- if (decorations)
- *decorations = hints->decorations;
- result = TRUE;
- }
-
- XFree (hints);
- }
-
- return result;
-}
-
-static void
-gdk_x11_surface_set_functions (GdkSurface *window,
- GdkWMFunction functions)
-{
- MotifWmHints hints;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- /* initialize to zero to avoid writing uninitialized data to socket */
- memset(&hints, 0, sizeof(hints));
- hints.flags = MWM_HINTS_FUNCTIONS;
- hints.functions = functions;
-
- gdk_surface_set_mwm_hints (window, &hints);
-}
-
-cairo_region_t *
-_gdk_x11_xwindow_get_shape (Display *xdisplay,
- Window window,
- gint scale,
- gint shape_type)
-{
- cairo_region_t *shape;
- GdkRectangle *rl;
- XRectangle *xrl;
- gint rn, ord, i;
-
- shape = NULL;
- rn = 0;
-
- /* 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 (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
- */
- g_warning ("non YXBanded shape masks not supported");
- XFree (xrl);
- return NULL;
- }
-
- /* NOTE: The scale divisions here may lose some precision if someone
- else set the shape to be non-scale precision */
- rl = g_new (GdkRectangle, rn);
- for (i = 0; i < rn; i++)
- {
- rl[i].x = xrl[i].x / scale;
- rl[i].y = xrl[i].y / scale;
- rl[i].width = xrl[i].width / scale;
- rl[i].height = xrl[i].height / scale;
- }
- XFree (xrl);
-
- shape = cairo_region_create_rectangles (rl, rn);
- g_free (rl);
-
- return shape;
-}
-
-/* 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_send_message (GdkDisplay *display,
- GdkSurface *window,
- gint root_x,
- gint root_y,
- gint action,
- gint button)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
- XClientMessageEvent xclient;
-
- memset (&xclient, 0, sizeof (xclient));
- xclient.type = ClientMessage;
- xclient.window = GDK_SURFACE_XID (window);
- xclient.message_type =
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_MOVERESIZE");
- xclient.format = 32;
- xclient.data.l[0] = root_x * impl->window_scale;
- xclient.data.l[1] = root_y * impl->window_scale;
- xclient.data.l[2] = action;
- xclient.data.l[3] = button;
- xclient.data.l[4] = 1; /* source indication */
-
- XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XROOTWIN (window), False,
- SubstructureRedirectMask | SubstructureNotifyMask,
- (XEvent *)&xclient);
-}
-
-static void
-handle_wmspec_button_release (GdkDisplay *display,
- const XEvent *xevent)
-{
- GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
- GdkSurface *window;
-
-#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_surface_lookup_for_display (display, xidev->event);
- else
-#endif
- window = gdk_x11_surface_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);
- }
- }
-}
-
-static void
-wmspec_moveresize (GdkSurface *window,
- gint direction,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
-
- if (button != 0)
- gdk_seat_ungrab (gdk_device_get_seat (device)); /* Release passive grab */
- GDK_X11_DISPLAY (display)->wm_moveresize_button = button;
-
- wmspec_send_message (display, window, root_x, root_y, direction, button);
-}
-
-static void
-wmspec_resize_drag (GdkSurface *window,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- gint direction;
-
- if (button == 0)
- direction = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
- else
- switch (edge)
- {
- /* Let the compiler turn a switch into a table, instead
- * of doing the table manually, this way is easier to verify.
- */
- case GDK_SURFACE_EDGE_NORTH_WEST:
- direction = _NET_WM_MOVERESIZE_SIZE_TOPLEFT;
- break;
-
- case GDK_SURFACE_EDGE_NORTH:
- direction = _NET_WM_MOVERESIZE_SIZE_TOP;
- break;
-
- case GDK_SURFACE_EDGE_NORTH_EAST:
- direction = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT;
- break;
-
- case GDK_SURFACE_EDGE_WEST:
- direction = _NET_WM_MOVERESIZE_SIZE_LEFT;
- break;
-
- case GDK_SURFACE_EDGE_EAST:
- direction = _NET_WM_MOVERESIZE_SIZE_RIGHT;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH:
- direction = _NET_WM_MOVERESIZE_SIZE_BOTTOM;
- break;
-
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- direction = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT;
- break;
-
- default:
- g_warning ("gdk_surface_begin_resize_drag: bad resize edge %d!",
- edge);
- return;
- }
-
- wmspec_moveresize (window, direction, device, button, root_x, root_y, timestamp);
-}
-
-typedef struct _MoveResizeData MoveResizeData;
-
-struct _MoveResizeData
-{
- GdkDisplay *display;
-
- GdkSurface *moveresize_window;
- GdkSurface *moveresize_emulation_window;
- gboolean is_resize;
- GdkSurfaceEdge 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;
- GdkSurfaceHints moveresize_geom_mask;
- GdkGeometry moveresize_geometry;
- Time moveresize_process_time;
- XEvent *moveresize_pending_event;
-};
-
-static MoveResizeData *
-get_move_resize_data (GdkDisplay *display,
- gboolean create)
-{
- MoveResizeData *mv_resize;
- static GQuark move_resize_quark = 0;
-
- if (!move_resize_quark)
- move_resize_quark = g_quark_from_static_string ("gdk-window-moveresize");
-
- mv_resize = g_object_get_qdata (G_OBJECT (display), move_resize_quark);
-
- if (!mv_resize && create)
- {
- mv_resize = g_new0 (MoveResizeData, 1);
- mv_resize->display = display;
-
- g_object_set_qdata (G_OBJECT (display), move_resize_quark, mv_resize);
- }
-
- return mv_resize;
-}
-
-static void
-check_maximize (MoveResizeData *mv_resize,
- gdouble x_root,
- gdouble y_root)
-{
- GdkSurfaceState state;
- gint y;
-
- if (mv_resize->is_resize)
- return;
-
- state = gdk_surface_get_state (mv_resize->moveresize_window);
-
- if (state & GDK_SURFACE_STATE_MAXIMIZED)
- return;
-
- y = mv_resize->moveresize_orig_y + (y_root - mv_resize->moveresize_y);
-
- if (y < 10)
- gdk_surface_maximize (mv_resize->moveresize_window);
-}
-
-static void
-check_unmaximize (MoveResizeData *mv_resize,
- gdouble x_root,
- gdouble y_root)
-{
- GdkSurfaceState state;
- gint dx, dy;
-
- if (mv_resize->is_resize)
- return;
-
- state = gdk_surface_get_state (mv_resize->moveresize_window);
-
- if ((state & (GDK_SURFACE_STATE_MAXIMIZED | GDK_SURFACE_STATE_TILED)) == 0)
- return;
-
- dx = x_root - mv_resize->moveresize_x;
- dy = y_root - mv_resize->moveresize_y;
-
- if (ABS (dx) > 20 || ABS (dy) > 20)
- gdk_surface_unmaximize (mv_resize->moveresize_window);
-}
-
-static void
-update_pos (MoveResizeData *mv_resize,
- gint new_root_x,
- gint new_root_y)
-{
- gint dx, dy;
-
- check_unmaximize (mv_resize, new_root_x, new_root_y);
- dx = new_root_x - mv_resize->moveresize_x;
- dy = new_root_y - mv_resize->moveresize_y;
-
- if (mv_resize->is_resize)
- {
- gint x, y, w, h;
-
- x = mv_resize->moveresize_orig_x;
- y = mv_resize->moveresize_orig_y;
-
- w = mv_resize->moveresize_orig_width;
- h = mv_resize->moveresize_orig_height;
-
- switch (mv_resize->resize_edge)
- {
- case GDK_SURFACE_EDGE_NORTH_WEST:
- x += dx;
- y += dy;
- w -= dx;
- h -= dy;
- break;
- case GDK_SURFACE_EDGE_NORTH:
- y += dy;
- h -= dy;
- break;
- case GDK_SURFACE_EDGE_NORTH_EAST:
- y += dy;
- h -= dy;
- w += dx;
- break;
- case GDK_SURFACE_EDGE_SOUTH_WEST:
- h += dy;
- x += dx;
- w -= dx;
- break;
- case GDK_SURFACE_EDGE_SOUTH_EAST:
- w += dx;
- h += dy;
- break;
- case GDK_SURFACE_EDGE_SOUTH:
- h += dy;
- break;
- case GDK_SURFACE_EDGE_EAST:
- w += dx;
- break;
- case GDK_SURFACE_EDGE_WEST:
- x += dx;
- w -= dx;
- break;
- default:
- break;
- }
-
- x = MAX (x, 0);
- y = MAX (y, 0);
- w = MAX (w, 1);
- h = MAX (h, 1);
-
- if (mv_resize->moveresize_geom_mask)
- {
- gdk_surface_constrain_size (&mv_resize->moveresize_geometry,
- mv_resize->moveresize_geom_mask,
- w, h, &w, &h);
- }
-
- gdk_surface_move_resize (mv_resize->moveresize_window, x, y, w, h);
- }
- else
- {
- gint x, y;
-
- x = mv_resize->moveresize_orig_x + dx;
- y = mv_resize->moveresize_orig_y + dy;
-
- gdk_surface_move (mv_resize->moveresize_window, x, y);
- }
-}
-
-static void
-finish_drag (MoveResizeData *mv_resize)
-{
- gdk_surface_destroy (mv_resize->moveresize_emulation_window);
- mv_resize->moveresize_emulation_window = NULL;
- g_clear_object (&mv_resize->moveresize_window);
- g_clear_pointer (&mv_resize->moveresize_pending_event, g_free);
-}
-
-static int
-lookahead_motion_predicate (Display *xdisplay,
- XEvent *event,
- XPointer arg)
-{
- gboolean *seen_release = (gboolean *)arg;
- GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
- MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
-
- if (*seen_release)
- return False;
-
- switch (event->xany.type)
- {
- case ButtonRelease:
- *seen_release = TRUE;
- break;
- case MotionNotify:
- mv_resize->moveresize_process_time = event->xmotion.time;
- break;
- default:
- break;
- }
-
- return False;
-}
-
-static gboolean
-moveresize_lookahead (MoveResizeData *mv_resize,
- const XEvent *event)
-{
- XEvent tmp_event;
- gboolean seen_release = FALSE;
-
- if (mv_resize->moveresize_process_time)
- {
- if (event->xmotion.time == mv_resize->moveresize_process_time)
- {
- mv_resize->moveresize_process_time = 0;
- return TRUE;
- }
- else
- return FALSE;
- }
-
- XCheckIfEvent (event->xany.display, &tmp_event,
- lookahead_motion_predicate, (XPointer) & seen_release);
-
- return mv_resize->moveresize_process_time == 0;
-}
-
-gboolean
-_gdk_x11_moveresize_handle_event (const XEvent *event)
-{
- guint button_mask = 0;
- GdkDisplay *display = gdk_x11_lookup_xdisplay (event->xany.display);
- MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
- GdkSurfaceImplX11 *impl;
-
- if (!mv_resize || !mv_resize->moveresize_window)
- {
- handle_wmspec_button_release (display, event);
- return FALSE;
- }
-
- impl = GDK_SURFACE_IMPL_X11 (mv_resize->moveresize_window->impl);
-
- if (mv_resize->moveresize_button != 0)
- button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1);
-
- switch (event->xany.type)
- {
- case MotionNotify:
- if (mv_resize->moveresize_window->resize_count > 0)
- {
- if (mv_resize->moveresize_pending_event)
- *mv_resize->moveresize_pending_event = *event;
- else
- mv_resize->moveresize_pending_event =
- g_memdup (event, sizeof (XEvent));
-
- break;
- }
- if (!moveresize_lookahead (mv_resize, event))
- break;
-
- update_pos (mv_resize,
- event->xmotion.x_root / impl->window_scale,
- event->xmotion.y_root / impl->window_scale);
-
- /* This should never be triggered in normal cases, but in the
- * case where the drag started without an implicit grab being
- * in effect, we could miss the release if it occurs before
- * we grab the pointer; this ensures that we will never
- * get a permanently stuck grab.
- */
- if ((event->xmotion.state & button_mask) == 0)
- {
- check_maximize (mv_resize,
- event->xmotion.x_root / impl->window_scale,
- event->xmotion.y_root / impl->window_scale);
- finish_drag (mv_resize);
- }
- break;
-
- case ButtonRelease:
- update_pos (mv_resize,
- event->xbutton.x_root / impl->window_scale,
- event->xbutton.y_root / impl->window_scale);
-
- if (event->xbutton.button == mv_resize->moveresize_button)
- {
- check_maximize (mv_resize,
- event->xmotion.x_root / impl->window_scale,
- event->xmotion.y_root / impl->window_scale);
- 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 / impl->window_scale, xev->root_y / impl->window_scale);
- state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
- if ((state & button_mask) == 0)
- {
- check_maximize (mv_resize,
- xev->root_x / impl->window_scale,
- xev->root_y / impl->window_scale);
- finish_drag (mv_resize);
- }
- break;
-
- case XI_ButtonRelease:
- update_pos (mv_resize, xev->root_x / impl->window_scale, xev->root_y / impl->window_scale);
- if (xev->detail == mv_resize->moveresize_button)
- {
- check_maximize (mv_resize,
- xev->root_x / impl->window_scale,
- xev->root_y / impl->window_scale);
- finish_drag (mv_resize);
- }
- break;
- default:
- break;
- }
- }
- break;
-#endif
-
- default:
- break;
-
- }
- return TRUE;
-}
-
-gboolean
-_gdk_x11_moveresize_configure_done (GdkDisplay *display,
- GdkSurface *window)
-{
- XEvent *tmp_event;
- MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
-
- if (!mv_resize || window != mv_resize->moveresize_window)
- return FALSE;
-
- if (mv_resize->moveresize_pending_event)
- {
- tmp_event = mv_resize->moveresize_pending_event;
- mv_resize->moveresize_pending_event = NULL;
- _gdk_x11_moveresize_handle_event (tmp_event);
- g_free (tmp_event);
- }
-
- return TRUE;
-}
-
-static void
-create_moveresize_window (MoveResizeData *mv_resize,
- guint32 timestamp)
-{
- GdkGrabStatus status;
-
- g_assert (mv_resize->moveresize_emulation_window == NULL);
-
- mv_resize->moveresize_emulation_window = gdk_surface_new_temp (mv_resize->display);
- gdk_surface_show (mv_resize->moveresize_emulation_window);
-
- status = gdk_seat_grab (gdk_device_get_seat (mv_resize->device),
- mv_resize->moveresize_emulation_window,
- GDK_SEAT_CAPABILITY_POINTER, FALSE,
- NULL, NULL, NULL, NULL);
-
- if (status != GDK_GRAB_SUCCESS)
- {
- /* If this fails, some other client has grabbed the window
- * already.
- */
- finish_drag (mv_resize);
- }
-
- mv_resize->moveresize_process_time = 0;
-}
-
-/*
- Calculate mv_resize->moveresize_orig_x and mv_resize->moveresize_orig_y
- so that calling XMoveWindow with these coordinates will not move the
- window.
- Note that this depends on the WM to implement ICCCM-compliant reference
- point handling.
-*/
-static void
-calculate_unmoving_origin (MoveResizeData *mv_resize)
-{
- GdkRectangle rect;
- gint width, height;
-
- if (mv_resize->moveresize_geom_mask & GDK_HINT_WIN_GRAVITY &&
- mv_resize->moveresize_geometry.win_gravity == GDK_GRAVITY_STATIC)
- {
- gdk_surface_get_origin (mv_resize->moveresize_window,
- &mv_resize->moveresize_orig_x,
- &mv_resize->moveresize_orig_y);
- }
- else
- {
- gdk_surface_get_frame_extents (mv_resize->moveresize_window, &rect);
- gdk_surface_get_geometry (mv_resize->moveresize_window,
- NULL, NULL, &width, &height);
-
- switch (mv_resize->moveresize_geometry.win_gravity)
- {
- case GDK_GRAVITY_NORTH_WEST:
- mv_resize->moveresize_orig_x = rect.x;
- mv_resize->moveresize_orig_y = rect.y;
- break;
- case GDK_GRAVITY_NORTH:
- mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
- mv_resize->moveresize_orig_y = rect.y;
- break;
- case GDK_GRAVITY_NORTH_EAST:
- mv_resize->moveresize_orig_x = rect.x + rect.width - width;
- mv_resize->moveresize_orig_y = rect.y;
- break;
- case GDK_GRAVITY_WEST:
- mv_resize->moveresize_orig_x = rect.x;
- mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
- break;
- case GDK_GRAVITY_CENTER:
- mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
- mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
- break;
- case GDK_GRAVITY_EAST:
- mv_resize->moveresize_orig_x = rect.x + rect.width - width;
- mv_resize->moveresize_orig_y = rect.y + rect.height / 2 - height / 2;
- break;
- case GDK_GRAVITY_SOUTH_WEST:
- mv_resize->moveresize_orig_x = rect.x;
- mv_resize->moveresize_orig_y = rect.y + rect.height - height;
- break;
- case GDK_GRAVITY_SOUTH:
- mv_resize->moveresize_orig_x = rect.x + rect.width / 2 - width / 2;
- mv_resize->moveresize_orig_y = rect.y + rect.height - height;
- break;
- case GDK_GRAVITY_SOUTH_EAST:
- mv_resize->moveresize_orig_x = rect.x + rect.width - width;
- mv_resize->moveresize_orig_y = rect.y + rect.height - height;
- break;
- case GDK_GRAVITY_STATIC:
- default:
- mv_resize->moveresize_orig_x = rect.x;
- mv_resize->moveresize_orig_y = rect.y;
- break;
- }
- }
-}
-
-static void
-emulate_resize_drag (GdkSurface *window,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- MoveResizeData *mv_resize = get_move_resize_data (GDK_SURFACE_DISPLAY (window), TRUE);
-
- if (mv_resize->moveresize_window != NULL)
- return; /* already a drag operation in progress */
-
- mv_resize->is_resize = TRUE;
- mv_resize->moveresize_button = button;
- mv_resize->resize_edge = edge;
- mv_resize->device = device;
- mv_resize->moveresize_x = root_x;
- mv_resize->moveresize_y = root_y;
- mv_resize->moveresize_window = g_object_ref (window);
-
- mv_resize->moveresize_orig_width = gdk_surface_get_width (window);
- mv_resize->moveresize_orig_height = gdk_surface_get_height (window);
-
- mv_resize->moveresize_geom_mask = 0;
- gdk_surface_get_geometry_hints (window,
- &mv_resize->moveresize_geometry,
- &mv_resize->moveresize_geom_mask);
-
- calculate_unmoving_origin (mv_resize);
-
- create_moveresize_window (mv_resize, timestamp);
-}
-
-static void
-emulate_move_drag (GdkSurface *window,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- MoveResizeData *mv_resize = get_move_resize_data (GDK_SURFACE_DISPLAY (window), TRUE);
-
- if (mv_resize->moveresize_window != NULL)
- return; /* already a drag operation in progress */
-
- mv_resize->is_resize = FALSE;
- mv_resize->device = device;
- mv_resize->moveresize_button = button;
- mv_resize->moveresize_x = root_x;
- mv_resize->moveresize_y = root_y;
-
- mv_resize->moveresize_window = g_object_ref (window);
-
- calculate_unmoving_origin (mv_resize);
-
- create_moveresize_window (mv_resize, timestamp);
-}
-
-static gboolean
-_should_perform_ewmh_drag (GdkSurface *window,
- GdkDevice *device)
-{
- GdkPointerSurfaceInfo *info;
- GdkDisplay *display;
-
- display = gdk_surface_get_display (window);
- info = _gdk_display_get_pointer_info (display, device);
-
- if ((!info->last_slave || gdk_device_get_source (info->last_slave) != GDK_SOURCE_TOUCHSCREEN) &&
- gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
- g_intern_static_string ("_NET_WM_MOVERESIZE")))
- return TRUE;
-
- return FALSE;
-}
-
-static void
-gdk_x11_surface_begin_resize_drag (GdkSurface *window,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
- return;
-
- /* Avoid EWMH for touch devices */
- if (_should_perform_ewmh_drag (window, device))
- wmspec_resize_drag (window, edge, device, button, root_x, root_y, timestamp);
- else
- emulate_resize_drag (window, edge, device, button, root_x, root_y, timestamp);
-}
-
-static void
-gdk_x11_surface_begin_move_drag (GdkSurface *window,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- gint direction;
-
- if (GDK_SURFACE_DESTROYED (window) || !WINDOW_IS_TOPLEVEL (window))
- return;
-
- if (button == 0)
- direction = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
- else
- direction = _NET_WM_MOVERESIZE_MOVE;
-
- /* Avoid EWMH for touch devices */
- if (_should_perform_ewmh_drag (window, device))
- wmspec_moveresize (window, direction, device, button, root_x, root_y, timestamp);
- else
- emulate_move_drag (window, device, button, root_x, root_y, timestamp);
-}
-
-static gboolean
-gdk_x11_surface_beep (GdkSurface *window)
-{
- GdkDisplay *display;
-
- display = GDK_SURFACE_DISPLAY (window);
-
-#ifdef HAVE_XKB
- if (GDK_X11_DISPLAY (display)->use_xkb)
- {
- XkbBell (GDK_DISPLAY_XDISPLAY (display),
- GDK_SURFACE_XID (window),
- 0,
- None);
- return TRUE;
- }
-#endif
-
- return FALSE;
-}
-
-static void
-gdk_x11_surface_set_opacity (GdkSurface *window,
- gdouble opacity)
-{
- GdkDisplay *display;
- gulong cardinal;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !WINDOW_IS_TOPLEVEL (window))
- return;
-
- display = gdk_surface_get_display (window);
-
- if (opacity < 0)
- opacity = 0;
- else if (opacity > 1)
- opacity = 1;
-
- cardinal = opacity * 0xffffffff;
-
- if (cardinal == 0xffffffff)
- XDeleteProperty (GDK_DISPLAY_XDISPLAY (display),
- GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_OPACITY"));
- else
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
- GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_OPACITY"),
- XA_CARDINAL, 32,
- PropModeReplace,
- (guchar *) &cardinal, 1);
-}
-
-static Bool
-timestamp_predicate (Display *display,
- XEvent *xevent,
- XPointer arg)
-{
- Window xwindow = GPOINTER_TO_UINT (arg);
- GdkDisplay *gdk_display = gdk_x11_lookup_xdisplay (display);
-
- if (xevent->type == PropertyNotify &&
- xevent->xproperty.window == xwindow &&
- xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (gdk_display,
- "GDK_TIMESTAMP_PROP"))
- return True;
-
- return False;
-}
-
-/**
- * gdk_x11_get_server_time:
- * @window: (type GdkX11Surface): a #GdkSurface, used for communication
- * with the server. The window must have
- * GDK_PROPERTY_CHANGE_MASK in its events mask or a hang will
- * result.
- *
- * Routine to get the current X server time stamp.
- *
- * Returns: the time stamp.
- **/
-guint32
-gdk_x11_get_server_time (GdkSurface *window)
-{
- Display *xdisplay;
- Window xwindow;
- guchar c = 'a';
- XEvent xevent;
- Atom timestamp_prop_atom;
-
- g_return_val_if_fail (GDK_IS_SURFACE (window), 0);
- g_return_val_if_fail (!GDK_SURFACE_DESTROYED (window), 0);
-
- xdisplay = GDK_SURFACE_XDISPLAY (window);
- xwindow = GDK_SURFACE_XID (window);
- timestamp_prop_atom =
- gdk_x11_get_xatom_by_name_for_display (GDK_SURFACE_DISPLAY (window),
- "GDK_TIMESTAMP_PROP");
-
- XChangeProperty (xdisplay, xwindow, timestamp_prop_atom,
- timestamp_prop_atom,
- 8, PropModeReplace, &c, 1);
-
- XIfEvent (xdisplay, &xevent,
- timestamp_predicate, GUINT_TO_POINTER(xwindow));
-
- return xevent.xproperty.time;
-}
-
-/**
- * gdk_x11_surface_get_xid:
- * @window: (type GdkX11Surface): a native #GdkSurface.
- *
- * Returns the X resource (window) belonging to a #GdkSurface.
- *
- * Returns: the ID of @drawable’s X resource.
- **/
-XID
-gdk_x11_surface_get_xid (GdkSurface *window)
-{
- if (!GDK_SURFACE_IS_X11 (window) ||
- !_gdk_surface_has_impl (window))
- {
- g_warning (G_STRLOC " drawable is not a native X11 window");
- return None;
- }
-
- return GDK_SURFACE_IMPL_X11 (window->impl)->xid;
-}
-
-static gint
-gdk_x11_surface_get_scale_factor (GdkSurface *window)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return 1;
-
- return impl->window_scale;
-}
-
-/**
- * gdk_x11_surface_set_frame_sync_enabled:
- * @window: (type GdkX11Surface): a native #GdkSurface
- * @frame_sync_enabled: whether frame-synchronization should be enabled
- *
- * This function can be used to disable frame synchronization for a window.
- * Normally frame synchronziation will be enabled or disabled based on whether
- * the system has a compositor that supports frame synchronization, but if
- * the window is not directly managed by the window manager, then frame
- * synchronziation may need to be disabled. This is the case for a window
- * embedded via the XEMBED protocol.
- */
-void
-gdk_x11_surface_set_frame_sync_enabled (GdkSurface *window,
- gboolean frame_sync_enabled)
-{
- if (!GDK_SURFACE_IS_X11 (window) ||
- !_gdk_surface_has_impl (window))
- {
- g_warning (G_STRLOC " drawable is not a native X11 window");
- return;
- }
-
- GDK_SURFACE_IMPL_X11 (window->impl)->frame_sync_enabled = FALSE;
-}
-
-static void
-gdk_x11_surface_set_opaque_region (GdkSurface *window,
- cairo_region_t *region)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
- GdkDisplay *display;
- int nitems;
- gulong *data;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (region != NULL)
- {
- int i, nrects;
-
- nrects = cairo_region_num_rectangles (region);
- nitems = nrects * 4;
- data = g_new (gulong, nitems);
-
- for (i = 0; i < nrects; i++)
- {
- cairo_rectangle_int_t rect;
- cairo_region_get_rectangle (region, i, &rect);
- data[i*4+0] = rect.x * impl->window_scale;
- data[i*4+1] = rect.y * impl->window_scale;
- data[i*4+2] = rect.width * impl->window_scale;
- data[i*4+3] = rect.height * impl->window_scale;
- }
- }
- else
- {
- nitems = 0;
- data = NULL;
- }
-
- display = gdk_surface_get_display (window);
-
- XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
- GDK_SURFACE_XID (window),
- gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_OPAQUE_REGION"),
- XA_CARDINAL, 32, PropModeReplace,
- (guchar *) data, nitems);
-
- g_free (data);
-}
-
-static gboolean
-gdk_x11_surface_show_window_menu (GdkSurface *window,
- GdkEvent *event)
-{
- GdkSurfaceImplX11 *impl = GDK_SURFACE_IMPL_X11 (window->impl);
- GdkDisplay *display = GDK_SURFACE_DISPLAY (window);
- GdkDevice *device;
- int device_id;
- double x_root, y_root;
- XClientMessageEvent xclient = { 0 };
-
- switch ((guint) event->any.type)
- {
- case GDK_BUTTON_PRESS:
- case GDK_BUTTON_RELEASE:
- break;
- default:
- return FALSE;
- }
-
- if (!gdk_x11_screen_supports_net_wm_hint (GDK_SURFACE_SCREEN (window),
- g_intern_static_string ("_GTK_SHOW_WINDOW_MENU")))
- return FALSE;
-
- gdk_event_get_root_coords (event, &x_root, &y_root);
- device = gdk_event_get_device (event);
- g_object_get (G_OBJECT (device),
- "device-id", &device_id,
- NULL);
-
- /* Ungrab the implicit grab */
- gdk_seat_ungrab (gdk_device_get_seat (device));
-
- xclient.type = ClientMessage;
- xclient.window = GDK_SURFACE_XID (window);
- xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_GTK_SHOW_WINDOW_MENU");
- xclient.data.l[0] = device_id;
- xclient.data.l[1] = x_root * impl->window_scale;
- xclient.data.l[2] = y_root * impl->window_scale;
- xclient.format = 32;
-
- XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_SURFACE_XROOTWIN (window), False,
- SubstructureRedirectMask | SubstructureNotifyMask,
- (XEvent *)&xclient);
-
- return TRUE;
-}
-
-static void
-gdk_surface_impl_x11_class_init (GdkSurfaceImplX11Class *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_CLASS (klass);
-
- object_class->finalize = gdk_surface_impl_x11_finalize;
-
- impl_class->ref_cairo_surface = gdk_x11_ref_cairo_surface;
- impl_class->show = gdk_surface_x11_show;
- impl_class->hide = gdk_surface_x11_hide;
- impl_class->withdraw = gdk_surface_x11_withdraw;
- impl_class->set_events = gdk_surface_x11_set_events;
- impl_class->get_events = gdk_surface_x11_get_events;
- impl_class->raise = gdk_surface_x11_raise;
- impl_class->lower = gdk_surface_x11_lower;
- impl_class->restack_toplevel = gdk_surface_x11_restack_toplevel;
- impl_class->move_resize = gdk_surface_x11_move_resize;
- impl_class->get_geometry = gdk_surface_x11_get_geometry;
- impl_class->get_root_coords = gdk_surface_x11_get_root_coords;
- impl_class->get_device_state = gdk_surface_x11_get_device_state;
- impl_class->shape_combine_region = gdk_surface_x11_shape_combine_region;
- impl_class->input_shape_combine_region = gdk_surface_x11_input_shape_combine_region;
- impl_class->queue_antiexpose = _gdk_x11_surface_queue_antiexpose;
- impl_class->destroy = gdk_x11_surface_destroy;
- impl_class->beep = gdk_x11_surface_beep;
-
- impl_class->focus = gdk_x11_surface_focus;
- impl_class->set_type_hint = gdk_x11_surface_set_type_hint;
- impl_class->get_type_hint = gdk_x11_surface_get_type_hint;
- impl_class->set_modal_hint = gdk_x11_surface_set_modal_hint;
- impl_class->set_skip_taskbar_hint = gdk_x11_surface_set_skip_taskbar_hint;
- impl_class->set_skip_pager_hint = gdk_x11_surface_set_skip_pager_hint;
- impl_class->set_urgency_hint = gdk_x11_surface_set_urgency_hint;
- impl_class->set_geometry_hints = gdk_x11_surface_set_geometry_hints;
- impl_class->set_title = gdk_x11_surface_set_title;
- impl_class->set_role = gdk_x11_surface_set_role;
- impl_class->set_startup_id = gdk_x11_surface_set_startup_id;
- impl_class->set_transient_for = gdk_x11_surface_set_transient_for;
- impl_class->get_frame_extents = gdk_x11_surface_get_frame_extents;
- impl_class->set_accept_focus = gdk_x11_surface_set_accept_focus;
- impl_class->set_focus_on_map = gdk_x11_surface_set_focus_on_map;
- impl_class->set_icon_list = gdk_x11_surface_set_icon_list;
- impl_class->set_icon_name = gdk_x11_surface_set_icon_name;
- impl_class->iconify = gdk_x11_surface_iconify;
- impl_class->deiconify = gdk_x11_surface_deiconify;
- impl_class->stick = gdk_x11_surface_stick;
- impl_class->unstick = gdk_x11_surface_unstick;
- impl_class->maximize = gdk_x11_surface_maximize;
- impl_class->unmaximize = gdk_x11_surface_unmaximize;
- impl_class->fullscreen = gdk_x11_surface_fullscreen;
- impl_class->fullscreen_on_monitor = gdk_x11_surface_fullscreen_on_monitor;
- impl_class->apply_fullscreen_mode = gdk_x11_surface_apply_fullscreen_mode;
- impl_class->unfullscreen = gdk_x11_surface_unfullscreen;
- impl_class->set_keep_above = gdk_x11_surface_set_keep_above;
- impl_class->set_keep_below = gdk_x11_surface_set_keep_below;
- impl_class->get_group = gdk_x11_surface_get_group;
- impl_class->set_group = gdk_x11_surface_set_group;
- impl_class->set_decorations = gdk_x11_surface_set_decorations;
- impl_class->get_decorations = gdk_x11_surface_get_decorations;
- impl_class->set_functions = gdk_x11_surface_set_functions;
- impl_class->begin_resize_drag = gdk_x11_surface_begin_resize_drag;
- impl_class->begin_move_drag = gdk_x11_surface_begin_move_drag;
- impl_class->set_opacity = gdk_x11_surface_set_opacity;
- impl_class->destroy_notify = gdk_x11_surface_destroy_notify;
- impl_class->register_dnd = _gdk_x11_surface_register_dnd;
- impl_class->drag_begin = _gdk_x11_surface_drag_begin;
- impl_class->get_scale_factor = gdk_x11_surface_get_scale_factor;
- impl_class->set_opaque_region = gdk_x11_surface_set_opaque_region;
- impl_class->set_shadow_width = gdk_x11_surface_set_shadow_width;
- impl_class->show_window_menu = gdk_x11_surface_show_window_menu;
- impl_class->create_gl_context = gdk_x11_surface_create_gl_context;
- impl_class->get_unscaled_size = gdk_x11_surface_get_unscaled_size;
- impl_class->supports_edge_constraints = gdk_x11_surface_supports_edge_constraints;
-}
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#ifndef __GDK_SURFACE_X11_H__
-#define __GDK_SURFACE_X11_H__
-
-#include "gdk/x11/gdkprivate-x11.h"
-#include "gdk/gdkwindowimpl.h"
-
-#include <X11/Xlib.h>
-
-#ifdef HAVE_XDAMAGE
-#include <X11/extensions/Xdamage.h>
-#endif
-
-#ifdef HAVE_XSYNC
-#include <X11/Xlib.h>
-#include <X11/extensions/sync.h>
-#endif
-
-G_BEGIN_DECLS
-
-typedef struct _GdkToplevelX11 GdkToplevelX11;
-typedef struct _GdkSurfaceImplX11 GdkSurfaceImplX11;
-typedef struct _GdkSurfaceImplX11Class GdkSurfaceImplX11Class;
-typedef struct _GdkXPositionInfo GdkXPositionInfo;
-
-/* Window implementation for X11
- */
-
-#define GDK_TYPE_SURFACE_IMPL_X11 (gdk_surface_impl_x11_get_type ())
-#define GDK_SURFACE_IMPL_X11(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL_X11, GdkSurfaceImplX11))
-#define GDK_SURFACE_IMPL_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL_X11, GdkSurfaceImplX11Class))
-#define GDK_IS_SURFACE_IMPL_X11(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL_X11))
-#define GDK_IS_SURFACE_IMPL_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL_X11))
-#define GDK_SURFACE_IMPL_X11_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL_X11, GdkSurfaceImplX11Class))
-
-struct _GdkSurfaceImplX11
-{
- GdkSurfaceImpl parent_instance;
-
- GdkSurface *wrapper;
-
- Window xid;
-
- GdkToplevelX11 *toplevel; /* Toplevel-specific information */
- GdkCursor *cursor;
-
- guint no_bg : 1; /* Set when the window background is temporarily
- * unset during resizing and scaling */
- guint override_redirect : 1;
- guint frame_clock_connected : 1;
- guint frame_sync_enabled : 1;
- guint tracking_damage: 1;
-
- gint window_scale;
-
- /* Width and height not divided by window_scale - this matters in the
- * corner-case where the window manager assigns us a size that isn't
- * a multiple of window_scale - for example for a maximized window
- * with an odd-sized title-bar.
- */
- gint unscaled_width;
- gint unscaled_height;
-
- cairo_surface_t *cairo_surface;
-
-#if defined (HAVE_XCOMPOSITE) && defined(HAVE_XDAMAGE) && defined (HAVE_XFIXES)
- Damage damage;
-#endif
-};
-
-struct _GdkSurfaceImplX11Class
-{
- GdkSurfaceImplClass parent_class;
-};
-
-struct _GdkToplevelX11
-{
-
- /* Set if the window, or any descendent of it, is the server's focus window
- */
- guint has_focus_window : 1;
-
- /* Set if window->has_focus_window and the focus isn't grabbed elsewhere.
- */
- guint has_focus : 1;
-
- /* Set if the pointer is inside this window. (This is needed for
- * for focus tracking)
- */
- guint has_pointer : 1;
-
- /* Set if the window is a descendent of the focus window and the pointer is
- * inside it. (This is the case where the window will receive keystroke
- * events even window->has_focus_window is FALSE)
- */
- guint has_pointer_focus : 1;
-
- /* Set if we are requesting these hints */
- guint skip_taskbar_hint : 1;
- guint skip_pager_hint : 1;
- guint urgency_hint : 1;
-
- guint on_all_desktops : 1; /* _NET_WM_STICKY == 0xFFFFFFFF */
-
- guint have_sticky : 1; /* _NET_WM_STATE_STICKY */
- guint have_maxvert : 1; /* _NET_WM_STATE_MAXIMIZED_VERT */
- guint have_maxhorz : 1; /* _NET_WM_STATE_MAXIMIZED_HORZ */
- guint have_fullscreen : 1; /* _NET_WM_STATE_FULLSCREEN */
- guint have_hidden : 1; /* _NET_WM_STATE_HIDDEN */
-
- guint is_leader : 1;
-
- /* Set if the WM is presenting us as focused, i.e. with active decorations
- */
- guint have_focused : 1;
-
- guint in_frame : 1;
-
- /* If we're expecting a response from the compositor after painting a frame */
- guint frame_pending : 1;
-
- /* Whether pending_counter_value/configure_counter_value are updates
- * to the extended update counter */
- guint pending_counter_value_is_extended : 1;
- guint configure_counter_value_is_extended : 1;
-
- gulong map_serial; /* Serial of last transition from unmapped */
-
- cairo_surface_t *icon_pixmap;
- cairo_surface_t *icon_mask;
- GdkSurface *group_leader;
-
- /* Time of most recent user interaction. */
- gulong user_time;
-
- /* We use an extra X window for toplevel windows that we XSetInputFocus()
- * to in order to avoid getting keyboard events redirected to subwindows
- * that might not even be part of this app
- */
- Window focus_window;
-
- GdkSurfaceHints last_geometry_hints_mask;
- GdkGeometry last_geometry_hints;
-
- /* Constrained edge information */
- guint edge_constraints;
-
-#ifdef HAVE_XSYNC
- XID update_counter;
- XID extended_update_counter;
- gint64 pending_counter_value; /* latest _NET_WM_SYNC_REQUEST value received */
- gint64 configure_counter_value; /* Latest _NET_WM_SYNC_REQUEST value received
- * where we have also seen the corresponding
- * ConfigureNotify
- */
- gint64 current_counter_value;
-
- /* After a _NET_WM_FRAME_DRAWN message, this is the soonest that we think
- * frame after will be presented */
- gint64 throttled_presentation_time;
-#endif
-};
-
-GType gdk_surface_impl_x11_get_type (void);
-
-GdkToplevelX11 *_gdk_x11_surface_get_toplevel (GdkSurface *window);
-
-GdkCursor *_gdk_x11_surface_get_cursor (GdkSurface *window);
-
-void _gdk_x11_surface_update_size (GdkSurfaceImplX11 *impl);
-void _gdk_x11_surface_set_window_scale (GdkSurface *window,
- int scale);
-
-G_END_DECLS
-
-#endif /* __GDK_SURFACE_X11_H__ */
#include <gdk/x11/gdkx11screen.h>
#include <gdk/x11/gdkx11selection.h>
#include <gdk/x11/gdkx11utils.h>
-#include <gdk/x11/gdkx11window.h>
+#include <gdk/x11/gdkx11surface.h>
#include <gdk/x11/gdkx-autocleanups.h>
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __GDK_X11_SURFACE_H__
+#define __GDK_X11_SURFACE_H__
+
+#if !defined (__GDKX_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdkx.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_X11_SURFACE (gdk_x11_surface_get_type ())
+#define GDK_X11_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_X11_SURFACE, GdkX11Surface))
+#define GDK_X11_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_X11_SURFACE, GdkX11SurfaceClass))
+#define GDK_IS_X11_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_X11_SURFACE))
+#define GDK_IS_X11_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_X11_SURFACE))
+#define GDK_X11_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_X11_SURFACE, GdkX11SurfaceClass))
+
+#ifdef GDK_COMPILATION
+typedef struct _GdkX11Surface GdkX11Surface;
+#else
+typedef GdkSurface GdkX11Surface;
+#endif
+typedef struct _GdkX11SurfaceClass GdkX11SurfaceClass;
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_x11_surface_get_type (void);
+
+GDK_AVAILABLE_IN_ALL
+Window gdk_x11_surface_get_xid (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_x11_surface_set_user_time (GdkSurface *window,
+ guint32 timestamp);
+GDK_AVAILABLE_IN_ALL
+void gdk_x11_surface_set_utf8_property (GdkSurface *window,
+ const gchar *name,
+ const gchar *value);
+GDK_AVAILABLE_IN_ALL
+void gdk_x11_surface_set_theme_variant (GdkSurface *window,
+ const char *variant);
+GDK_AVAILABLE_IN_ALL
+void gdk_x11_surface_move_to_current_desktop (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+guint32 gdk_x11_surface_get_desktop (GdkSurface *window);
+GDK_AVAILABLE_IN_ALL
+void gdk_x11_surface_move_to_desktop (GdkSurface *window,
+ guint32 desktop);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_x11_surface_set_frame_sync_enabled (GdkSurface *window,
+ gboolean frame_sync_enabled);
+
+/**
+ * GDK_SURFACE_XDISPLAY:
+ * @win: a #GdkSurface.
+ *
+ * Returns the display of a #GdkSurface.
+ *
+ * Returns: an Xlib Display*.
+ */
+#define GDK_SURFACE_XDISPLAY(win) (GDK_DISPLAY_XDISPLAY (gdk_surface_get_display (win)))
+
+/**
+ * GDK_SURFACE_XID:
+ * @win: a #GdkSurface.
+ *
+ * Returns the X window belonging to a #GdkSurface.
+ *
+ * Returns: the Xlib Window of @win.
+ */
+#define GDK_SURFACE_XID(win) (gdk_x11_surface_get_xid (win))
+
+GDK_AVAILABLE_IN_ALL
+guint32 gdk_x11_get_server_time (GdkSurface *window);
+
+GDK_AVAILABLE_IN_ALL
+GdkSurface *gdk_x11_surface_foreign_new_for_display (GdkDisplay *display,
+ Window window);
+GDK_AVAILABLE_IN_ALL
+GdkSurface *gdk_x11_surface_lookup_for_display (GdkDisplay *display,
+ Window window);
+
+G_END_DECLS
+
+#endif /* __GDK_X11_SURFACE_H__ */
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * 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, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
- * file for a list of people on the GTK+ Team. See the ChangeLog
- * files for a list of changes. These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#ifndef __GDK_X11_SURFACE_H__
-#define __GDK_X11_SURFACE_H__
-
-#if !defined (__GDKX_H_INSIDE__) && !defined (GDK_COMPILATION)
-#error "Only <gdk/gdkx.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_X11_SURFACE (gdk_x11_surface_get_type ())
-#define GDK_X11_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_X11_SURFACE, GdkX11Surface))
-#define GDK_X11_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_X11_SURFACE, GdkX11SurfaceClass))
-#define GDK_IS_X11_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_X11_SURFACE))
-#define GDK_IS_X11_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_X11_SURFACE))
-#define GDK_X11_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_X11_SURFACE, GdkX11SurfaceClass))
-
-#ifdef GDK_COMPILATION
-typedef struct _GdkX11Surface GdkX11Surface;
-#else
-typedef GdkSurface GdkX11Surface;
-#endif
-typedef struct _GdkX11SurfaceClass GdkX11SurfaceClass;
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_x11_surface_get_type (void);
-
-GDK_AVAILABLE_IN_ALL
-Window gdk_x11_surface_get_xid (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_x11_surface_set_user_time (GdkSurface *window,
- guint32 timestamp);
-GDK_AVAILABLE_IN_ALL
-void gdk_x11_surface_set_utf8_property (GdkSurface *window,
- const gchar *name,
- const gchar *value);
-GDK_AVAILABLE_IN_ALL
-void gdk_x11_surface_set_theme_variant (GdkSurface *window,
- const char *variant);
-GDK_AVAILABLE_IN_ALL
-void gdk_x11_surface_move_to_current_desktop (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-guint32 gdk_x11_surface_get_desktop (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-void gdk_x11_surface_move_to_desktop (GdkSurface *window,
- guint32 desktop);
-
-GDK_AVAILABLE_IN_ALL
-void gdk_x11_surface_set_frame_sync_enabled (GdkSurface *window,
- gboolean frame_sync_enabled);
-
-/**
- * GDK_SURFACE_XDISPLAY:
- * @win: a #GdkSurface.
- *
- * Returns the display of a #GdkSurface.
- *
- * Returns: an Xlib Display*.
- */
-#define GDK_SURFACE_XDISPLAY(win) (GDK_DISPLAY_XDISPLAY (gdk_surface_get_display (win)))
-
-/**
- * GDK_SURFACE_XID:
- * @win: a #GdkSurface.
- *
- * Returns the X window belonging to a #GdkSurface.
- *
- * Returns: the Xlib Window of @win.
- */
-#define GDK_SURFACE_XID(win) (gdk_x11_surface_get_xid (win))
-
-GDK_AVAILABLE_IN_ALL
-guint32 gdk_x11_get_server_time (GdkSurface *window);
-
-GDK_AVAILABLE_IN_ALL
-GdkSurface *gdk_x11_surface_foreign_new_for_display (GdkDisplay *display,
- Window window);
-GDK_AVAILABLE_IN_ALL
-GdkSurface *gdk_x11_surface_lookup_for_display (GdkDisplay *display,
- Window window);
-
-G_END_DECLS
-
-#endif /* __GDK_X11_SURFACE_H__ */
'gdktextlistconverter-x11.c',
'gdkvisual-x11.c',
'gdkvulkancontext-x11.c',
- 'gdkwindow-x11.c',
+ 'gdksurface-x11.c',
'gdkxftdefaults.c',
'gdkxid.c',
'xsettings-client.c',
'gdkx11screen.h',
'gdkx11selection.h',
'gdkx11utils.h',
- 'gdkx11window.h',
+ 'gdkx11surface.h',
])
install_headers(gdk_x11_public_headers, subdir: 'gtk-4.0/gdk/x11/')
#include <gdk/x11/gdkx11display.h>
#include <gdk/x11/gdkx11property.h>
#include <gdk/x11/gdkx11screen.h>
-#include <gdk/x11/gdkx11window.h>
+#include <gdk/x11/gdkx11surface.h>
#include <gdk/x11/gdkprivate-x11.h>
#include <gdk/x11/gdkdisplay-x11.h>
#include <gdk/x11/gdkscreen-x11.h>
}
/* Fake protocol to let us call GdkNSView gdkWindow without including
* gdk/GdkNSView.h (which we can’t because it pulls in the internal-only
- * gdkwindow.h).
+ * gdksurface.h).
*/
@protocol GdkNSView
- (GdkSurface *)gdkWindow;
G_OBJECT_CLASS (gtk_window_parent_class)->finalize (object);
}
-/* copied from gdkwindow-x11.c */
+/* copied from gdksurface-x11.c */
static const gchar *
get_default_title (void)
{