XRandR integration V2



Here is a new version of the XRandR integration patch.

The gnome-session part is basically the same as the old one with some spew 
removed and ChangeLog entries added.

The gnome-cc one has had the UI changed somewhat. The "save as default" 
checkbox has been removed (settings are always saved), and the "save as 
default for this machine only" checkbox has been moved to the main dialog. 
The main dialog has also gotten some polish (influenced by various 
comments here).

It's missing an icon. I used red-apple.png while testing.

Comments on this? Is it good enough for initial checkin?

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Alexander Larsson                                            Red Hat, Inc 
                   alexl redhat com    alla lysator liu se 
He's a globe-trotting dishevelled dog-catcher who knows the secret of the 
alien invasion. She's a cynical Buddhist magician's assistant with a 
flame-thrower. They fight crime! 
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gnome-session/ChangeLog,v
retrieving revision 1.478
diff -u -p -r1.478 ChangeLog
--- ChangeLog	22 Apr 2003 05:01:22 -0000	1.478
+++ ChangeLog	22 Apr 2003 15:22:05 -0000
@@ -1,3 +1,8 @@
+2003-04-22  Alexander Larsson  <alexl redhat com>
+
+	* configure.in:
+	Look for Xrandr.
+
 2003-04-21  Taneem Ahmed <taneem eyetap org>
 
 	* configure.in: Added "bn" to ALL_LINGUAS.
Index: configure.in
===================================================================
RCS file: /cvs/gnome/gnome-session/configure.in,v
retrieving revision 1.433
diff -u -p -r1.433 configure.in
--- configure.in	22 Apr 2003 05:01:22 -0000	1.433
+++ configure.in	22 Apr 2003 15:22:05 -0000
@@ -120,6 +120,13 @@ if test $pango_omitted_x_deps = yes ; th
   fi
 fi
 
+AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration,
+  [AC_CHECK_HEADER(X11/extensions/Xrandr.h,
+     X_LIBS="-lXrandr -lXrender $X_LIBS"
+     AC_DEFINE(HAVE_RANDR, 1, Have the Xrandr extension library),
+	  :, [#include <X11/Xlib.h>])], : ,
+       -lXrandr -lXrender $X_LIBS)
+
 AC_SUBST(X_LIBS)
 
 dnl -----------------------------------------------------------
Index: gnome-session/main.c
===================================================================
RCS file: /cvs/gnome/gnome-session/gnome-session/main.c,v
retrieving revision 1.52
diff -u -p -r1.52 main.c
--- gnome-session/main.c	6 Jan 2003 06:33:40 -0000	1.52
+++ gnome-session/main.c	22 Apr 2003 15:22:05 -0000
@@ -35,6 +35,11 @@
 
 #include <libgnomeui/gnome-window-icon.h>
 
+#ifdef HAVE_RANDR
+#include <gdk/gdkx.h>
+#include <X11/extensions/Xrandr.h>
+#endif
+
 #include "manager.h"
 #include "ice.h"
 #include "save.h"
@@ -233,6 +238,199 @@ gnome_login_check (void)
     }
 }
 
