]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkscreen-x11.c
Fixes from #98358, Havoc Pennington.
[~andy/gtk] / gdk / x11 / gdkscreen-x11.c
index 61f7e6a9899a3f452d7272d46bec593d084a5ba0..c8f819727b4e02573a75f0632fc9e2958466bc72 100644 (file)
@@ -21,6 +21,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#include <config.h>
 #include <glib.h>
 #include "gdkscreen.h"
 #include "gdkscreen-x11.h"
 #include "gdkdisplay-x11.h"
 #include "gdkx.h"
 
+#ifdef HAVE_XFT
+#include <pango/pangoxft.h>
+#endif
+#include <pango/pangox.h>
+
 #ifdef HAVE_SOLARIS_XINERAMA
 #include <X11/extensions/xinerama.h>
 #endif
 #include <X11/extensions/Xinerama.h>
 #endif
 
-static void         gdk_screen_x11_class_init       (GdkScreenX11Class *klass);
-static GdkDisplay * gdk_screen_x11_get_display           (GdkScreen             *screen);
-static gint         gdk_screen_x11_get_width             (GdkScreen             *screen);
-static gint         gdk_screen_x11_get_height            (GdkScreen             *screen);
-static gint         gdk_screen_x11_get_width_mm          (GdkScreen             *screen);
-static gint         gdk_screen_x11_get_height_mm         (GdkScreen             *screen);
-static gint         gdk_screen_x11_get_default_depth     (GdkScreen             *screen);
-static GdkWindow *  gdk_screen_x11_get_root_window       (GdkScreen             *screen);
-static gint         gdk_screen_x11_get_screen_num        (GdkScreen             *screen);
-static GdkColormap *gdk_screen_x11_get_default_colormap  (GdkScreen             *screen);
-static void         gdk_screen_x11_set_default_colormap  (GdkScreen             *screen,
-                                                         GdkColormap           *colormap);
-static GdkWindow *  gdk_screen_x11_get_window_at_pointer (GdkScreen             *screen,
-                                                         gint                  *win_x,
-                                                         gint                  *win_y);
-static void         gdk_screen_x11_finalize             (GObject               *object);
-
-static gint          gdk_screen_x11_get_n_monitors        (GdkScreen       *screen);
-static void          gdk_screen_x11_get_monitor_geometry  (GdkScreen       *screen,
-                                                          gint             num_monitor,
-                                                          GdkRectangle    *dest);
-static void         init_xinerama_support                (GdkScreen * screen);
-
-
-GType gdk_screen_x11_get_type ();
+static void         gdk_screen_x11_class_init  (GdkScreenX11Class *klass);
+static void         gdk_screen_x11_dispose     (GObject                  *object);
+static void         gdk_screen_x11_finalize    (GObject                  *object);
+static void        init_xinerama_support      (GdkScreen         *screen);
+static void        init_randr_support         (GdkScreen         *screen);
+
+enum
+{
+  WINDOW_MANAGER_CHANGED,
+  LAST_SIGNAL
+};
+
 static gpointer parent_class = NULL;
+static guint signals[LAST_SIGNAL] = { 0 };
 
 GType
-gdk_screen_x11_get_type ()
+_gdk_screen_x11_get_type ()
 {
   static GType object_type = 0;
 
@@ -88,144 +82,200 @@ gdk_screen_x11_get_type ()
   return object_type;
 }
 
-void
-gdk_screen_x11_class_init (GdkScreenX11Class * klass)
+static void
+gdk_screen_x11_class_init (GdkScreenX11Class *klass)
 {
-  GdkScreenClass *screen_class = GDK_SCREEN_CLASS (klass);
-  
-  screen_class->get_display = gdk_screen_x11_get_display;
-  screen_class->get_width = gdk_screen_x11_get_width;
-  screen_class->get_height = gdk_screen_x11_get_height;
-  screen_class->get_width_mm = gdk_screen_x11_get_width_mm;
-  screen_class->get_height_mm = gdk_screen_x11_get_height_mm;
-  screen_class->get_root_depth = gdk_screen_x11_get_default_depth;
-  screen_class->get_screen_num = gdk_screen_x11_get_screen_num;
-  screen_class->get_root_window = gdk_screen_x11_get_root_window;
-  screen_class->get_default_colormap = gdk_screen_x11_get_default_colormap;
-  screen_class->set_default_colormap = gdk_screen_x11_set_default_colormap;
-  screen_class->get_window_at_pointer = gdk_screen_x11_get_window_at_pointer;
-  screen_class->get_n_monitors = gdk_screen_x11_get_n_monitors;
-  screen_class->get_monitor_geometry = gdk_screen_x11_get_monitor_geometry;
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   
-  G_OBJECT_CLASS (klass)->finalize = gdk_screen_x11_finalize;
-  parent_class = g_type_class_peek_parent (klass);
-}
+  object_class->dispose = gdk_screen_x11_dispose;
+  object_class->finalize = gdk_screen_x11_finalize;
 
