XRandR integration patch



Here is a first cut at a XRandR integration patch. The UI needs some 
polish, but it seems to work well. The control-center patch adds a capplet 
for setting the resolution and refresh rate. The gnome-session patch reads 
the settings and sets the resolution on login.

I also want to add a launcher for the capplet from the nautilus desktop 
context menu.

Comments?

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Alexander Larsson                                            Red Hat, Inc 
                   alexl redhat com    alla lysator liu se 
He's a sword-wielding coffee-fuelled dwarf haunted by an iconic dead American 
confidante She's a pregnant psychic archaeologist from a different time and 
place. They fight crime! 
Index: configure.in
===================================================================
RCS file: /cvs/gnome/gnome-session/configure.in,v
retrieving revision 1.432
diff -u -p -r1.432 configure.in
--- configure.in	26 Mar 2003 05:44:17 -0000	1.432
+++ configure.in	17 Apr 2003 17:21:43 -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	17 Apr 2003 17:21:43 -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,201 @@ 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++)
+    {
+      g_message ("screen %d:\n", 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 +459,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	17 Apr 2003 17:16:41 -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	17 Apr 2003 17:16:41 -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/main.c	2003-04-17 18:30:37.000000000 +0200
@@ -0,0 +1,787 @@
+#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"
+
+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;
+};
+
+
+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, int nr)
+{
+  GtkWidget *vbox, *hbox;
+  GtkWidget *label;
+  char *str;
+  char *str2;
+
+  vbox = gtk_vbox_new (FALSE, 6);
+  label = 0;
+
+  label = gtk_label_new ("");
+
+  str = g_strdup_printf (_("Screen %d"), nr + 1);
+  str2 = g_strdup_printf ("<b>%s</b>", str);
+  gtk_label_set_markup (GTK_LABEL (label), str2);
+  g_free (str);
+  g_free (str2);
+  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;
+
+  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, 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, 0,
+		    0, 0);
+  
+  if (no_header)
+    return table;
+  else
+    return wrap_in_label (table, nr);
+}
+
+
+static GtkWidget *
+create_dialog (struct DisplayInfo *info)
+{
+  GtkWidget *dialog;
+  GtkWidget *screen_widget;
+  int i;
+  
+  dialog = gtk_dialog_new_with_buttons (_("Change Resolution"),
+					NULL,
+					GTK_DIALOG_NO_SEPARATOR,
+					"gtk-apply",
+					GTK_RESPONSE_APPLY,
+					NULL);
+					
+  gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
+  gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 12);
+  
+  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);
+    }
+
+  return dialog;
+}
+
+static void
+default_check_toggled_callback (GtkToggleButton *default_check,
+				GtkWidget *computer_check)
+{
+  if (computer_check)
+    gtk_widget_set_sensitive (computer_check,
+			      gtk_toggle_button_get_active (default_check));
+}
+
+struct TimeoutData {
+  int time;
+  GtkLabel *label;
+  GtkDialog *dialog;
+  gboolean timed_out;
+};
+
+char *
+timeout_string (int time)
+{
+  return g_strdup_printf (_("If you don't respond in %d seconds the old 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,
+		   gboolean *save,
+		   gboolean *save_computer,
+		   gboolean *clear_computer)
+{
+  GtkWidget *dialog;
+  GtkWidget *hbox;
+  GtkWidget *vbox;
+  GtkWidget *label;
+  GtkWidget *label_sec;
+  GtkWidget *image;
+  GtkWidget *default_check;
+  GtkWidget *computer_check;
+  gboolean was_computer_specific;
+  int res;
+  struct TimeoutData timeout_data;
+  guint timeout;
+  char *str;
+#ifdef HOST_NAME_MAX
+  char hostname[HOST_NAME_MAX + 1];
+#else
+  char hostname[256];
+#endif
+
+  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_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+  gtk_window_set_title (GTK_WINDOW (dialog), _("Keep resolution?"));
+  
+  label = gtk_label_new (_("Testing the new settings. Do you want to keep using this resolution?"));
+  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 (15);
+  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);
+
+  default_check = gtk_check_button_new_with_mnemonic (_("Make _default resolution next time you log in"));
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (default_check),
+				TRUE);
+  
+  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 (vbox), default_check,
+                      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 old resolution"),
+			  GTK_RESPONSE_NO,
+			  _("Keep resolution"),
+			  GTK_RESPONSE_YES,
+			  NULL);
+
+  was_computer_specific = FALSE;
+  computer_check = NULL;
+  if (gethostname (hostname, sizeof(hostname)) == 0 &&
+      strcmp (hostname, "localhost") != 0 &&
+      strcmp (hostname, "l") != 0)
+    {
+      GtkWidget *hbox2;
+      GtkWidget *label2;
+      GConfClient *client;
+      char *key;
+      char *resolution;
+      
+      str = g_strdup_printf (_("Make default for this _computer (%s) only"), hostname);
+      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_print ("key: %s was: %s\n", key, resolution);
+      was_computer_specific = resolution != NULL;
+      g_free (resolution);
+      g_free (key);
+      g_object_unref (client);
+      
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (computer_check),
+				    was_computer_specific);
+      
+      hbox2 = gtk_hbox_new (FALSE, 6);
+      label2 = gtk_label_new ("  ");
+      gtk_box_pack_start (GTK_BOX (hbox2), label2,
+			  TRUE, TRUE, 0);
+      gtk_box_pack_start (GTK_BOX (hbox2), computer_check,
+			  TRUE, TRUE, 0);
+      
+      gtk_box_pack_start (GTK_BOX (vbox), hbox2,
+			  TRUE, TRUE, 0);
+    }
+
+  gtk_widget_show_all (hbox);
+
+  g_signal_connect (default_check, "toggled", G_CALLBACK (default_check_toggled_callback), computer_check);
+
+  timeout_data.time = 15;
+  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);
+  
+  *save = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (default_check));
+  *save_computer = FALSE;
+  *clear_computer = FALSE;
+  if (computer_check)
+    {
+      *save_computer = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (computer_check));
+      if (was_computer_specific && !*save_computer)
+	*clear_computer = TRUE;
+    }
+  
+  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);
+}
+
+int
+main (int argc, char *argv[])
+{
+  int major, minor;
+  int event_base, error_base;
+  GdkDisplay *display;
+  GtkWidget *dialog;
+  struct DisplayInfo *info;
+  Display *xdisplay;
+  gboolean save, save_computer, clear_computer;
+  int res;
+ 
+  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);
+
+  save = FALSE;
+  save_computer = FALSE;
+  while (TRUE)
+    {
+      res = gtk_dialog_run (GTK_DIALOG (dialog));
+
+      if (res == GTK_RESPONSE_DELETE_EVENT)
+	break;
+      
+      if (res == GTK_RESPONSE_APPLY)
+	{
+	  if (apply_config (info))
+	    {
+	      save = FALSE;
+	      save_computer = FALSE;
+	      if (!run_revert_dialog (info, dialog, &save, &save_computer, &clear_computer))
+		revert_config (info);
+	      else
+		break;
+	    }
+	  else
+	    break;
+	}
+    }
+  if (save)
+    save_to_gconf (info, save_computer, clear_computer);
+  
+  gtk_widget_destroy (dialog);
+
+  return 0;
+}
--- /dev/null	2003-01-30 11:24:37.000000000 +0100
+++ capplets/display/Makefile.am	2003-04-15 16:54:05.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) $(glade_DATA) $(pixmap_DATA)


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