+#ifdef HAVE_RANDR
+static gboolean
+get_resolution (GConfClient *client, int screen, char *keys[], int *width, int *height)
+{
+  int i;
+  char *key;
+  char *val;
+  int w, h;
+
+  val = NULL;
+  for (i = 0; keys[i] != NULL; i++)
+    {
+      key = g_strdup_printf ("%s/%d/resolution", keys[i], screen);
+      val = gconf_client_get_string (client, key, NULL);
+      g_free (key);
+
+      if (val != NULL)
+	break;
+    }
+  
+  if (val == NULL)
+    return FALSE;
+
+  if (sscanf (val, "%dx%d", &w, &h) != 2)
+    return FALSE;
+
+  *width = w;
+  *height = h;
+  
+  return TRUE;
+}
+
+static int
+get_rate (GConfClient *client, int screen, char *keys[])
+{
+  int i;
+  char *key;
+  int val;
+  GError *error;
+
+  for (i = 0; keys[i] != NULL; i++)
+    {
+      key = g_strdup_printf ("%s/%d/rate", keys[i], screen);
+      error = NULL;
+      val = gconf_client_get_int (client, key, &error);
+      g_free (key);
+
+      if (error == NULL)
+	return val;
+
+      g_error_free (error);
+    }
+  
+  return 0;
+}
+
+static int
+find_closest_size (XRRScreenSize *sizes, int nsizes, int width, int height)
+{
+  int closest;
+  int closest_width, closest_height;
+  int i;
+
+  closest = 0;
+  closest_width = sizes[0].width;
+  closest_height = sizes[0].height;
+  for (i = 1; i < nsizes; i++)
+    {
+      if (ABS (sizes[i].width - width) < ABS (closest_width - width) ||
+	  (sizes[i].width == closest_width &&
+	   ABS (sizes[i].height - height) < ABS (closest_height - height)))
+	{
+	  closest = i;
+	  closest_width = sizes[i].width;
+	  closest_height = sizes[i].height;
+	}
+    }
+  
+  return closest;
+}
+
+#endif
+
+static void
+set_display_properties (void)
+{
+#ifdef HAVE_RANDR
+  GdkDisplay *display;
+  Display *xdisplay;
+  int major, minor;
+  int event_base, error_base;
+  int n_screens;
+  GdkScreen *screen;
+  GdkWindow *root_window;
+  int width, height, rate;
+  GConfClient *client;
+#ifdef HOST_NAME_MAX
+  char hostname[HOST_NAME_MAX + 1];
+#else
+  char hostname[256];
+#endif
+  char *specific_path;
+  char *keys[3];
+  int i;
+
+  display = gdk_display_get_default ();
+  xdisplay = gdk_x11_display_get_xdisplay (display);
+
+  /* Check if XRandR is supported on the display */
+  if (!XRRQueryExtension (xdisplay, &event_base, &error_base) ||
+      XRRQueryVersion (xdisplay, &major, &minor) == 0)
+    return;
+  
+  if (major != 1 || minor < 1)
+    {
+      g_message ("Display has unsupported version of XRandR (%d.%d), not setting resolution.", major, minor);
+      return;
+    }
+
+  client = gconf_client_get_default ();
+  
+  keys[0] = "/desktop/gnome/screen/default";
+  specific_path = NULL;
+  if (gethostname (hostname, sizeof (hostname)) != 0)
+    specific_path = g_strconcat ("/desktop/gnome/screen/", hostname,  NULL);
+  keys[1] = specific_path;
+  keys[2] = NULL;
+  
+  n_screens = gdk_display_get_n_screens (display);
+  for (i = 0; i < n_screens; i++)
+    {
+      screen = gdk_display_get_screen (display, i);
+      root_window = gdk_screen_get_root_window (screen);
+
+      if (get_resolution (client, i, keys, &width, &height))
+	{
+	  XRRScreenSize *sizes;
+	  int nsizes, j;
+	  int closest;
+	  short *rates;
+	  int nrates;
+	  int status;
+	  int current_size;
+	  short current_rate;
+	  XRRScreenConfiguration *config;
+	  Rotation current_rotation;
+
+	  config = XRRGetScreenInfo (xdisplay, gdk_x11_drawable_get_xid (GDK_DRAWABLE (root_window)));
+
+	  rate = get_rate (client, i, keys);
+	  
+	  sizes = XRRConfigSizes (config, &nsizes);
+	  closest = find_closest_size (sizes, nsizes, width, height);
+	  
+	  rates = XRRConfigRates (config, closest, &nrates);
+	  for (j = 0; j < nrates; j++)
+	    {
+	      if (rates[j] == rate)
+		break;
+	    }
+	  /* Rate not supported, let X pick */
+	  if (j == nrates)
+	    rate = 0;
+
+	  current_size = XRRConfigCurrentConfiguration (config, &current_rotation);
+	  current_rate = XRRConfigCurrentRate (config);
+
+	  if (closest != current_size ||
+	      rate != current_rate)
+	    {
+	      status = XRRSetScreenConfigAndRate (xdisplay, 
+						  config,
+						  gdk_x11_drawable_get_xid (GDK_DRAWABLE (root_window)),
+						  closest,
+						  current_rotation,
+						  rate,
+						  GDK_CURRENT_TIME);
+	    }
+	}
+    }
+	  
+  g_object_unref (client);
+  
+  g_free (specific_path);
+
+  /* We need to make sure we process the screen resize event. */
+  gdk_display_sync (display);
+  while (gtk_events_pending ())
+    gtk_main_iteration();
+  
+#endif
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -259,6 +457,10 @@ main (int argc, char *argv[])
    * gnome yet
    */
   gtk_init (&argc, &argv);
+
+  /* We need to do this as early as possible */
+  set_display_properties ();
+  
   gnome_login_check ();
 
   err = NULL;
Index: configure.in
===================================================================
RCS file: /cvs/gnome/gnome-control-center/configure.in,v
retrieving revision 1.378
diff -u -p -r1.378 configure.in
--- configure.in	21 Mar 2003 10:39:27 -0000	1.378
+++ configure.in	22 Apr 2003 15:22:56 -0000
@@ -47,6 +47,7 @@ AC_SUBST(XF86MISC_LIBS)
 AC_CHECK_HEADERS(X11/extensions/XKB.h)
 CPPFLAGS=$savecppflags
 
+	
 dnl ==============================================
 dnl Check that we meet the  dependencies
 dnl ==============================================
@@ -72,7 +73,26 @@ if $PKG_CONFIG --exists xft ; then
 fi
 
 PKG_CHECK_MODULES(FONT_CAPPLET, $COMMON_MODULES $xft_modules)
+				
+dnl
+dnl Check for XRandR, needed for display capplet
+dnl		
+	
+have_randr=no
+AC_CHECK_LIB(Xrandr, XRRUpdateConfiguration,
+  [AC_CHECK_HEADER(X11/extensions/Xrandr.h,
+     have_randr=yes
+     RANDR_LIBS="-lXrandr -lXrender"
+     AC_DEFINE(HAVE_RANDR, 1, Have the Xrandr extension library),
+	  :, [#include <X11/Xlib.h>])], : ,
+       -lXrandr -lXrender $x_libs)
+AM_CONDITIONAL(HAVE_RANDR, [test $have_randr = yes])
+	
+PKG_CHECK_MODULES(DISPLAY_CAPPLET, $COMMON_MODULES)
+
+DISPLAY_CAPPLET_LIBS="$DISPLAY_CAPPLET_LIBS $RANDR_LIBS"
 
+				   
 CAPPLET_LIBS="$CAPPLET_LIBS $x_libs"
 GNOMECC_LIBS="$GNOMECC_LIBS $x_libs"
 GNOME_SETTINGS_DAEMON_LIBS="$GNOME_SETTINGS_DAEMON_LIBS $x_libs"
@@ -168,6 +188,9 @@ AC_SUBST(SOUND_CAPPLET_LIBS)
 AC_SUBST(FONT_CAPPLET_CFLAGS)
 AC_SUBST(FONT_CAPPLET_LIBS)
 
+AC_SUBST(DISPLAY_CAPPLET_CFLAGS)
+AC_SUBST(DISPLAY_CAPPLET_LIBS)
+
 AC_SUBST(GNOMECC_CFLAGS)
 AC_SUBST(GNOMECC_LIBS)
 
@@ -249,6 +272,7 @@ capplets/common/Makefile
 capplets/background/Makefile
 capplets/default-applications/Makefile
 capplets/desktop-links/Makefile
+capplets/display/Makefile
 capplets/file-types/Makefile
 capplets/file-types/libuuid/Makefile
 capplets/font/Makefile
Index: capplets/Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-control-center/capplets/Makefile.am,v
retrieving revision 1.64
diff -u -p -r1.64 Makefile.am
--- capplets/Makefile.am	8 Aug 2002 07:17:12 -0000	1.64
+++ capplets/Makefile.am	22 Apr 2003 15:22:56 -0000
@@ -3,12 +3,18 @@ always_built_SUBDIRS =					\
 	default-applications desktop-links font		\
 	background keyboard mouse sound			\
 	file-types theme-switcher ui-properties		\
-	keybindings network windows
+	keybindings network windows 
 
-SUBDIRS =  $(always_built_SUBDIRS)
+if HAVE_RANDR
+randr_SUBDIRS = display
+else
+randr_SUBDIRS = 
+endif
+
+SUBDIRS =  $(always_built_SUBDIRS) $(randr_SUBDIRS)
 
 DIST_SUBDIRS = \
-	$(always_built_SUBDIRS)
+	$(always_built_SUBDIRS) display
 
 
 
--- /dev/null	2003-01-30 11:24:37.000000000 +0100
+++ capplets/display/Makefile.am	2003-04-22 16:55:47.000000000 +0200
@@ -0,0 +1,26 @@
+bin_PROGRAMS = gnome-display-properties
+
+gnome_display_properties_LDADD = $(DISPLAY_CAPPLET_LIBS) $(top_builddir)/capplets/common/libcommon.la
+gnome_display_properties_SOURCES = \
+	main.c		
+gnome_display_properties_LDFLAGS = -export-dynamic
+
+ INTLTOOL_DESKTOP_RULE@
+
+iconsdir   = $(GNOMECC_ICONS_DIR)
+icons_DATA = display-capplet.png
+
+desktop_iconsdir = $(datadir)/pixmaps
+desktop_icons_DATA = display-capplet.png
+
+desktopdir = $(GNOMECC_DESKTOP_DIR)
+Desktop_in_files = display-properties.desktop.in
+desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
+
+INCLUDES   = $(DISPLAY_CAPPLET_CFLAGS)     \
+             $(GNOMECC_CAPPLETS_CFLAGS) \
+	     -DGLADEDIR=\""$(gladedir)"\" \
+	     -DPIXMAPDIR=\""$(pixmapdir)"\"
+
+CLEANFILES = $(GNOMECC_CAPPLETS_CLEANFILES)
+EXTRA_DIST = $(Desktop_in_files) $(icons_DATA)
--- /dev/null	2003-01-30 11:24:37.000000000 +0100
+++ capplets/display/display-properties.desktop.in	2003-04-22 16:40:20.000000000 +0200
@@ -0,0 +1,13 @@
+[Desktop Entry]
+Encoding=UTF-8
+_Name=Screen Resolution
+_Comment=Change screen resolution
+Exec=gnome-display-properties
+Icon=display-capplet.png
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=GNOME;Settings;Appearance;
+X-GNOME-Bugzilla-Bugzilla=GNOME
+X-GNOME-Bugzilla-Product=control-center
+X-GNOME-Bugzilla-Component=display properties
--- /dev/null	2003-01-30 11:24:37.000000000 +0100
+++ capplets/display/main.c	2003-04-22 17:11:36.000000000 +0200
@@ -0,0 +1,778 @@
+#include <config.h>
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+#include <glade/glade.h>
+#include <gdk/gdkx.h>
+
+#include <X11/extensions/Xrandr.h>
+
+#include "capplet-util.h"
+
+#define REVERT_COUNT 20
+
+struct ScreenInfo {
+  int current_width;
+  int current_height;
+  SizeID current_size;
+  short current_rate;
+  Rotation current_rotation;
+  
+  XRRScreenConfiguration *config;
+  XRRScreenSize *sizes;
+  int n_sizes;
+  
+  GtkWidget *resolution_widget;
+  GtkWidget *rate_widget;
+};
+
+struct DisplayInfo {
+  int n_screens;
+  struct ScreenInfo *screens;
+
+  GtkWidget *per_computer_check;
+  gboolean was_per_computer;
+};
+
+
+struct DisplayInfo *
+read_display_info (GdkDisplay *display)
+{
+  struct DisplayInfo *info;
+  struct ScreenInfo *screen_info;
+  GdkScreen *screen;
+  GdkWindow *root_window;
+  int i;
+
+  info = g_new (struct DisplayInfo, 1);
+  info->n_screens = gdk_display_get_n_screens (display);
+  info->screens = g_new (struct ScreenInfo, info->n_screens);
+
+  for (i = 0; i < info->n_screens; i++)
+    {
+      screen = gdk_display_get_screen (display, i);
+      
+      screen_info = &info->screens[i];
+      screen_info->current_width = gdk_screen_get_width (screen);
+      screen_info->current_height = gdk_screen_get_height (screen);
+
+      root_window = gdk_screen_get_root_window (screen);
+      screen_info->config = XRRGetScreenInfo (gdk_x11_display_get_xdisplay (display),
+					      gdk_x11_drawable_get_xid (GDK_DRAWABLE (root_window)));
+      
+      screen_info->current_rate = XRRConfigCurrentRate (screen_info->config);
+      screen_info->current_size = XRRConfigCurrentConfiguration (screen_info->config, &screen_info->current_rotation);
+      screen_info->sizes = XRRConfigSizes (screen_info->config, &screen_info->n_sizes);
+    }
+
+  return info;
+}
+
+static int
+get_current_resolution (struct ScreenInfo *screen_info)
+{
+  GtkWidget *menu;
+  GList *children;
+  GList *child;
+  int i;
+
+  i = gtk_option_menu_get_history (GTK_OPTION_MENU (screen_info->resolution_widget));
+  menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (screen_info->resolution_widget));
+  children = gtk_container_get_children (GTK_CONTAINER (menu));
+  child = g_list_nth (children, i);
+
+  if (child != NULL)
+    return GPOINTER_TO_INT (g_object_get_data (child->data, "screen_nr"));
+  else
+    return 0;
+}
+
+static int
+get_current_rate (struct ScreenInfo *screen_info)
+{
+  GtkWidget *menu;
+  GList *children;
+  GList *child;
+  int i;
+
+  i = gtk_option_menu_get_history (GTK_OPTION_MENU (screen_info->rate_widget));
+  menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (screen_info->rate_widget));
+  children = gtk_container_get_children (GTK_CONTAINER (menu));
+  child = g_list_nth (children, i);
+
+  if (child != NULL)
+    return GPOINTER_TO_INT (g_object_get_data (child->data, "rate"));
+  else
+    return 0;
+}
+
+static gboolean
+apply_config (struct DisplayInfo *info)
+{
+  int i;
+  GdkDisplay *display;
+  Display *xdisplay;
+  GdkScreen *screen;
+  gboolean changed;
+
+  display = gdk_display_get_default ();
+  xdisplay = gdk_x11_display_get_xdisplay (display);
+
+  changed = FALSE;
+  for (i = 0; i < info->n_screens; i++)
+    {
+      struct ScreenInfo *screen_info = &info->screens[i];
+      Status status;
+      GdkWindow *root_window;
+      int new_res, new_rate;
+
+      screen = gdk_display_get_screen (display, i);
+      root_window = gdk_screen_get_root_window (screen);
+
+      new_res = get_current_resolution (screen_info);
+      new_rate = get_current_rate (screen_info);
+      
+      if (new_res != screen_info->current_size ||
+	  new_rate != screen_info->current_rate)
+	{
+	  changed = TRUE; 
+	  status = XRRSetScreenConfigAndRate (xdisplay, 
+					      screen_info->config,
+					      gdk_x11_drawable_get_xid (GDK_DRAWABLE (root_window)),
+					      new_res,
+					      screen_info->current_rotation,
+					      new_rate,
+					      GDK_CURRENT_TIME);
+	}
+    }
+  
+  return changed;
+}
+
+static int
+revert_config (struct DisplayInfo *info)
+{
+  int i;
+  GdkDisplay *display;
+  Display *xdisplay;
+  GdkScreen *screen;
+
+  display = gdk_display_get_default ();
+  xdisplay = gdk_x11_display_get_xdisplay (display);
+  
+  for (i = 0; i < info->n_screens; i++)
+    {
+      struct ScreenInfo *screen_info = &info->screens[i];
+      Status status;
+      GdkWindow *root_window;
+
+      screen = gdk_display_get_screen (display, i);
+      root_window = gdk_screen_get_root_window (screen);
+
+      status = XRRSetScreenConfigAndRate (xdisplay, 
+					  screen_info->config,
+					  gdk_x11_drawable_get_xid (GDK_DRAWABLE (root_window)),
+					  screen_info->current_size,
+					  screen_info->current_rotation,
+					  screen_info->current_rate,
+					  GDK_CURRENT_TIME);
+    }
+  return 0;
+}
+
+static GtkWidget *
+wrap_in_label (GtkWidget *child, char *text)
+{
+  GtkWidget *vbox, *hbox;
+  GtkWidget *label;
+  char *str;
+
+  vbox = gtk_vbox_new (FALSE, 6);
+  label = 0;
+
+  label = gtk_label_new ("");
+
+  str = g_strdup_printf ("<b>%s</b>", text);
+  gtk_label_set_markup (GTK_LABEL (label), str);
+  g_free (str);
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_box_pack_start (GTK_BOX (vbox),
+		      label,
+		      FALSE, FALSE, 0);
+
+  hbox = gtk_hbox_new (FALSE, 0);
+
+  label = gtk_label_new ("    ");
+  gtk_widget_show (label);
+  gtk_box_pack_start (GTK_BOX (hbox),
+		      label,
+		      FALSE, FALSE, 0);
+
+  gtk_box_pack_start (GTK_BOX (hbox),
+		      child,
+		      TRUE, TRUE, 0);
+
+  gtk_widget_show (hbox);
+  
+  gtk_box_pack_start (GTK_BOX (vbox),
+		      hbox,
+		      FALSE, FALSE, 0);
+
+  gtk_widget_show (vbox);
+
+  return vbox;
+}
+
+static gboolean
+show_resolution (int width, int height)
+{
+  if (width >= 800 && height >= 600)
+    return TRUE;
+
+  if (width == 640 && height == 480)
+    return TRUE;
+
+  return FALSE;
+}
+
+static void
+generate_rate_menu (struct ScreenInfo *screen_info)
+{
+  GtkWidget *menu;
+  GtkWidget *menuitem;
+  short *rates;
+  int nrates, i;
+  int size_nr;
+  char *str;
+  int closest_rate_nr;
+  
+  gtk_option_menu_remove_menu (GTK_OPTION_MENU (screen_info->rate_widget));
+
+  menu = gtk_menu_new ();
+
+  size_nr = get_current_resolution (screen_info);
+  
+  closest_rate_nr = -1;
+  rates = XRRConfigRates (screen_info->config, size_nr, &nrates);
+  for (i = 0; i < nrates; i++)
+    {
+      str = g_strdup_printf (_("%d Hz"), rates[i]);
+
+      if ((closest_rate_nr < 0) ||
+	  (ABS (rates[i] - screen_info->current_rate) <
+	   ABS (rates[closest_rate_nr] - screen_info->current_rate)))
+	closest_rate_nr = i;
+      
+      menuitem = gtk_menu_item_new_with_label (str);
+
+      g_object_set_data (G_OBJECT (menuitem), "rate", GINT_TO_POINTER ((int)rates[i]));
+	  
+      g_free (str);
+      gtk_widget_show (menuitem);
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+    }
+
+  gtk_option_menu_set_menu (GTK_OPTION_MENU (screen_info->rate_widget), menu);
+  gtk_option_menu_set_history (GTK_OPTION_MENU (screen_info->rate_widget),
+			       closest_rate_nr);
+}
+
+static void
+resolution_changed_callback (GtkWidget *optionmenu,
+			     struct ScreenInfo *screen_info)
+{
+  generate_rate_menu (screen_info);
+}
+
+static GtkWidget *
+create_resolution_menu (struct ScreenInfo *screen_info)
+{
+  GtkWidget *optionmenu;
+  GtkWidget *menu;
+  GtkWidget *menuitem;
+  int i, item, current_item;
+  XRRScreenSize *sizes;
+  char *str;
+  SizeID current_size;
+  Rotation rot;
+
+  screen_info->resolution_widget = optionmenu = gtk_option_menu_new ();
+
+  menu = gtk_menu_new ();
+
+  current_size = XRRConfigCurrentConfiguration (screen_info->config, &rot);
+  
+  current_item = 0;
+  item = 0;
+  sizes = screen_info->sizes;
+  for (i = 0; i < screen_info->n_sizes; i++)
+    {
+      if (i == current_size || show_resolution (sizes[i].width, sizes[i].height))
+	{
+	  str = g_strdup_printf ("%dx%d", sizes[i].width, sizes[i].height);
+	  
+	  if (i == current_size)
+	    current_item = item;
+	  
+	  menuitem = gtk_menu_item_new_with_label (str);
+
+	  g_object_set_data (G_OBJECT (menuitem), "screen_nr", GINT_TO_POINTER (i));
+	  
+	  g_free (str);
+	  gtk_widget_show (menuitem);
+	  gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+	  item++;
+	}
+    }
+  
+  gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), menu);
+  gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu),
+			       current_item);
+
+  g_signal_connect (optionmenu, "changed",
+		    G_CALLBACK (resolution_changed_callback), screen_info);
+  
+  gtk_widget_show (optionmenu);
+  return optionmenu;
+}
+
+static GtkWidget *
+create_rate_menu (struct ScreenInfo *screen_info)
+{
+  GtkWidget *optionmenu;
+
+  screen_info->rate_widget = optionmenu = gtk_option_menu_new ();
+
+  generate_rate_menu (screen_info);
+  
+  gtk_widget_show (optionmenu);
+  return optionmenu;
+}
+
+static GtkWidget *
+create_screen_widgets (struct ScreenInfo *screen_info, int nr, gboolean no_header)
+{
+  GtkWidget *table;
+  GtkWidget *label;
+  GtkWidget *option_menu;
+  char *str;
+
+  table = gtk_table_new (2, 2, FALSE);
+
+  gtk_table_set_row_spacings ( GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings ( GTK_TABLE (table), 12);
+  
+  label = gtk_label_new (_("Resolution:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table),
+		    label,
+		    0, 1,
+		    0, 1,
+		    GTK_FILL, 0,
+		    0, 0);
+
+  option_menu = create_resolution_menu (screen_info);
+  gtk_table_attach (GTK_TABLE (table),
+		    option_menu,
+		    1, 2,
+		    0, 1,
+		    GTK_FILL | GTK_EXPAND, 0,
+		    0, 0);
+  
+  label = gtk_label_new (_("Refresh rate:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_widget_show (label);
+  gtk_table_attach (GTK_TABLE (table),
+		    label,
+		    0, 1,
+		    1, 2,
+		    GTK_FILL, 0,
+		    0, 0);
+  gtk_widget_show (table);
+  
+  option_menu = create_rate_menu (screen_info);
+  gtk_table_attach (GTK_TABLE (table),
+		    option_menu,
+		    1, 2,
+		    1, 2,
+		    GTK_FILL | GTK_EXPAND, 0,
+		    0, 0);
+  
+  if (nr == 0)
+    str = g_strdup (_("Default Settings"));
+  else
+    str = g_strdup_printf (_("Screen %d Settings\n"), nr);
+  return wrap_in_label (table, str);
+  
+  g_free (str);
+}
+
+
+static GtkWidget *
+create_dialog (struct DisplayInfo *info)
+{
+  GtkWidget *dialog;
+  GtkWidget *screen_widget;
+  GtkWidget *per_computer_check;
+  int i;
+  GtkWidget *wrapped;
+  GConfClient *client;
+  char *key;
+  char *resolution;
+  char *str;
+#ifdef HOST_NAME_MAX
+  char hostname[HOST_NAME_MAX + 1];
+#else
+  char hostname[256];
+#endif
+  
+  dialog = gtk_dialog_new_with_buttons (_("Screen Resolution Preferences"),
+					NULL,
+					GTK_DIALOG_NO_SEPARATOR,
+					"gtk-apply",
+					GTK_RESPONSE_APPLY,
+					"gtk-help",
+					GTK_RESPONSE_HELP,
+					NULL);
+					
+  gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
+  gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 12);
+  capplet_set_icon (dialog, "display-capplet.png");
+  
+  for (i = 0; i < info->n_screens; i++)
+    {
+      screen_widget = create_screen_widgets (&info->screens[i], i, info->n_screens == 1);
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+			  screen_widget, FALSE, FALSE, 0);
+      gtk_widget_show (screen_widget);
+    }
+
+  per_computer_check = NULL;
+  info->was_per_computer = FALSE;
+  if (gethostname (hostname, sizeof (hostname)) == 0 &&
+      strcmp (hostname, "localhost") != 0 &&
+      strcmp (hostname, "localhost.localdomain") != 0)
+    {
+      
+      str = g_strdup_printf (_("Make default for this _computer (%s) only"), hostname);
+      per_computer_check = gtk_check_button_new_with_mnemonic (str);
+
+      /* If we previously set the resolution specifically for this hostname, default
+	 to it on */
+      client = gconf_client_get_default ();
+      key = g_strconcat ("/desktop/gnome/screen/", hostname,  "/0/resolution",NULL);
+      resolution = gconf_client_get_string (client, key, NULL);
+      g_free (resolution);
+      g_free (key);
+      g_object_unref (client);
+      
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (per_computer_check),
+				    resolution != NULL);
+      info->was_per_computer = resolution != NULL;
+      
+      gtk_widget_show (per_computer_check);
+      
+      wrapped = wrap_in_label (per_computer_check, _("Options"));
+      gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+			  wrapped, FALSE, FALSE, 0);
+      gtk_widget_show (wrapped);
+    }
+
+  info->per_computer_check = per_computer_check;
+  
+  return dialog;
+}
+
+struct TimeoutData {
+  int time;
+  GtkLabel *label;
+  GtkDialog *dialog;
+  gboolean timed_out;
+};
+
+char *
+timeout_string (int time)
+{
+  return g_strdup_printf (_("Testing the new settings. If you don't respond in %d seconds the previous settings will be restored."), time);
+}
+
+gboolean
+save_timeout_callback (gpointer _data)
+{
+  struct TimeoutData *data = _data;
+  char *str;
+  
+  data->time--;
+
+  if (data->time == 0)
+    {
+      gtk_dialog_response (data->dialog, GTK_RESPONSE_NO);
+      data->timed_out = TRUE;
+      return FALSE;
+    }
+
+  str = timeout_string (data->time);
+  gtk_label_set_text (data->label, str);
+  g_free (str);
+  
+  return TRUE;
+}
+
+static int
+run_revert_dialog (struct DisplayInfo *info,
+		   GtkWidget *parent)
+{
+  GtkWidget *dialog;
+  GtkWidget *hbox;
+  GtkWidget *vbox;
+  GtkWidget *label;
+  GtkWidget *label_sec;
+  GtkWidget *image;
+  int res;
+  struct TimeoutData timeout_data;
+  guint timeout;
+  char *str;
+
+  dialog = gtk_dialog_new ();
+  gtk_window_set_transient_for (GTK_WINDOW (dialog),
+				GTK_WINDOW (parent));
+  gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+  gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+  gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
+  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+  gtk_window_set_title (GTK_WINDOW (dialog), "");
+  
+  label = gtk_label_new (NULL);
+  str = g_strdup_printf ("<b>%s</b>", _("Do you want to keep this resolution?"));
+  gtk_label_set_markup (GTK_LABEL (label), str);
+  g_free (str);
+  image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
+  gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+  
+  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+  gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+
+  str = timeout_string (REVERT_COUNT);
+  label_sec = gtk_label_new (str);
+  g_free (str);
+  gtk_label_set_line_wrap (GTK_LABEL (label_sec), TRUE);
+  gtk_label_set_selectable (GTK_LABEL (label_sec), TRUE);
+  gtk_misc_set_alignment (GTK_MISC (label_sec), 0.0, 0.5);
+
+  hbox = gtk_hbox_new (FALSE, 6);
+  vbox = gtk_vbox_new (FALSE, 6);
+
+  gtk_box_pack_start (GTK_BOX (vbox), label,
+                      TRUE, TRUE, 0);
+			     
+  gtk_box_pack_start (GTK_BOX (vbox), label_sec,
+                      TRUE, TRUE, 0);
+  
+  gtk_box_pack_start (GTK_BOX (hbox), image,
+                      FALSE, FALSE, 0);
+  
+  gtk_box_pack_start (GTK_BOX (hbox), vbox,
+                      TRUE, TRUE, 0);
+
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+                      hbox,
+                      FALSE, FALSE, 0);
+
+  gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+			  _("Use _previous resolution"),
+			  GTK_RESPONSE_NO,
+			  _("_Keep resolution"),
+			  GTK_RESPONSE_YES,
+			  NULL);
+  
+  gtk_widget_show_all (hbox);
+
+  timeout_data.time = REVERT_COUNT;
+  timeout_data.label = GTK_LABEL (label_sec);
+  timeout_data.dialog = GTK_DIALOG (dialog);
+  timeout_data.timed_out = FALSE;
+  
+  timeout = g_timeout_add (1000,
+			   save_timeout_callback,
+			   &timeout_data);
+  
+  res = gtk_dialog_run (GTK_DIALOG (dialog));
+
+  if (!timeout_data.timed_out)
+    g_source_remove (timeout);
+
+  gtk_widget_destroy (dialog);
+  
+  return res == GTK_RESPONSE_YES;
+}
+
+static void
+save_to_gconf (struct DisplayInfo *info, gboolean save_computer, gboolean clear_computer)
+{
+  GConfClient    *client;
+  gboolean res;
+#ifdef HOST_NAME_MAX
+  char hostname[HOST_NAME_MAX + 1];
+#else
+  char hostname[256];
+#endif
+  char *path, *key, *str;
+  int i;
+
+  gethostname (hostname, sizeof(hostname));
+  
+  client = gconf_client_get_default ();
+
+  if (clear_computer)
+    {
+      for (i = 0; i < info->n_screens; i++)
+	{
+	  key = g_strdup_printf ("/desktop/gnome/screen/%s/%d/resolution",
+				 hostname, i);
+	  gconf_client_unset (client, key, NULL);
+	  g_free (key);
+	  key = g_strdup_printf ("/desktop/gnome/screen/%s/%d/rate",
+				 hostname, i);
+	  gconf_client_unset (client, key, NULL);
+	  g_free (key);
+	}
+    }
+  
+  if (save_computer)
+    {
+      path = g_strconcat ("/desktop/gnome/screen/",
+			  hostname,
+			  "/",
+			  NULL);
+    }
+  else
+    path = g_strdup ("/desktop/gnome/screen/default/");
+	       
+  for (i = 0; i < info->n_screens; i++)
+    {
+      struct ScreenInfo *screen_info = &info->screens[i];
+      int new_res, new_rate;
+
+      new_res = get_current_resolution (screen_info);
+      new_rate = get_current_rate (screen_info);
+
+      key = g_strdup_printf ("%s%d/resolution", path, i);
+      str = g_strdup_printf ("%dx%d",
+			     screen_info->sizes[new_res].width,
+			     screen_info->sizes[new_res].height);
+      
+      res = gconf_client_set_string  (client, key, str, NULL);
+      g_free (str);
+      g_free (key);
+      
+      key = g_strdup_printf ("%s%d/rate", path, i);
+      res = gconf_client_set_int  (client, key, new_rate, NULL);
+      g_free (key);
+    }
+
+  g_free (path);
+  g_object_unref (client);
+}
+
+static void
+cb_dialog_response (GtkDialog *dialog, gint response_id, struct DisplayInfo *info)
+{
+  gboolean save_computer, clear_computer;
+  
+  switch (response_id)
+    {
+    case GTK_RESPONSE_DELETE_EVENT:
+      gtk_main_quit ();
+      break;
+    case GTK_RESPONSE_HELP:
+      /* FIXME: This needs to be changed to the right section
+       * when the docs have been written. */
+      capplet_help (GTK_WINDOW (dialog),
+		    "wgoscustdesk.xml",
+		    "goscustdesk-38");
+      break;
+    case GTK_RESPONSE_APPLY:
+      save_computer = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (info->per_computer_check));
+      clear_computer = !save_computer && info->was_per_computer;
+	  
+      if (apply_config (info))
+	{
+	  if (!run_revert_dialog (info, GTK_WIDGET (dialog)))
+	    {
+	      revert_config (info);
+	      return;
+	    }
+	}
+      
+      save_to_gconf (info, save_computer, clear_computer);
+      gtk_main_quit ();
+      break;
+    }
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int major, minor;
+  int event_base, error_base;
+  GdkDisplay *display;
+  GtkWidget *dialog;
+  struct DisplayInfo *info;
+  Display *xdisplay;
+ 
+  bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+  textdomain (GETTEXT_PACKAGE);
+
+  gnome_program_init ("gnome-display-properties", VERSION,
+		      LIBGNOMEUI_MODULE, argc, argv,
+		      GNOME_PARAM_APP_DATADIR, GNOMECC_DATA_DIR,
+		      NULL);
+
+  display = gdk_display_get_default ();
+  xdisplay = gdk_x11_display_get_xdisplay (display);
+  
+  if (!XRRQueryExtension (xdisplay, &event_base, &error_base) ||
+      XRRQueryVersion (xdisplay, &major, &minor) == 0)
+    {
+      dialog = gtk_message_dialog_new (NULL,
+                                       GTK_DIALOG_MODAL,
+                                       GTK_MESSAGE_ERROR,
+                                       GTK_BUTTONS_OK,
+				       _("The Xserver doesn't support the XRandR extension, runtime resolution changes aren't possible."));
+      gtk_dialog_run (GTK_DIALOG (dialog));
+      gtk_widget_destroy (dialog);
+      exit (0);
+    }
+  
+  if (major != 1 || minor < 1)
+    {
+      dialog = gtk_message_dialog_new (NULL,
+                                       GTK_DIALOG_MODAL,
+                                       GTK_MESSAGE_ERROR,
+                                       GTK_BUTTONS_OK,
+				       _("The version of the XRandR extension is incompatible with this program, runtime resolution changes aren't possible."));
+      gtk_dialog_run (GTK_DIALOG (dialog));
+      gtk_widget_destroy (dialog);
+      exit (0);
+    }
+
+  info = read_display_info (display);
+  
+  dialog = create_dialog (info);
+
+  g_signal_connect (G_OBJECT (dialog),
+		    "response",
+		    G_CALLBACK (cb_dialog_response), info);
+
+  gtk_widget_show (dialog);
+
+  gtk_main ();
+
+  return 0;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]