-static GdkDisplay *
-gdk_screen_x11_get_display (GdkScreen *screen)
-{
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  parent_class = g_type_class_peek_parent (klass);
 
-  return screen_x11->display;
+  signals[WINDOW_MANAGER_CHANGED] =
+    g_signal_new ("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 gint
-gdk_screen_x11_get_width (GdkScreen *screen)
+/**
+ * gdk_screen_get_display:
+ * @screen: a #GdkScreen
+ *
+ * Gets the display to which the @screen belongs.
+ * 
+ * Returns: the display to which @screen belongs
+ **/
+GdkDisplay *
+gdk_screen_get_display (GdkScreen *screen)
 {
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
 
-  return WidthOfScreen (screen_x11->xscreen);
+  return GDK_SCREEN_X11 (screen)->display;
 }
-
-static gint
-gdk_screen_x11_get_height (GdkScreen *screen)
+/**
+ * gdk_screen_get_width:
+ * @screen: a #GdkScreen
+ *
+ * Gets the width of @screen in pixels
+ * 
+ * Returns: the width of @screen in pixels.
+ **/
+gint
+gdk_screen_get_width (GdkScreen *screen)
 {
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
 
-  return HeightOfScreen (screen_x11->xscreen);
+  return WidthOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
 }
 
-static gint
-gdk_screen_x11_get_width_mm (GdkScreen *screen)
+/**
+ * gdk_screen_get_height:
+ * @screen: a #GdkScreen
+ *
+ * Gets the height of @screen in pixels
+ * 
+ * Returns: the height of @screen in pixels.
+ **/
+gint
+gdk_screen_get_height (GdkScreen *screen)
 {
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
 
-  return WidthMMOfScreen (screen_x11->xscreen);
+  return HeightOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
 }
 
-static gint
-gdk_screen_x11_get_height_mm (GdkScreen *screen)
+/**
+ * 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 pixels.
+ **/
+gint
+gdk_screen_get_width_mm (GdkScreen *screen)
 {
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);  
 
-  return HeightMMOfScreen (screen_x11->xscreen);
+  return WidthMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
 }
 
-static gint
-gdk_screen_x11_get_default_depth (GdkScreen *screen)
+/**
+ * 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 pixels.
+ **/
+gint
+gdk_screen_get_height_mm (GdkScreen *screen)
 {
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
 
-  return DefaultDepthOfScreen (screen_x11->xscreen);
+  return HeightMMOfScreen (GDK_SCREEN_X11 (screen)->xscreen);
 }
 
-static gint
-gdk_screen_x11_get_screen_num (GdkScreen *screen)
+/**
+ * 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
+ **/
+gint
+gdk_screen_get_number (GdkScreen *screen)
 {
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);  
   
-  return screen_x11->screen_num;
+  return GDK_SCREEN_X11 (screen)->screen_num;
 }
 
-static GdkWindow *
-gdk_screen_x11_get_root_window (GdkScreen *screen)
+/**
+ * gdk_screen_get_root_window:
+ * @screen: a #GdkScreen
+ *
+ * Gets the root window of @screen. 
+ * 
+ * Returns: the root window
+ **/
+GdkWindow *
+gdk_screen_get_root_window (GdkScreen *screen)
 {
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
 
-  return screen_x11->root_window;
+  return GDK_SCREEN_X11 (screen)->root_window;
 }
 
