2006-11-22  Federico Mena Quintero  <federico@novell.com>

	Fix the gnome-settings-daemon part of
	https://bugzilla.novell.com/show_bug.cgi?id=217790 and
	http://bugzilla.gnome.org/show_bug.cgi?id=378338:  try to figure
	out the DPI value from the X server or the user's GConf settings.

	Should also fix https://bugzilla.novell.com/show_bug.cgi?id=240246.

	* gnome-settings-daemon/gnome-settings-xsettings.c (gnome_xft_settings_get): Call
	get_dpi_from_gconf_or_server() to figure out a reasonable DPI
	value; don't unconditionally get it from GConf.
	(get_dpi_from_gconf_or_server): New function.  If the user has
	ever set the /desktop/gnome/font_rendering/dpi value in GConf, we
	use its value.  Otherwise, we ask the X server.  We constrain the
	X server's response to a range of reasonable DPI values, since
	some servers lie about the screen's phisical dimensions --- the
	user would get unusably huge or tiny fonts otherwise.

	* capplets/font/main.c (dpi_load): First, see if the DPI value is actually set
	in GConf.  If it is, it means that the user has changed it at
	least once.  In that case, just use the value.  Otherwise, find
	the value from the X server in a similar way to what we do in
	gnome-settings-daemon.

Index: gnome-settings-daemon/gnome-settings-xsettings.c
===================================================================
--- gnome-settings-daemon/gnome-settings-xsettings.c	(revision 7214)
+++ gnome-settings-daemon/gnome-settings-xsettings.c	(working copy)
@@ -33,6 +33,20 @@ struct _TranslationEntry
 };
 
 #ifdef HAVE_XFT2 
+/* X servers sometimes lie about the screen's physical dimensions, so we cannot
+ * compute an accurate DPI value.  When this happens, the user gets fonts that
+ * are too huge or too tiny.  So, we see what the server returns:  if it reports
+ * something outside of the range [DPI_LOW_REASONABLE_VALUE,
+ * DPI_HIGH_REASONABLE_VALUE], then we assume that it is lying and we use
+ * DPI_FALLBACK instead.
+ *
+ * See get_dpi_from_gconf_or_server() below, and also
+ * https://bugzilla.novell.com/show_bug.cgi?id=217790
+ */
+#define DPI_FALLBACK 96
+#define DPI_LOW_REASONABLE_VALUE 50
+#define DPI_HIGH_REASONABLE_VALUE 500
+
 static void gnome_settings_update_xft (GConfClient *client);
 static void xft_callback              (GConfEntry  *entry);
 #endif /* HAVE_XFT2 */
@@ -264,6 +278,74 @@ xft_callback (GConfEntry *entry)
     xsettings_manager_notify (managers [i]);
 }
 
