summaryrefslogtreecommitdiff
path: root/gdk/broadway/gdkscreen-broadway.c
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2010-11-12 13:18:58 +0100
committerAlexander Larsson <alexl@redhat.com>2010-11-25 22:09:19 +0100
commit5b480e1b0de0c8184cb2805ac85f7362c42fb2f6 (patch)
treedf5fd13a56b7ec224daa0281429bbc7e75b7128b /gdk/broadway/gdkscreen-broadway.c
parenteb5a5004959227d22b2f98a157beda8600df00d3 (diff)
downloadgtk+-5b480e1b0de0c8184cb2805ac85f7362c42fb2f6.tar.gz
[broadway] Copy X backend to broadway
Diffstat (limited to 'gdk/broadway/gdkscreen-broadway.c')
-rw-r--r--gdk/broadway/gdkscreen-broadway.c2003
1 files changed, 2003 insertions, 0 deletions
diff --git a/gdk/broadway/gdkscreen-broadway.c b/gdk/broadway/gdkscreen-broadway.c
new file mode 100644
index 0000000000..9bb2259b89
--- /dev/null
+++ b/gdk/broadway/gdkscreen-broadway.c
@@ -0,0 +1,2003 @@
+ /*
+ * gdkscreen-broadway.c
+ *
+ * Copyright 2001 Sun Microsystems Inc.
+ *
+ * Erwann Chenede <erwann.chenede@sun.com>
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gdkscreen-broadway.h"
+
+#include "gdkscreen.h"
+#include "gdkdisplay.h"
+#include "gdkdisplay-broadway.h"
+#include "gdkx.h"
+
+#include <glib.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xatom.h>
+
+#ifdef HAVE_SOLARIS_XINERAMA
+#include <X11/extensions/xinerama.h>
+#endif
+#ifdef HAVE_XFREE_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+
+#ifdef HAVE_RANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
+
+#include "gdksettings.c"
+
+static void gdk_screen_x11_dispose (GObject *object);
+static void gdk_screen_x11_finalize (GObject *object);
+static void init_randr_support (GdkScreen *screen);
+static void deinit_multihead (GdkScreen *screen);
+
+enum
+{
+ WINDOW_MANAGER_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GdkScreenX11, _gdk_screen_x11, GDK_TYPE_SCREEN)
+
+typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms;
+
+struct _NetWmSupportedAtoms
+{
+ Atom *atoms;
+ gulong n_atoms;
+};
+
+struct _GdkX11Monitor
+{
+ GdkRectangle geometry;
+ XID output;
+ int width_mm;
+ int height_mm;
+ char * output_name;
+ char * manufacturer;
+};
+
+static void
+_gdk_screen_x11_class_init (GdkScreenX11Class *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gdk_screen_x11_dispose;
+ object_class->finalize = gdk_screen_x11_finalize;
+
+ signals[WINDOW_MANAGER_CHANGED] =
+ g_signal_new (g_intern_static_string ("window_manager_changed"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdkScreenX11Class, window_manager_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+_gdk_screen_x11_init (GdkScreenX11 *screen)
+{
+}
+
+/**
+ * gdk_screen_get_display:
+ * @screen: a #GdkScreen
+ *
+ * Gets the display to which the @screen belongs.
+ *
+ * Returns: the display to which @screen belongs
+ *
+ * Since: 2.2
+ **/
+GdkDisplay *
+gdk_screen_get_display (GdkScreen *screen)
+{
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+ return GDK_SCREEN_X11 (screen)->display;
+}
+/**
+ * gdk_screen_get_width:
+ * @screen: a #GdkScreen
+ *
+ * Gets the width of @screen in pixels
+ *
+ * Returns: the width of @screen in pixels.
+ *
+ * Since: 2.2
+ **/
+gint
+gdk_screen_get_width (GdkScreen *screen)
+{
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+ return WidthOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
+}
+
+/**
+ * gdk_screen_get_height:
+ * @screen: a #GdkScreen
+ *
+ * Gets the height of @screen in pixels
+ *
+ * Returns: the height of @screen in pixels.
+ *
+ * Since: 2.2
+ **/
+gint
+gdk_screen_get_height (GdkScreen *screen)
+{
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+ return HeightOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
+}
+
+/**
+ * gdk_screen_get_width_mm:
+ * @screen: a #GdkScreen
+ *
+ * Gets the width of @screen in millimeters.
+ * Note that on some X servers this value will not be correct.
+ *
+ * Returns: the width of @screen in millimeters.
+ *
+ * Since: 2.2
+ **/
+gint
+gdk_screen_get_width_mm (GdkScreen *screen)
+{
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+ return WidthMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
+}
+
+/**
+ * gdk_screen_get_height_mm:
+ * @screen: a #GdkScreen
+ *
+ * Returns the height of @screen in millimeters.
+ * Note that on some X servers this value will not be correct.
+ *
+ * Returns: the heigth of @screen in millimeters.
+ *
+ * Since: 2.2
+ **/
+gint
+gdk_screen_get_height_mm (GdkScreen *screen)
+{
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+ return HeightMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
+}
+
+/**
+ * gdk_screen_get_number:
+ * @screen: a #GdkScreen
+ *
+ * Gets the index of @screen among the screens in the display
+ * to which it belongs. (See gdk_screen_get_display())
+ *
+ * Returns: the index
+ *
+ * Since: 2.2
+ **/
+gint
+gdk_screen_get_number (GdkScreen *screen)
+{
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+ return GDK_SCREEN_X11 (screen)->screen_num;
+}
+
+/**
+ * gdk_screen_get_root_window:
+ * @screen: a #GdkScreen
+ *
+ * Gets the root window of @screen.
+ *
+ * Returns: (transfer none): the root window
+ *
+ * Since: 2.2
+ **/
+GdkWindow *
+gdk_screen_get_root_window (GdkScreen *screen)
+{
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+ return GDK_SCREEN_X11 (screen)->root_window;
+}
+
+static void
+_gdk_screen_x11_events_uninit (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ if (screen_x11->xsettings_client)
+ {
+ xsettings_client_destroy (screen_x11->xsettings_client);
+ screen_x11->xsettings_client = NULL;
+ }
+}
+
+static void
+gdk_screen_x11_dispose (GObject *object)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
+ int i;
+
+ for (i = 0; i < 32; ++i)
+ {
+ if (screen_x11->subwindow_gcs[i])
+ {
+ XFreeGC (screen_x11->xdisplay, screen_x11->subwindow_gcs[i]);
+ screen_x11->subwindow_gcs[i] = 0;
+ }
+ }
+
+ _gdk_screen_x11_events_uninit (GDK_SCREEN (object));
+
+ if (screen_x11->root_window)
+ _gdk_window_destroy (screen_x11->root_window, TRUE);
+
+ G_OBJECT_CLASS (_gdk_screen_x11_parent_class)->dispose (object);
+
+ screen_x11->xdisplay = NULL;
+ screen_x11->xscreen = NULL;
+ screen_x11->screen_num = -1;
+ screen_x11->xroot_window = None;
+ screen_x11->wmspec_check_window = None;
+}
+
+static void
+gdk_screen_x11_finalize (GObject *object)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
+ gint i;
+
+ if (screen_x11->root_window)
+ g_object_unref (screen_x11->root_window);
+
+ /* Visual Part */
+ for (i = 0; i < screen_x11->nvisuals; i++)
+ g_object_unref (screen_x11->visuals[i]);
+ g_free (screen_x11->visuals);
+ g_hash_table_destroy (screen_x11->visual_hash);
+
+ g_free (screen_x11->window_manager_name);
+
+ deinit_multihead (GDK_SCREEN (object));
+
+ G_OBJECT_CLASS (_gdk_screen_x11_parent_class)->finalize (object);
+}
+
+/**
+ * gdk_screen_get_n_monitors:
+ * @screen: a #GdkScreen
+ *
+ * Returns the number of monitors which @screen consists of.
+ *
+ * Returns: number of monitors which @screen consists of
+ *
+ * Since: 2.2
+ */
+gint
+gdk_screen_get_n_monitors (GdkScreen *screen)
+{
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+ return GDK_SCREEN_X11 (screen)->n_monitors;
+}
+
+/**
+ * gdk_screen_get_primary_monitor:
+ * @screen: a #GdkScreen.
+ *
+ * Gets the primary monitor for @screen. The primary monitor
+ * is considered the monitor where the 'main desktop' lives.
+ * While normal application windows typically allow the window
+ * manager to place the windows, specialized desktop applications
+ * such as panels should place themselves on the primary monitor.
+ *
+ * If no primary monitor is configured by the user, the return value
+ * will be 0, defaulting to the first monitor.
+ *
+ * Returns: An integer index for the primary monitor, or 0 if none is configured.
+ *
+ * Since: 2.20
+ */
+gint
+gdk_screen_get_primary_monitor (GdkScreen *screen)
+{
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+
+ return GDK_SCREEN_X11 (screen)->primary_monitor;
+}
+
+/**
+ * gdk_screen_get_monitor_width_mm:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
+ *
+ * Gets the width in millimeters of the specified monitor, if available.
+ *
+ * Returns: the width of the monitor, or -1 if not available
+ *
+ * Since: 2.14
+ */
+gint
+gdk_screen_get_monitor_width_mm (GdkScreen *screen,
+ gint monitor_num)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
+ g_return_val_if_fail (monitor_num >= 0, -1);
+ g_return_val_if_fail (monitor_num < screen_x11->n_monitors, -1);
+
+ return screen_x11->monitors[monitor_num].width_mm;
+}
+
+/**
+ * gdk_screen_get_monitor_height_mm:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
+ *
+ * Gets the height in millimeters of the specified monitor.
+ *
+ * Returns: the height of the monitor, or -1 if not available
+ *
+ * Since: 2.14
+ */
+gint
+gdk_screen_get_monitor_height_mm (GdkScreen *screen,
+ gint monitor_num)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
+ g_return_val_if_fail (monitor_num >= 0, -1);
+ g_return_val_if_fail (monitor_num < screen_x11->n_monitors, -1);
+
+ return screen_x11->monitors[monitor_num].height_mm;
+}
+
+/**
+ * gdk_screen_get_monitor_plug_name:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
+ *
+ * Returns the output name of the specified monitor.
+ * Usually something like VGA, DVI, or TV, not the actual
+ * product name of the display device.
+ *
+ * Returns: a newly-allocated string containing the name of the monitor,
+ * or %NULL if the name cannot be determined
+ *
+ * Since: 2.14
+ */
+gchar *
+gdk_screen_get_monitor_plug_name (GdkScreen *screen,
+ gint monitor_num)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+ g_return_val_if_fail (monitor_num >= 0, NULL);
+ g_return_val_if_fail (monitor_num < screen_x11->n_monitors, NULL);
+
+ return g_strdup (screen_x11->monitors[monitor_num].output_name);
+}
+
+/**
+ * gdk_x11_screen_get_monitor_output:
+ * @screen: a #GdkScreen
+ * @monitor_num: number of the monitor, between 0 and gdk_screen_get_n_monitors (screen)
+ *
+ * Gets the XID of the specified output/monitor.
+ * If the X server does not support version 1.2 of the RANDR
+ * extension, 0 is returned.
+ *
+ * Returns: the XID of the monitor
+ *
+ * Since: 2.14
+ */
+XID
+gdk_x11_screen_get_monitor_output (GdkScreen *screen,
+ gint monitor_num)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), None);
+ g_return_val_if_fail (monitor_num >= 0, None);
+ g_return_val_if_fail (monitor_num < screen_x11->n_monitors, None);
+
+ return screen_x11->monitors[monitor_num].output;
+}
+
+/**
+ * gdk_screen_get_monitor_geometry:
+ * @screen: a #GdkScreen
+ * @monitor_num: the monitor number, between 0 and gdk_screen_get_n_monitors (screen)
+ * @dest: a #GdkRectangle to be filled with the monitor geometry
+ *
+ * Retrieves the #GdkRectangle representing the size and position of
+ * the individual monitor within the entire screen area.
+ *
+ * Note that the size of the entire screen area can be retrieved via
+ * gdk_screen_get_width() and gdk_screen_get_height().
+ *
+ * Since: 2.2
+ */
+void
+gdk_screen_get_monitor_geometry (GdkScreen *screen,
+ gint monitor_num,
+ GdkRectangle *dest)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ g_return_if_fail (GDK_IS_SCREEN (screen));
+ g_return_if_fail (monitor_num >= 0);
+ g_return_if_fail (monitor_num < screen_x11->n_monitors);
+
+ if (dest)
+ *dest = screen_x11->monitors[monitor_num].geometry;
+}
+
+/**
+ * gdk_screen_get_rgba_visual:
+ * @screen: a #GdkScreen
+ *
+ * Gets a visual to use for creating windows with an alpha channel.
+ * The windowing system on which GTK+ is running
+ * may not support this capability, in which case %NULL will
+ * be returned. Even if a non-%NULL value is returned, its
+ * possible that the window's alpha channel won't be honored
+ * when displaying the window on the screen: in particular, for
+ * X an appropriate windowing manager and compositing manager
+ * must be running to provide appropriate display.
+ *
+ * This functionality is not implemented in the Windows backend.
+ *
+ * For setting an overall opacity for a top-level window, see
+ * gdk_window_set_opacity().
+ *
+ * Return value: (transfer none): a visual to use for windows with an
+ * alpha channel or %NULL if the capability is not available.
+ *
+ * Since: 2.8
+ **/
+GdkVisual *
+gdk_screen_get_rgba_visual (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+
+ return screen_x11->rgba_visual;
+}
+
+/**
+ * gdk_x11_screen_get_xscreen:
+ * @screen: a #GdkScreen.
+ * @returns: (transfer none): an Xlib <type>Screen*</type>
+ *
+ * Returns the screen of a #GdkScreen.
+ *
+ * Since: 2.2
+ */
+Screen *
+gdk_x11_screen_get_xscreen (GdkScreen *screen)
+{
+ return GDK_SCREEN_X11 (screen)->xscreen;
+}
+
+/**
+ * gdk_x11_screen_get_screen_number:
+ * @screen: a #GdkScreen.
+ * @returns: the position of @screen among the screens of
+ * its display.
+ *
+ * Returns the index of a #GdkScreen.
+ *
+ * Since: 2.2
+ */
+int
+gdk_x11_screen_get_screen_number (GdkScreen *screen)
+{
+ return GDK_SCREEN_X11 (screen)->screen_num;
+}
+
+static gboolean
+check_is_composited (GdkDisplay *display,
+ GdkScreenX11 *screen_x11)
+{
+ Atom xselection = gdk_x11_atom_to_xatom_for_display (display, screen_x11->cm_selection_atom);
+ Window xwindow;
+
+ xwindow = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display), xselection);
+
+ return xwindow != None;
+}
+
+static GdkAtom
+make_cm_atom (int screen_number)
+{
+ gchar *name = g_strdup_printf ("_NET_WM_CM_S%d", screen_number);
+ GdkAtom atom = gdk_atom_intern (name, FALSE);
+ g_free (name);
+ return atom;
+}
+
+static void
+init_monitor_geometry (GdkX11Monitor *monitor,
+ int x, int y, int width, int height)
+{
+ monitor->geometry.x = x;
+ monitor->geometry.y = y;
+ monitor->geometry.width = width;
+ monitor->geometry.height = height;
+
+ monitor->output = None;
+ monitor->width_mm = -1;
+ monitor->height_mm = -1;
+ monitor->output_name = NULL;
+ monitor->manufacturer = NULL;
+}
+
+static gboolean
+init_fake_xinerama (GdkScreen *screen)
+{
+#ifdef G_ENABLE_DEBUG
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ XSetWindowAttributes atts;
+ Window win;
+ gint w, h;
+
+ if (!(_gdk_debug_flags & GDK_DEBUG_XINERAMA))
+ return FALSE;
+
+ /* Fake Xinerama mode by splitting the screen into 4 monitors.
+ * Also draw a little cross to make the monitor boundaries visible.
+ */
+ w = WidthOfScreen (screen_x11->xscreen);
+ h = HeightOfScreen (screen_x11->xscreen);
+
+ screen_x11->n_monitors = 4;
+ screen_x11->monitors = g_new0 (GdkX11Monitor, 4);
+ init_monitor_geometry (&screen_x11->monitors[0], 0, 0, w / 2, h / 2);
+ init_monitor_geometry (&screen_x11->monitors[1], w / 2, 0, w / 2, h / 2);
+ init_monitor_geometry (&screen_x11->monitors[2], 0, h / 2, w / 2, h / 2);
+ init_monitor_geometry (&screen_x11->monitors[3], w / 2, h / 2, w / 2, h / 2);
+
+ atts.override_redirect = 1;
+ atts.background_pixel = WhitePixel(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->screen_num);
+ win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->xroot_window, 0, h / 2, w, 1, 0,
+ DefaultDepth(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->screen_num),
+ InputOutput,
+ DefaultVisual(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->screen_num),
+ CWOverrideRedirect|CWBackPixel,
+ &atts);
+ XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
+ win = XCreateWindow(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->xroot_window, w/2 , 0, 1, h, 0,
+ DefaultDepth(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->screen_num),
+ InputOutput,
+ DefaultVisual(GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->screen_num),
+ CWOverrideRedirect|CWBackPixel,
+ &atts);
+ XMapRaised(GDK_SCREEN_XDISPLAY (screen), win);
+ return TRUE;
+#endif
+
+ return FALSE;
+}
+
+static void
+free_monitors (GdkX11Monitor *monitors,
+ gint n_monitors)
+{
+ int i;
+
+ for (i = 0; i < n_monitors; ++i)
+ {
+ g_free (monitors[i].output_name);
+ g_free (monitors[i].manufacturer);
+ }
+
+ g_free (monitors);
+}
+
+#ifdef HAVE_RANDR
+static int
+monitor_compare_function (GdkX11Monitor *monitor1,
+ GdkX11Monitor *monitor2)
+{
+ /* Sort the leftmost/topmost monitors first.
+ * For "cloned" monitors, sort the bigger ones first
+ * (giving preference to taller monitors over wider
+ * monitors)
+ */
+
+ if (monitor1->geometry.x != monitor2->geometry.x)
+ return monitor1->geometry.x - monitor2->geometry.x;
+
+ if (monitor1->geometry.y != monitor2->geometry.y)
+ return monitor1->geometry.y - monitor2->geometry.y;
+
+ if (monitor1->geometry.height != monitor2->geometry.height)
+ return - (monitor1->geometry.height - monitor2->geometry.height);
+
+ if (monitor1->geometry.width != monitor2->geometry.width)
+ return - (monitor1->geometry.width - monitor2->geometry.width);
+
+ return 0;
+}
+#endif
+
+static gboolean
+init_randr13 (GdkScreen *screen)
+{
+#ifdef HAVE_RANDR
+ GdkDisplay *display = gdk_screen_get_display (screen);
+ GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+ XRRScreenResources *resources;
+ RROutput primary_output;
+ RROutput first_output = None;
+ int i;
+ GArray *monitors;
+ gboolean randr12_compat = FALSE;
+
+ if (!display_x11->have_randr13)
+ return FALSE;
+
+ resources = XRRGetScreenResourcesCurrent (screen_x11->xdisplay,
+ screen_x11->xroot_window);
+ if (!resources)
+ return FALSE;
+
+ monitors = g_array_sized_new (FALSE, TRUE, sizeof (GdkX11Monitor),
+ resources->noutput);
+
+ for (i = 0; i < resources->noutput; ++i)
+ {
+ XRROutputInfo *output =
+ XRRGetOutputInfo (dpy, resources, resources->outputs[i]);
+
+ /* Non RandR1.2 X driver have output name "default" */
+ randr12_compat |= !g_strcmp0 (output->name, "default");
+
+ if (output->connection == RR_Disconnected)
+ {
+ XRRFreeOutputInfo (output);
+ continue;
+ }
+
+ if (output->crtc)
+ {
+ GdkX11Monitor monitor;
+ XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, output->crtc);
+
+ monitor.geometry.x = crtc->x;
+ monitor.geometry.y = crtc->y;
+ monitor.geometry.width = crtc->width;
+ monitor.geometry.height = crtc->height;
+
+ monitor.output = resources->outputs[i];
+ monitor.width_mm = output->mm_width;
+ monitor.height_mm = output->mm_height;
+ monitor.output_name = g_strdup (output->name);
+ /* FIXME: need EDID parser */
+ monitor.manufacturer = NULL;
+
+ g_array_append_val (monitors, monitor);
+
+ XRRFreeCrtcInfo (crtc);
+ }
+
+ XRRFreeOutputInfo (output);
+ }
+
+ if (resources->noutput > 0)
+ first_output = resources->outputs[0];
+
+ XRRFreeScreenResources (resources);
+
+ /* non RandR 1.2 X driver doesn't return any usable multihead data */
+ if (randr12_compat)
+ {
+ guint n_monitors = monitors->len;
+
+ free_monitors ((GdkX11Monitor *)g_array_free (monitors, FALSE),
+ n_monitors);
+
+ return FALSE;
+ }
+
+ g_array_sort (monitors,
+ (GCompareFunc) monitor_compare_function);
+ screen_x11->n_monitors = monitors->len;
+ screen_x11->monitors = (GdkX11Monitor *)g_array_free (monitors, FALSE);
+
+ screen_x11->primary_monitor = 0;
+
+ primary_output = XRRGetOutputPrimary (screen_x11->xdisplay,
+ screen_x11->xroot_window);
+
+ for (i = 0; i < screen_x11->n_monitors; ++i)
+ {
+ if (screen_x11->monitors[i].output == primary_output)
+ {
+ screen_x11->primary_monitor = i;
+ break;
+ }
+
+ /* No RandR1.3+ available or no primary set, fall back to prefer LVDS as primary if present */
+ if (primary_output == None &&
+ g_ascii_strncasecmp (screen_x11->monitors[i].output_name, "LVDS", 4) == 0)
+ {
+ screen_x11->primary_monitor = i;
+ break;
+ }
+
+ /* No primary specified and no LVDS found */
+ if (screen_x11->monitors[i].output == first_output)
+ screen_x11->primary_monitor = i;
+ }
+
+ return screen_x11->n_monitors > 0;
+#endif
+
+ return FALSE;
+}
+
+static gboolean
+init_solaris_xinerama (GdkScreen *screen)
+{
+#ifdef HAVE_SOLARIS_XINERAMA
+ Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+ int screen_no = gdk_screen_get_number (screen);
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ XRectangle monitors[MAXFRAMEBUFFERS];
+ unsigned char hints[16];
+ gint result;
+ int n_monitors;
+ int i;
+
+ if (!XineramaGetState (dpy, screen_no))
+ return FALSE;
+
+ result = XineramaGetInfo (dpy, screen_no, monitors, hints, &n_monitors);
+
+ /* Yes I know it should be Success but the current implementation
+ * returns the num of monitor
+ */
+ if (result == 0)
+ {
+ return FALSE;
+ }
+
+ screen_x11->monitors = g_new0 (GdkX11Monitor, n_monitors);
+ screen_x11->n_monitors = n_monitors;
+
+ for (i = 0; i < n_monitors; i++)
+ {
+ init_monitor_geometry (&screen_x11->monitors[i],
+ monitors[i].x, monitors[i].y,
+ monitors[i].width, monitors[i].height);
+ }
+
+ screen_x11->primary_monitor = 0;
+
+ return TRUE;
+#endif /* HAVE_SOLARIS_XINERAMA */
+
+ return FALSE;
+}
+
+static gboolean
+init_xfree_xinerama (GdkScreen *screen)
+{
+#ifdef HAVE_XFREE_XINERAMA
+ Display *dpy = GDK_SCREEN_XDISPLAY (screen);
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ XineramaScreenInfo *monitors;
+ int i, n_monitors;
+
+ if (!XineramaIsActive (dpy))
+ return FALSE;
+
+ monitors = XineramaQueryScreens (dpy, &n_monitors);
+
+ if (n_monitors <= 0 || monitors == NULL)
+ {
+ /* If Xinerama doesn't think we have any monitors, try acting as
+ * though we had no Xinerama. If the "no monitors" condition
+ * is because XRandR 1.2 is currently switching between CRTCs,
+ * we'll be notified again when we have our monitor back,
+ * and can go back into Xinerama-ish mode at that point.
+ */
+ if (monitors)
+ XFree (monitors);
+
+ return FALSE;
+ }
+
+ screen_x11->n_monitors = n_monitors;
+ screen_x11->monitors = g_new0 (GdkX11Monitor, n_monitors);
+
+ for (i = 0; i < n_monitors; ++i)
+ {
+ init_monitor_geometry (&screen_x11->monitors[i],
+ monitors[i].x_org, monitors[i].y_org,
+ monitors[i].width, monitors[i].height);
+ }
+
+ XFree (monitors);
+
+ screen_x11->primary_monitor = 0;
+
+ return TRUE;
+#endif /* HAVE_XFREE_XINERAMA */
+
+ return FALSE;
+}
+
+static void
+deinit_multihead (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ free_monitors (screen_x11->monitors, screen_x11->n_monitors);
+
+ screen_x11->n_monitors = 0;
+ screen_x11->monitors = NULL;
+}
+
+static gboolean
+compare_monitor (GdkX11Monitor *m1,
+ GdkX11Monitor *m2)
+{
+ if (m1->geometry.x != m2->geometry.x ||
+ m1->geometry.y != m2->geometry.y ||
+ m1->geometry.width != m2->geometry.width ||
+ m1->geometry.height != m2->geometry.height)
+ return FALSE;
+
+ if (m1->width_mm != m2->width_mm ||
+ m1->height_mm != m2->height_mm)
+ return FALSE;
+
+ if (g_strcmp0 (m1->output_name, m2->output_name) != 0)
+ return FALSE;
+
+ if (g_strcmp0 (m1->manufacturer, m2->manufacturer) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+compare_monitors (GdkX11Monitor *monitors1, gint n_monitors1,
+ GdkX11Monitor *monitors2, gint n_monitors2)
+{
+ gint i;
+
+ if (n_monitors1 != n_monitors2)
+ return FALSE;
+
+ for (i = 0; i < n_monitors1; i++)
+ {
+ if (!compare_monitor (monitors1 + i, monitors2 + i))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+init_multihead (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ int opcode, firstevent, firsterror;
+
+ /* There are four different implementations of multihead support:
+ *
+ * 1. Fake Xinerama for debugging purposes
+ * 2. RandR 1.2
+ * 3. Solaris Xinerama
+ * 4. XFree86/Xorg Xinerama
+ *
+ * We use them in that order.
+ */
+ if (init_fake_xinerama (screen))
+ return;
+
+ if (init_randr13 (screen))
+ return;
+
+ if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
+ &opcode, &firstevent, &firsterror))
+ {
+ if (init_solaris_xinerama (screen))
+ return;
+
+ if (init_xfree_xinerama (screen))
+ return;
+ }
+
+ /* No multihead support of any kind for this screen */
+ screen_x11->n_monitors = 1;
+ screen_x11->monitors = g_new0 (GdkX11Monitor, 1);
+ screen_x11->primary_monitor = 0;
+
+ init_monitor_geometry (screen_x11->monitors, 0, 0,
+ WidthOfScreen (screen_x11->xscreen),
+ HeightOfScreen (screen_x11->xscreen));
+}
+
+GdkScreen *
+_gdk_x11_screen_new (GdkDisplay *display,
+ gint screen_number)
+{
+ GdkScreen *screen;
+ GdkScreenX11 *screen_x11;
+ GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
+
+ screen = g_object_new (GDK_TYPE_SCREEN_X11, NULL);
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+ screen_x11->display = display;
+ screen_x11->xdisplay = display_x11->xdisplay;
+ screen_x11->xscreen = ScreenOfDisplay (display_x11->xdisplay, screen_number);
+ screen_x11->screen_num = screen_number;
+ screen_x11->xroot_window = RootWindow (display_x11->xdisplay,screen_number);
+ screen_x11->wmspec_check_window = None;
+ /* we want this to be always non-null */
+ screen_x11->window_manager_name = g_strdup ("unknown");
+
+ init_multihead (screen);
+ init_randr_support (screen);
+
+ _gdk_visual_init (screen);
+ _gdk_windowing_window_init (screen);
+
+ return screen;
+}
+
+/*
+ * It is important that we first request the selection
+ * notification, and then setup the initial state of
+ * is_composited to avoid a race condition here.
+ */
+void
+_gdk_x11_screen_setup (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ screen_x11->cm_selection_atom = make_cm_atom (screen_x11->screen_num);
+ gdk_display_request_selection_notification (screen_x11->display,
+ screen_x11->cm_selection_atom);
+ screen_x11->is_composited = check_is_composited (screen_x11->display, screen_x11);
+}
+
+/**
+ * gdk_screen_is_composited:
+ * @screen: a #GdkScreen
+ *
+ * Returns whether windows with an RGBA visual can reasonably
+ * be expected to have their alpha channel drawn correctly on
+ * the screen.
+ *
+ * On X11 this function returns whether a compositing manager is
+ * compositing @screen.
+ *
+ * Return value: Whether windows with RGBA visuals can reasonably be
+ * expected to have their alpha channels drawn correctly on the screen.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gdk_screen_is_composited (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+
+ return screen_x11->is_composited;
+}
+
+static void
+init_randr_support (GdkScreen * screen)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ XSelectInput (GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->xroot_window,
+ StructureNotifyMask);
+
+#ifdef HAVE_RANDR
+ XRRSelectInput (GDK_SCREEN_XDISPLAY (screen),
+ screen_x11->xroot_window,
+ RRScreenChangeNotifyMask |
+ RRCrtcChangeNotifyMask |
+ RROutputPropertyNotifyMask);
+#endif
+}
+
+static void
+process_monitors_change (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ gint n_monitors;
+ GdkX11Monitor *monitors;
+ gboolean changed;
+
+ n_monitors = screen_x11->n_monitors;
+ monitors = screen_x11->monitors;
+
+ screen_x11->n_monitors = 0;
+ screen_x11->monitors = NULL;
+
+ init_multihead (screen);
+
+ changed = !compare_monitors (monitors, n_monitors,
+ screen_x11->monitors, screen_x11->n_monitors);
+
+ free_monitors (monitors, n_monitors);
+
+ if (changed)
+ g_signal_emit_by_name (screen, "monitors-changed");
+}
+
+void
+_gdk_x11_screen_size_changed (GdkScreen *screen,
+ XEvent *event)
+{
+ gint width, height;
+#ifdef HAVE_RANDR
+ GdkDisplayX11 *display_x11;
+#endif
+
+ width = gdk_screen_get_width (screen);
+ height = gdk_screen_get_height (screen);
+
+#ifdef HAVE_RANDR
+ display_x11 = GDK_DISPLAY_X11 (gdk_screen_get_display (screen));
+
+ if (display_x11->have_randr13 && event->type == ConfigureNotify)
+ {
+ g_signal_emit_by_name (screen, "monitors-changed");
+ return;
+ }
+
+ XRRUpdateConfiguration (event);
+#else
+ if (event->type == ConfigureNotify)
+ {
+ XConfigureEvent *rcevent = (XConfigureEvent *) event;
+ Screen *xscreen = gdk_x11_screen_get_xscreen (screen);
+
+ xscreen->width = rcevent->width;
+ xscreen->height = rcevent->height;
+ }
+ else
+ return;
+#endif
+
+ process_monitors_change (screen);
+
+ if (width != gdk_screen_get_width (screen) ||
+ height != gdk_screen_get_height (screen))
+ g_signal_emit_by_name (screen, "size-changed");
+}
+
+void
+_gdk_x11_screen_window_manager_changed (GdkScreen *screen)
+{
+ g_signal_emit (screen, signals[WINDOW_MANAGER_CHANGED], 0);
+}
+
+void
+_gdk_x11_screen_process_owner_change (GdkScreen *screen,
+ XEvent *event)
+{
+#ifdef HAVE_XFIXES
+ XFixesSelectionNotifyEvent *selection_event = (XFixesSelectionNotifyEvent *)event;
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+ Atom xcm_selection_atom = gdk_x11_atom_to_xatom_for_display (screen_x11->display,
+ screen_x11->cm_selection_atom);
+
+ if (selection_event->selection == xcm_selection_atom)
+ {
+ gboolean composited = selection_event->owner != None;
+
+ if (composited != screen_x11->is_composited)
+ {
+ screen_x11->is_composited = composited;
+
+ g_signal_emit_by_name (screen, "composited-changed");
+ }
+ }
+#endif
+}
+
+/**
+ * _gdk_windowing_substitute_screen_number:
+ * @display_name: The name of a display, in the form used by
+ * gdk_display_open (). If %NULL a default value
+ * will be used. On X11, this is derived from the DISPLAY
+ * environment variable.
+ * @screen_number: The number of a screen within the display
+ * referred to by @display_name.
+ *
+ * Modifies a @display_name to make @screen_number the default
+ * screen when the display is opened.
+ *
+ * Return value: a newly allocated string holding the resulting
+ * display name. Free with g_free().
+ */
+gchar *
+_gdk_windowing_substitute_screen_number (const gchar *display_name,
+ gint screen_number)
+{
+ GString *str;
+ gchar *p;
+
+ if (!display_name)
+ display_name = getenv ("DISPLAY");
+
+ if (!display_name)
+ return NULL;
+
+ str = g_string_new (display_name);
+
+ p = strrchr (str->str, '.');
+ if (p && p > strchr (str->str, ':'))
+ g_string_truncate (str, p - str->str);
+
+ g_string_append_printf (str, ".%d", screen_number);
+
+ return g_string_free (str, FALSE);
+}
+
+/**
+ * gdk_screen_make_display_name:
+ * @screen: a #GdkScreen
+ *
+ * Determines the name to pass to gdk_display_open() to get
+ * a #GdkDisplay with this screen as the default screen.
+ *
+ * Return value: a newly allocated string, free with g_free()
+ *
+ * Since: 2.2
+ **/
+gchar *
+gdk_screen_make_display_name (GdkScreen *screen)
+{
+ const gchar *old_display;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+ old_display = gdk_display_get_name (gdk_screen_get_display (screen));
+
+ return _gdk_windowing_substitute_screen_number (old_display,
+ gdk_screen_get_number (screen));
+}
+
+/**
+ * gdk_screen_get_active_window
+ * @screen: a #GdkScreen
+ *
+ * Returns the screen's currently active window.
+ *
+ * On X11, this is done by inspecting the _NET_ACTIVE_WINDOW property
+ * on the root window, as described in the <ulink
+ * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window
+ * Manager Hints</ulink>. If there is no currently currently active
+ * window, or the window manager does not support the
+ * _NET_ACTIVE_WINDOW hint, this function returns %NULL.
+ *
+ * On other platforms, this function may return %NULL, depending on whether
+ * it is implementable on that platform.
+ *
+ * The returned window should be unrefed using g_object_unref() when
+ * no longer needed.
+ *
+ * Return value: the currently active window, or %NULL.
+ *
+ * Since: 2.10
+ **/
+GdkWindow *
+gdk_screen_get_active_window (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11;
+ GdkWindow *ret = NULL;
+ Atom type_return;
+ gint format_return;
+ gulong nitems_return;
+ gulong bytes_after_return;
+ guchar *data = NULL;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+ if (!gdk_x11_screen_supports_net_wm_hint (screen,
+ gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW")))
+ return NULL;
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+
+ if (XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
+ gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
+ "_NET_ACTIVE_WINDOW"),
+ 0, 1, False, XA_WINDOW, &type_return,
+ &format_return, &nitems_return,
+ &bytes_after_return, &data)
+ == Success)
+ {
+ if ((type_return == XA_WINDOW) && (format_return == 32) && (data))
+ {
+ GdkNativeWindow window = *(GdkNativeWindow *) data;
+
+ if (window != None)
+ {
+ ret = gdk_window_foreign_new_for_display (screen_x11->display,
+ *(GdkNativeWindow *) data);
+ }
+ }
+ }
+
+ if (data)
+ XFree (data);
+
+ return ret;
+}
+
+/**
+ * gdk_screen_get_window_stack:
+ * @screen: a #GdkScreen
+ *
+ * Returns a #GList of #GdkWindow<!-- -->s representing the current
+ * window stack.
+ *
+ * On X11, this is done by inspecting the _NET_CLIENT_LIST_STACKING
+ * property on the root window, as described in the <ulink
+ * url="http://www.freedesktop.org/Standards/wm-spec">Extended Window
+ * Manager Hints</ulink>. If the window manager does not support the
+ * _NET_CLIENT_LIST_STACKING hint, this function returns %NULL.
+ *
+ * On other platforms, this function may return %NULL, depending on whether
+ * it is implementable on that platform.
+ *
+ * The returned list is newly allocated and owns references to the
+ * windows it contains, so it should be freed using g_list_free() and
+ * its windows unrefed using g_object_unref() when no longer needed.
+ *
+ * Return value: (transfer full) (element-type GdkWindow):
+ * a list of #GdkWindow<!-- -->s for the current window stack,
+ * or %NULL.
+ *
+ * Since: 2.10
+ **/
+GList *
+gdk_screen_get_window_stack (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11;
+ GList *ret = NULL;
+ Atom type_return;
+ gint format_return;
+ gulong nitems_return;
+ gulong bytes_after_return;
+ guchar *data = NULL;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
+
+ if (!gdk_x11_screen_supports_net_wm_hint (screen,
+ gdk_atom_intern_static_string ("_NET_CLIENT_LIST_STACKING")))
+ return NULL;
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+
+ if (XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
+ gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
+ "_NET_CLIENT_LIST_STACKING"),
+ 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) && (nitems_return > 0))
+ {
+ gulong *stack = (gulong *) data;
+ GdkWindow *win;
+ int i;
+
+ for (i = 0; i < nitems_return; i++)
+ {
+ win = gdk_window_foreign_new_for_display (screen_x11->display,
+ (GdkNativeWindow)stack[i]);
+
+ if (win != NULL)
+ ret = g_list_append (ret, win);
+ }
+ }
+ }
+
+ if (data)
+ XFree (data);
+
+ return ret;
+}
+
+/* Sends a ClientMessage to all toplevel client windows */
+static gboolean
+gdk_event_send_client_message_to_all_recurse (GdkDisplay *display,
+ XEvent *xev,
+ guint32 xid,
+ guint level)
+{
+ Atom type = None;
+ int format;
+ unsigned long nitems, after;
+ unsigned char *data;
+ Window *ret_children, ret_root, ret_parent;
+ unsigned int ret_nchildren;
+ gboolean send = FALSE;
+ gboolean found = FALSE;
+ gboolean result = FALSE;
+ int i;
+
+ gdk_error_trap_push ();
+
+ if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid,
+ gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE"),
+ 0, 0, False, AnyPropertyType,
+ &type, &format, &nitems, &after, &data) != Success)
+ goto out;
+
+ if (type)
+ {
+ send = TRUE;
+ XFree (data);
+ }
+ else
+ {
+ /* OK, we're all set, now let's find some windows to send this to */
+ if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xid,
+ &ret_root, &ret_parent,
+ &ret_children, &ret_nchildren))
+ goto out;
+
+ for(i = 0; i < ret_nchildren; i++)
+ if (gdk_event_send_client_message_to_all_recurse (display, xev, ret_children[i], level + 1))
+ found = TRUE;
+
+ XFree (ret_children);
+ }
+
+ if (send || (!found && (level == 1)))
+ {
+ xev->xclient.window = xid;
+ _gdk_send_xevent (display, xid, False, NoEventMask, xev);
+ }
+
+ result = send || found;
+
+ out:
+ gdk_error_trap_pop_ignored ();
+
+ return result;
+}
+
+/**
+ * gdk_screen_broadcast_client_message:
+ * @screen: the #GdkScreen where the event will be broadcasted.
+ * @event: the #GdkEvent.
+ *
+ * On X11, sends an X ClientMessage event to all toplevel windows on
+ * @screen.
+ *
+ * Toplevel windows are determined by checking for the WM_STATE property,
+ * as described in the Inter-Client Communication Conventions Manual (ICCCM).
+ * If no windows are found with the WM_STATE property set, the message is
+ * sent to all children of the root window.
+ *
+ * On Windows, broadcasts a message registered with the name
+ * GDK_WIN32_CLIENT_MESSAGE to all top-level windows. The amount of
+ * data is limited to one long, i.e. four bytes.
+ *
+ * Since: 2.2
+ */
+
+void
+gdk_screen_broadcast_client_message (GdkScreen *screen,
+ GdkEvent *event)
+{
+ XEvent sev;
+ GdkWindow *root_window;
+
+ g_return_if_fail (event != NULL);
+
+ root_window = gdk_screen_get_root_window (screen);
+
+ /* Set up our event to send, with the exception of its target window */
+ sev.xclient.type = ClientMessage;
+ sev.xclient.display = GDK_WINDOW_XDISPLAY (root_window);
+ sev.xclient.format = event->client.data_format;
+ memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
+ sev.xclient.message_type =
+ gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (root_window),
+ event->client.message_type);
+
+ gdk_event_send_client_message_to_all_recurse (gdk_screen_get_display (screen),
+ &sev,
+ GDK_WINDOW_XID (root_window),
+ 0);
+}
+
+static gboolean
+check_transform (const gchar *xsettings_name,
+ GType src_type,
+ GType dest_type)
+{
+ if (!g_value_type_transformable (src_type, dest_type))
+ {
+ g_warning ("Cannot transform xsetting %s of type %s to type %s\n",
+ xsettings_name,
+ g_type_name (src_type),
+ g_type_name (dest_type));
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+/**
+ * gdk_screen_get_setting:
+ * @screen: the #GdkScreen where the setting is located
+ * @name: the name of the setting
+ * @value: location to store the value of the setting
+ *
+ * Retrieves a desktop-wide setting such as double-click time
+ * for the #GdkScreen @screen.
+ *
+ * FIXME needs a list of valid settings here, or a link to
+ * more information.
+ *
+ * Returns: %TRUE if the setting existed and a value was stored
+ * in @value, %FALSE otherwise.
+ *
+ * Since: 2.2
+ **/
+gboolean
+gdk_screen_get_setting (GdkScreen *screen,
+ const gchar *name,
+ GValue *value)
+{
+
+ const char *xsettings_name = NULL;
+ XSettingsResult result;
+ XSettingsSetting *setting = NULL;
+ GdkScreenX11 *screen_x11;
+ gboolean success = FALSE;
+ gint i;
+ GValue tmp_val = { 0, };
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+
+ for (i = 0; i < GDK_SETTINGS_N_ELEMENTS(); i++)
+ if (strcmp (GDK_SETTINGS_GDK_NAME (i), name) == 0)
+ {
+ xsettings_name = GDK_SETTINGS_X_NAME (i);
+ break;
+ }
+
+ if (!xsettings_name)
+ goto out;
+
+ result = xsettings_client_get_setting (screen_x11->xsettings_client,
+ xsettings_name, &setting);
+ if (result != XSETTINGS_SUCCESS)
+ goto out;
+
+ switch (setting->type)
+ {
+ case XSETTINGS_TYPE_INT:
+ if (check_transform (xsettings_name, G_TYPE_INT, G_VALUE_TYPE (value)))
+ {
+ g_value_init (&tmp_val, G_TYPE_INT);
+ g_value_set_int (&tmp_val, setting->data.v_int);
+ g_value_transform (&tmp_val, value);
+
+ success = TRUE;
+ }
+ break;
+ case XSETTINGS_TYPE_STRING:
+ if (check_transform (xsettings_name, G_TYPE_STRING, G_VALUE_TYPE (value)))
+ {
+ g_value_init (&tmp_val, G_TYPE_STRING);
+ g_value_set_string (&tmp_val, setting->data.v_string);
+ g_value_transform (&tmp_val, value);
+
+ success = TRUE;
+ }
+ break;
+ case XSETTINGS_TYPE_COLOR:
+ if (!check_transform (xsettings_name, GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
+ {
+ GdkColor color;
+
+ g_value_init (&tmp_val, GDK_TYPE_COLOR);
+
+ color.pixel = 0;
+ color.red = setting->data.v_color.red;
+ color.green = setting->data.v_color.green;
+ color.blue = setting->data.v_color.blue;
+
+ g_value_set_boxed (&tmp_val, &color);
+
+ g_value_transform (&tmp_val, value);
+
+ success = TRUE;
+ }
+ break;
+ }
+
+ g_value_unset (&tmp_val);
+
+ out:
+ if (setting)
+ xsettings_setting_free (setting);
+
+ if (success)
+ return TRUE;
+ else
+ return _gdk_x11_get_xft_setting (screen, name, value);
+}
+
+static void
+cleanup_atoms(gpointer data)
+{
+ NetWmSupportedAtoms *supported_atoms = data;
+ if (supported_atoms->atoms)
+ XFree (supported_atoms->atoms);
+ g_free (supported_atoms);
+}
+
+static void
+fetch_net_wm_check_window (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11;
+ GdkDisplay *display;
+ Atom type;
+ gint format;
+ gulong n_items;
+ gulong bytes_after;
+ guchar *data;
+ Window *xwindow;
+ GTimeVal tv;
+ gint error;
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+ display = screen_x11->display;
+
+ g_return_if_fail (GDK_DISPLAY_X11 (display)->trusted_client);
+
+ g_get_current_time (&tv);
+
+ if (ABS (tv.tv_sec - screen_x11->last_wmspec_check_time) < 15)
+ return; /* we've checked recently */
+
+ screen_x11->last_wmspec_check_time = tv.tv_sec;
+
+ data = NULL;
+ XGetWindowProperty (screen_x11->xdisplay, screen_x11->xroot_window,
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"),
+ 0, G_MAXLONG, False, XA_WINDOW, &type, &format,
+ &n_items, &bytes_after, &data);
+
+ if (type != XA_WINDOW)
+ {
+ if (data)
+ XFree (data);
+ return;
+ }
+
+ xwindow = (Window *)data;
+
+ if (screen_x11->wmspec_check_window == *xwindow)
+ {
+ XFree (xwindow);
+ return;
+ }
+
+ gdk_error_trap_push ();
+
+ /* Find out if this WM goes away, so we can reset everything. */
+ XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask);
+
+ error = gdk_error_trap_pop ();
+ if (!error)
+ {
+ screen_x11->wmspec_check_window = *xwindow;
+ screen_x11->need_refetch_net_supported = TRUE;
+ screen_x11->need_refetch_wm_name = TRUE;
+
+ /* Careful, reentrancy */
+ _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
+ }
+ else if (error == BadWindow)
+ {
+ /* Leftover property, try again immediately, new wm may be starting up */
+ screen_x11->last_wmspec_check_time = 0;
+ }
+
+ XFree (xwindow);
+}
+
+/**
+ * gdk_x11_screen_supports_net_wm_hint:
+ * @screen: the relevant #GdkScreen.
+ * @property: a property atom.
+ *
+ * This function is specific to the X11 backend of GDK, and indicates
+ * whether the window manager supports a certain hint from the
+ * Extended Window Manager Hints Specification. You can find this
+ * specification on
+ * <ulink url="http://www.freedesktop.org">http://www.freedesktop.org</ulink>.
+ *
+ * When using this function, keep in mind that the window manager
+ * can change over time; so you shouldn't use this function in
+ * a way that impacts persistent application state. A common bug
+ * is that your application can start up before the window manager
+ * does when the user logs in, and before the window manager starts
+ * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property.
+ * You can monitor the window_manager_changed signal on #GdkScreen to detect
+ * a window manager change.
+ *
+ * Return value: %TRUE if the window manager supports @property
+ *
+ * Since: 2.2
+ **/
+gboolean
+gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
+ GdkAtom property)
+{
+ gulong i;
+ GdkScreenX11 *screen_x11;
+ NetWmSupportedAtoms *supported_atoms;
+ GdkDisplay *display;
+
+ g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+ display = screen_x11->display;
+
+ if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
+ return FALSE;
+
+ supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
+ if (!supported_atoms)
+ {
+ supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
+ g_object_set_data_full (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms, cleanup_atoms);
+ }
+
+ fetch_net_wm_check_window (screen);
+
+ if (screen_x11->wmspec_check_window == None)
+ return FALSE;
+
+ if (screen_x11->need_refetch_net_supported)
+ {
+ /* WM has changed since we last got the supported list,
+ * refetch it.
+ */
+ Atom type;
+ gint format;
+ gulong bytes_after;
+
+ screen_x11->need_refetch_net_supported = FALSE;
+
+ if (supported_atoms->atoms)
+ XFree (supported_atoms->atoms);
+
+ supported_atoms->atoms = NULL;
+ supported_atoms->n_atoms = 0;
+
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window,
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"),
+ 0, G_MAXLONG, False, XA_ATOM, &type, &format,
+ &supported_atoms->n_atoms, &bytes_after,
+ (guchar **)&supported_atoms->atoms);
+
+ if (type != XA_ATOM)
+ return FALSE;
+ }
+
+ if (supported_atoms->atoms == NULL)
+ return FALSE;
+
+ i = 0;
+ while (i < supported_atoms->n_atoms)
+ {
+ if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property))
+ return TRUE;
+
+ ++i;
+ }
+
+ return FALSE;
+}
+
+/**
+ * gdk_net_wm_supports:
+ * @property: a property atom.
+ *
+ * This function is specific to the X11 backend of GDK, and indicates
+ * whether the window manager for the default screen supports a certain
+ * hint from the Extended Window Manager Hints Specification. See
+ * gdk_x11_screen_supports_net_wm_hint() for complete details.
+ *
+ * Return value: %TRUE if the window manager supports @property
+ **/
+gboolean
+gdk_net_wm_supports (GdkAtom property)
+{
+ return gdk_x11_screen_supports_net_wm_hint (gdk_screen_get_default (), property);
+}
+
+static void
+refcounted_grab_server (Display *xdisplay)
+{
+ GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
+
+ gdk_x11_display_grab (display);
+}
+
+static void
+refcounted_ungrab_server (Display *xdisplay)
+{
+ GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
+
+ gdk_x11_display_ungrab (display);
+}
+
+static GdkFilterReturn
+gdk_xsettings_client_event_filter (GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ GdkScreenX11 *screen = data;
+
+ if (xsettings_client_process_event (screen->xsettings_client, (XEvent *)xevent))
+ return GDK_FILTER_REMOVE;
+ else
+ return GDK_FILTER_CONTINUE;
+}
+
+static Bool
+gdk_xsettings_watch_cb (Window window,
+ Bool is_start,
+ long mask,
+ void *cb_data)
+{
+ GdkWindow *gdkwin;
+ GdkScreen *screen = cb_data;
+
+ gdkwin = gdk_window_lookup_for_display (gdk_screen_get_display (screen), window);
+
+ if (is_start)
+ {
+ if (gdkwin)
+ g_object_ref (gdkwin);
+ else
+ {
+ gdkwin = gdk_window_foreign_new_for_display (gdk_screen_get_display (screen), window);
+
+ /* gdk_window_foreign_new_for_display() can fail and return NULL if the
+ * window has already been destroyed.
+ */
+ if (!gdkwin)
+ return False;
+ }
+
+ gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+ }
+ else
+ {
+ if (!gdkwin)
+ {
+ /* gdkwin should not be NULL here, since if starting the watch succeeded
+ * we have a reference on the window. It might mean that the caller didn't
+ * remove the watch when it got a DestroyNotify event. Or maybe the
+ * caller ignored the return value when starting the watch failed.
+ */
+ g_warning ("gdk_xsettings_watch_cb(): Couldn't find window to unwatch");
+ return False;
+ }
+
+ gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
+ g_object_unref (gdkwin);
+ }
+
+ return True;
+}
+
+static void
+gdk_xsettings_notify_cb (const char *name,
+ XSettingsAction action,
+ XSettingsSetting *setting,
+ void *data)
+{
+ GdkEvent new_event;
+ GdkScreen *screen = data;
+ GdkScreenX11 *screen_x11 = data;
+ int i;
+
+ if (screen_x11->xsettings_in_init)
+ return;
+
+ new_event.type = GDK_SETTING;
+ new_event.setting.window = gdk_screen_get_root_window (screen);
+ new_event.setting.send_event = FALSE;
+ new_event.setting.name = NULL;
+
+ for (i = 0; i < GDK_SETTINGS_N_ELEMENTS() ; i++)
+ if (strcmp (GDK_SETTINGS_X_NAME (i), name) == 0)
+ {
+ new_event.setting.name = (char*) GDK_SETTINGS_GDK_NAME (i);
+ break;
+ }
+
+ if (!new_event.setting.name)
+ return;
+
+ switch (action)
+ {
+ case XSETTINGS_ACTION_NEW:
+ new_event.setting.action = GDK_SETTING_ACTION_NEW;
+ break;
+ case XSETTINGS_ACTION_CHANGED:
+ new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
+ break;
+ case XSETTINGS_ACTION_DELETED:
+ new_event.setting.action = GDK_SETTING_ACTION_DELETED;
+ break;
+ }
+
+ gdk_event_put (&new_event);
+}
+
+void
+_gdk_screen_x11_events_init (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+
+ /* Keep a flag to avoid extra notifies that we don't need
+ */
+ screen_x11->xsettings_in_init = TRUE;
+ screen_x11->xsettings_client = xsettings_client_new_with_grab_funcs (screen_x11->xdisplay,
+ screen_x11->screen_num,
+ gdk_xsettings_notify_cb,
+ gdk_xsettings_watch_cb,
+ screen,
+ refcounted_grab_server,
+ refcounted_ungrab_server);
+ screen_x11->xsettings_in_init = FALSE;
+}
+
+/**
+ * gdk_x11_screen_get_window_manager_name:
+ * @screen: a #GdkScreen
+ *
+ * Returns the name of the window manager for @screen.
+ *
+ * Return value: the name of the window manager screen @screen, or
+ * "unknown" if the window manager is unknown. The string is owned by GDK
+ * and should not be freed.
+ *
+ * Since: 2.2
+ **/
+const char*
+gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
+{
+ GdkScreenX11 *screen_x11;
+
+ screen_x11 = GDK_SCREEN_X11 (screen);
+
+ if (!G_LIKELY (GDK_DISPLAY_X11 (screen_x11->display)->trusted_client))
+ return screen_x11->window_manager_name;
+
+ fetch_net_wm_check_window (screen);
+
+ if (screen_x11->need_refetch_wm_name)
+ {
+ /* Get the name of the window manager */
+ screen_x11->need_refetch_wm_name = FALSE;
+
+ g_free (screen_x11->window_manager_name);
+ screen_x11->window_manager_name = g_strdup ("unknown");
+
+ if (screen_x11->wmspec_check_window != None)
+ {
+ Atom type;
+ gint format;
+ gulong n_items;
+ gulong bytes_after;
+ gchar *name;
+
+ name = NULL;
+
+ gdk_error_trap_push ();
+
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (screen_x11->display),
+ screen_x11->wmspec_check_window,
+ gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
+ "_NET_WM_NAME"),
+ 0, G_MAXLONG, False,
+ gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
+ "UTF8_STRING"),
+ &type, &format,
+ &n_items, &bytes_after,
+ (guchar **)&name);
+
+ gdk_error_trap_pop_ignored ();
+
+ if (name != NULL)
+ {
+ g_free (screen_x11->window_manager_name);
+ screen_x11->window_manager_name = g_strdup (name);
+ XFree (name);
+ }
+ }
+ }
+
+ return GDK_SCREEN_X11 (screen)->window_manager_name;
+}