-static GdkColormap *
-gdk_screen_x11_get_default_colormap (GdkScreen *screen)
+/**
+ * gdk_screen_get_default_colormap:
+ * @screen: a #GdkScreen
+ *
+ * Gets the default colormap for @screen.
+ * 
+ * Returns: the default #GdkColormap.
+ **/
+GdkColormap *
+gdk_screen_get_default_colormap (GdkScreen *screen)
 {
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
 
-  return screen_x11->default_colormap;
+  return GDK_SCREEN_X11 (screen)->default_colormap;
 }
 
-static void
-gdk_screen_x11_set_default_colormap (GdkScreen *screen,
-                                    GdkColormap * colormap)
+/**
+ * gdk_screen_set_default_colormap:
+ * @screen: a #GdkScreen
+ * @colormap: a #GdkColormap
+ *
+ * Sets the default @colormap for @screen.
+ **/
+void
+gdk_screen_set_default_colormap (GdkScreen   *screen,
+                                GdkColormap *colormap)
 {
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  GdkColormap *old_colormap;
   
-  screen_x11->default_colormap = colormap;
+  g_return_if_fail (GDK_IS_SCREEN (screen));
+  g_return_if_fail (GDK_IS_COLORMAP (colormap));
+
+  old_colormap = GDK_SCREEN_X11 (screen)->default_colormap;
+
+  GDK_SCREEN_X11 (screen)->default_colormap = g_object_ref (colormap);
+  
+  if (old_colormap)
+    g_object_unref (old_colormap);
 }
 
-static GdkWindow *
-gdk_screen_x11_get_window_at_pointer (GdkScreen *screen,
-                                     gint      *win_x,
-                                     gint      *win_y)
+static void
+gdk_screen_x11_dispose (GObject *object)
 {
-  GdkWindow *window;
-  Window root;
-  Window xwindow;
-  Window xwindow_last = 0;
-  Display *xdisplay;
-  int rootx = -1, rooty = -1;
-  int winx, winy;
-  unsigned int xmask;
-
-  xwindow = GDK_SCREEN_XROOTWIN (screen);
-  xdisplay = GDK_SCREEN_XDISPLAY (screen);
-
-  XGrabServer (xdisplay);
-  while (xwindow)
-    {
-      xwindow_last = xwindow;
-      XQueryPointer (xdisplay, xwindow,
-                    &root, &xwindow, &rootx, &rooty, &winx, &winy, &xmask);
-    }
-  XUngrabServer (xdisplay);
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
+
+  _gdk_x11_events_uninit_screen (GDK_SCREEN (object));
 
-  window = gdk_window_lookup_for_display (GDK_SCREEN_DISPLAY(screen),
-                                         xwindow_last);
-  if (win_x)
-    *win_x = window ? winx : -1;
-  if (win_y)
-    *win_y = window ? winy : -1;
+  g_object_unref (screen_x11->default_colormap);
+  screen_x11->default_colormap = NULL;
+  
+  screen_x11->root_window = NULL;
 
-  return window;
+  screen_x11->xdisplay = NULL;
+  screen_x11->xscreen = NULL;
+  screen_x11->screen_num = -1;
+  screen_x11->xroot_window = None;
+  screen_x11->wmspec_check_window = None;
+  
+  G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
 static void
@@ -233,35 +283,66 @@ gdk_screen_x11_finalize (GObject *object)
 {
   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (object);
   /* int i; */
-  g_object_unref (G_OBJECT (screen_x11->root_window));
+  g_object_unref (screen_x11->root_window);
   
   /* Visual Part (Need to implement finalize for Visuals for a clean
    * finalize) */
   /* for (i=0;i<screen_x11->nvisuals;i++)
-    g_object_unref (G_OBJECT (screen_x11->visuals[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);  
+
+  g_hash_table_destroy (screen_x11->colormap_hash);
   /* X settings */
   g_free (screen_x11->xsettings_client);
+  g_free (screen_x11->monitors);
+  
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-static gint 
-gdk_screen_x11_get_n_monitors (GdkScreen *screen)
+/**
+ * gdk_screen_get_n_monitors:
+ * @screen : a #GdkScreen.
+ *
+ * Returns the number of monitors being part of the virtual screen
+ *
+ * Returns: number of monitors part of the virtual screen or
+ *          0 if @screen is not in virtual screen mode.
+ **/
+gint 
+gdk_screen_get_n_monitors (GdkScreen *screen)
 {
-  g_return_val_if_fail (GDK_IS_SCREEN (screen), 1);
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), 0);
+  
   return GDK_SCREEN_X11 (screen)->num_monitors;
 }
 