+static double
+dpi_from_pixels_and_mm (int pixels, int mm)
+{
+	double dpi;
+
+	if (mm >= 1)
+		dpi = pixels / (mm / 25.4);
+	else
+		dpi = 0;
+
+	return dpi;
+}
+
+static double
+get_dpi_from_x_server (void)
+{
+  GdkScreen *screen;
+  double dpi;
+
+  screen = gdk_screen_get_default ();
+  if (screen)
+    {
+      double width_dpi, height_dpi;
+
+      width_dpi = dpi_from_pixels_and_mm (gdk_screen_get_width (screen), gdk_screen_get_width_mm (screen));
+      height_dpi = dpi_from_pixels_and_mm (gdk_screen_get_height (screen), gdk_screen_get_height_mm (screen));
+
+      if (width_dpi < DPI_LOW_REASONABLE_VALUE || width_dpi > DPI_HIGH_REASONABLE_VALUE
+	  || height_dpi < DPI_LOW_REASONABLE_VALUE || height_dpi > DPI_HIGH_REASONABLE_VALUE)
+	dpi = DPI_FALLBACK;
+      else
+	dpi = (width_dpi + height_dpi) / 2.0;
+    }
+  else
+    {
+      /* Huh!?  No screen? */
+
+      dpi = DPI_FALLBACK;
+    }
+
+  return dpi;
+}
+
+static double
+get_dpi_from_gconf_or_x_server (GConfClient *client)
+{
+  GConfValue *value;
+  double dpi;
+
+  value = gconf_client_get_without_default (client, FONT_DPI_KEY, NULL);
+
+  /* If the user has ever set the DPI preference in GConf, we use that.
+   * Otherwise, we see if the X server reports a reasonable DPI value:  some X
+   * servers report completely bogus values, and the user gets huge or tiny
+   * fonts which are unusable.
+   */
+
+  if (value)
+    {
+      dpi = gconf_value_get_float (value);
+      gconf_value_free (value);
+    }
+  else
+    dpi = get_dpi_from_x_server ();
+
+  return dpi;
+}
+
 typedef struct
 {
   gboolean antialias;
@@ -285,17 +367,14 @@ gnome_xft_settings_get (GConfClient     
   char *antialiasing = gconf_client_get_string (client, FONT_ANTIALIASING_KEY, NULL);
   char *hinting = gconf_client_get_string (client, FONT_HINTING_KEY, NULL);
   char *rgba_order = gconf_client_get_string (client, FONT_RGBA_ORDER_KEY, NULL);
-  double dpi = gconf_client_get_float (client, FONT_DPI_KEY, NULL);
+  double dpi = get_dpi_from_gconf_or_x_server (client);
 
   settings->antialias = TRUE;
   settings->hinting = TRUE;
   settings->hintstyle = "hintfull";
-  settings->dpi = 96 * 1024;
+  settings->dpi = dpi * 1024; /* Xft wants 1/1024ths of an inch */
   settings->rgba = "rgb";
 
-  if ((int)(1024 * dpi + 0.5) > 0)
-    settings->dpi = (int)(1024 * dpi + 0.5);
-
   if (rgba_order)
     {
       int i;
Index: capplets/font/main.c
===================================================================
--- capplets/font/main.c	(revision 7214)
+++ capplets/font/main.c	(working copy)
@@ -41,6 +41,19 @@ static void cb_show_details (GtkWidget *
 #define FONT_RGBA_ORDER_KEY   FONT_RENDER_DIR "/rgba_order"
 #define FONT_DPI_KEY          FONT_RENDER_DIR "/dpi"
 
+/* X servers sometimes lie about the screen's physical dimensions, so we cannot
+ * compute an accurate DPI value.  When this happens, the user gets fonts that
+ * are too huge or too tiny.  So, we see what the server returns:  if it reports
+ * something outside of the range [DPI_LOW_REASONABLE_VALUE,
+ * DPI_HIGH_REASONABLE_VALUE], then we assume that it is lying and we use
+ * DPI_FALLBACK instead.
+ *
+ * See get_dpi_from_gconf_or_server() below, and also
+ * https://bugzilla.novell.com/show_bug.cgi?id=217790
+ */
+#define DPI_FALLBACK 96
+#define DPI_LOW_REASONABLE_VALUE 50
+#define DPI_HIGH_REASONABLE_VALUE 500
 #endif /* HAVE_XFT2 */
 static gboolean in_change = FALSE;
 static gchar *old_font = NULL;
@@ -772,6 +785,49 @@ enum_group_create (const gchar         *
  	return group;
 }
 
+static double
+dpi_from_pixels_and_mm (int pixels, int mm)
+{
+	double dpi;
+
+	if (mm >= 1)
+		dpi = pixels / (mm / 25.4);
+	else
+		dpi = 0;
+
+	return dpi;
+}
+
+static double
+get_dpi_from_x_server (void)
+{
+  GdkScreen *screen;
+  double dpi;
+
+  screen = gdk_screen_get_default ();
+  if (screen)
+    {
+      double width_dpi, height_dpi;
+
+      width_dpi = dpi_from_pixels_and_mm (gdk_screen_get_width (screen), gdk_screen_get_width_mm (screen));
+      height_dpi = dpi_from_pixels_and_mm (gdk_screen_get_height (screen), gdk_screen_get_height_mm (screen));
+
+      if (width_dpi < DPI_LOW_REASONABLE_VALUE || width_dpi > DPI_HIGH_REASONABLE_VALUE
+	  || height_dpi < DPI_LOW_REASONABLE_VALUE || height_dpi > DPI_HIGH_REASONABLE_VALUE)
+	dpi = DPI_FALLBACK;
+      else
+	dpi = (width_dpi + height_dpi) / 2.0;
+    }
+  else
+    {
+      /* Huh!?  No screen? */
+
+      dpi = DPI_FALLBACK;
+    }
+
+  return dpi;
+}
+
 /*
  * The font rendering details dialog
  */
@@ -779,7 +835,16 @@ static void
 dpi_load (GConfClient   *client,
 	  GtkSpinButton *spinner)
 {
-	gdouble dpi = gconf_client_get_float (client, FONT_DPI_KEY, NULL);
+	GConfValue *value;
+	gdouble dpi;
+
+	value = gconf_client_get_without_default (client, FONT_DPI_KEY, NULL);
+
+	if (value) {
+		dpi = gconf_value_get_float (value);
+		gconf_value_free (value);
+	} else
+		dpi = get_dpi_from_x_server ();
 
 	if (dpi < 50.)
 		dpi = 50.;