-static void
-gdk_screen_x11_get_monitor_geometry (GdkScreen    *screen, 
-                                    gint          num_monitor,
-                                    GdkRectangle *dest)
+/**
+ * gdk_screen_get_monitor_geometry:
+ * @screen : a #GdkScreen.
+ * @monitor_num: the monitor number. 
+ * @dest : a #GdkRectangle to be filled with the monitor geometry
+ *
+ * Retrieves the #GdkRectangle representing the size and start
+ * coordinates of the individual monitor within the the entire virtual
+ * screen.
+ * 
+ * Note that the virtual screen coordinates can be retrieved via 
+ * gdk_screen_get_width() and gdk_screen_get_height().
+ *
+ **/
+void 
+gdk_screen_get_monitor_geometry (GdkScreen    *screen,
+                                gint          monitor_num,
+                                GdkRectangle *dest)
 {
-  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
-  g_return_if_fail (num_monitor < GDK_SCREEN_X11 (screen)->num_monitors);
+  g_return_if_fail (GDK_IS_SCREEN (screen));
+  g_return_if_fail (monitor_num < GDK_SCREEN_X11 (screen)->num_monitors);
+  g_return_if_fail (monitor_num >= 0);
 
-  *dest = screen_x11->monitors[num_monitor];
+  *dest = GDK_SCREEN_X11 (screen)->monitors[monitor_num];
 }
 
 /**
@@ -309,12 +390,14 @@ _gdk_x11_screen_new (GdkDisplay *display,
   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_xinerama_support (screen);
+  init_randr_support (screen);
   
   _gdk_visual_init (screen);
   _gdk_windowing_window_init (screen);
-  _gdk_x11_events_init_screen (screen);
 
   return screen;
 }
@@ -329,7 +412,7 @@ check_solaris_xinerama (GdkScreen *screen)
                        gdk_screen_get_number (screen)))
     {
       XRectangle monitors[MAXFRAMEBUFFERS];
-      char hints[16];
+      unsigned char hints[16];
       gint result;
       GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
 
@@ -372,6 +455,7 @@ check_xfree_xinerama (GdkScreen *screen)
 #ifdef HAVE_XFREE_XINERAMA
   if (XineramaIsActive (GDK_SCREEN_XDISPLAY (screen)))
     {
+      GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
       XineramaScreenInfo *monitors = XineramaQueryScreens (GDK_SCREEN_XDISPLAY (screen),
                                                           &screen_x11->num_monitors);
       if (screen_x11->num_monitors <= 0)
@@ -409,11 +493,14 @@ static void
 init_xinerama_support (GdkScreen * screen)
 {
   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
-  
 #ifdef HAVE_XINERAMA
   int opcode, firstevent, firsterror;
-  gint result;
+#endif
+
+  if (screen_x11->monitors)
+    g_free (screen_x11->monitors);
   
+#ifdef HAVE_XINERAMA  
   if (XQueryExtension (GDK_SCREEN_XDISPLAY (screen), "XINERAMA",
                       &opcode, &firstevent, &firsterror))
     {
@@ -433,3 +520,104 @@ init_xinerama_support (GdkScreen * screen)
   screen_x11->monitors[0].height = HeightOfScreen (screen_x11->xscreen);
 }
 
+static void
+init_randr_support (GdkScreen * screen)
+{
+  GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (screen);
+  
+  XSelectInput (GDK_SCREEN_XDISPLAY (screen),
+               screen_x11->xroot_window,
+               StructureNotifyMask);
+}
+
+void
+_gdk_x11_screen_size_changed (GdkScreen *screen,
+                             XEvent    *event)
+{
+#ifdef HAVE_RANDR
+  if (!XRRUpdateConfiguration (event))
+    return;
+#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
+  
+  init_xinerama_support (screen);
+  g_signal_emit_by_name (G_OBJECT (screen), "size_changed");
+}
+
+void
+_gdk_x11_screen_window_manager_changed (GdkScreen *screen)
+{
+  g_signal_emit (G_OBJECT (screen),
+                 signals[WINDOW_MANAGER_CHANGED], 0);
+}
+
+/**
+ * _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()
+ **/
+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));
+}