rpms/gnome-desktop/devel add-randr-12.patch,1.7,1.8

Soren Sandmann Pedersen (ssp) fedora-extras-commits at redhat.com
Tue Feb 12 16:52:29 UTC 2008


Author: ssp

Update of /cvs/pkgs/rpms/gnome-desktop/devel
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv1953/devel

Modified Files:
	add-randr-12.patch 
Log Message:
Add monitor-db.[ch]

add-randr-12.patch:

Index: add-randr-12.patch
===================================================================
RCS file: /cvs/pkgs/rpms/gnome-desktop/devel/add-randr-12.patch,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- add-randr-12.patch	12 Feb 2008 16:46:34 -0000	1.7
+++ add-randr-12.patch	12 Feb 2008 16:52:04 -0000	1.8
@@ -1,6 +1,6 @@
-diff -up gnome-desktop-2.21.90/configure.in.add-randr-12 gnome-desktop-2.21.90/configure.in
---- gnome-desktop-2.21.90/configure.in.add-randr-12	2008-01-27 18:48:13.000000000 -0500
-+++ gnome-desktop-2.21.90/configure.in	2008-02-04 08:50:16.000000000 -0500
+diff -up gnome-desktop-2.21.91/configure.in.add-randr-12 gnome-desktop-2.21.91/configure.in
+--- gnome-desktop-2.21.91/configure.in.add-randr-12	2008-02-11 13:38:20.000000000 -0500
++++ gnome-desktop-2.21.91/configure.in	2008-02-12 11:37:35.000000000 -0500
 @@ -51,10 +51,10 @@ AC_SUBST(GNOME_MICRO)
  AC_SUBST(GNOME_DISTRIBUTOR)
  AC_SUBST(GNOME_DATE)
@@ -16,9 +16,9 @@
  
  # As a special favour for vuntz, support --disable-deprecations
  
-diff -up gnome-desktop-2.21.90/libgnome-desktop/libgnomeui/Makefile.am.add-randr-12 gnome-desktop-2.21.90/libgnome-desktop/libgnomeui/Makefile.am
---- gnome-desktop-2.21.90/libgnome-desktop/libgnomeui/Makefile.am.add-randr-12	2008-01-27 18:44:20.000000000 -0500
-+++ gnome-desktop-2.21.90/libgnome-desktop/libgnomeui/Makefile.am	2008-02-12 11:34:54.000000000 -0500
+diff -up gnome-desktop-2.21.91/libgnome-desktop/libgnomeui/Makefile.am.add-randr-12 gnome-desktop-2.21.91/libgnome-desktop/libgnomeui/Makefile.am
+--- gnome-desktop-2.21.91/libgnome-desktop/libgnomeui/Makefile.am.add-randr-12	2008-02-11 13:35:11.000000000 -0500
++++ gnome-desktop-2.21.91/libgnome-desktop/libgnomeui/Makefile.am	2008-02-12 11:37:35.000000000 -0500
 @@ -2,4 +2,7 @@ libgnomeui_desktopdir = $(includedir)/gn
  libgnomeui_desktop_HEADERS = \
  	gnome-ditem-edit.h \
@@ -28,14 +28,60 @@
 +	randrwrap.h	   \
 +	monitor-db.h
 +
-diff -up gnome-desktop-2.21.90/libgnome-desktop/libgnomeui/monitor-db.h.add-randr-12 gnome-desktop-2.21.90/libgnome-desktop/libgnomeui/monitor-db.h
---- gnome-desktop-2.21.90/libgnome-desktop/libgnomeui/monitor-db.h.add-randr-12	2008-02-12 11:36:11.000000000 -0500
-+++ gnome-desktop-2.21.90/libgnome-desktop/libgnomeui/monitor-db.h	2008-02-12 11:37:03.000000000 -0500
-@@ -0,0 +1 @@
-+ 
-diff -up /dev/null gnome-desktop-2.21.90/libgnome-desktop/libgnomeui/randrwrap.h
+diff -up /dev/null gnome-desktop-2.21.91/libgnome-desktop/libgnomeui/monitor-db.h
+--- /dev/null	2008-02-12 08:56:47.229685651 -0500
++++ gnome-desktop-2.21.91/libgnome-desktop/libgnomeui/monitor-db.h	2008-02-12 11:44:30.000000000 -0500
+@@ -0,0 +1,47 @@
++#ifndef MONITOR_DB_H
++#define MONITOR_DB_H
++
++#define I_KNOW_THIS_IS_UNSTABLE_AND_ONLY_IN_FEDORA
++#include <libgnomeui/randrwrap.h>
++#include <glib.h>
++
++typedef struct Output Output;
++typedef struct Configuration Configuration;
++
++struct Output
++{
++    char *	name;
++
++    gboolean	on;
++    int		width;
++    int		height;
++    int		rate;
++    int		x;
++    int		y;
++    RWRotation	rotation;
++
++    gboolean	connected;
++    char	vendor[4];
++    guint	product;
++    guint	serial;
++    double	aspect;
++    int		pref_width;
++    int		pref_height;
++};
++
++struct Configuration
++{
++    Output **outputs;
++};
++
++void            configuration_free         (Configuration  *configuration);
++Configuration  *configuration_new_current  (RWScreen       *screen);
++gboolean        configuration_match        (Configuration  *config1,
++					    Configuration  *config2);
++gboolean        configuration_save         (Configuration  *configuration,
++					    GError        **err);
++gboolean	configuration_apply_stored (RWScreen       *screen);
++gboolean	configuration_applicable   (Configuration  *configuration,
++					    RWScreen       *screen);
++
++#endif
+diff -up /dev/null gnome-desktop-2.21.91/libgnome-desktop/libgnomeui/randrwrap.h
 --- /dev/null	2008-02-12 08:56:47.229685651 -0500
-+++ gnome-desktop-2.21.90/libgnome-desktop/libgnomeui/randrwrap.h	2008-02-12 09:12:16.000000000 -0500
++++ gnome-desktop-2.21.91/libgnome-desktop/libgnomeui/randrwrap.h	2008-02-12 11:44:30.000000000 -0500
 @@ -0,0 +1,100 @@
 +#ifndef I_KNOW_THIS_IS_UNSTABLE_AND_ONLY_IN_FEDORA
 +#error This is not yet for general consumption.
@@ -137,14 +183,1213 @@
 +					    RWRotation	     rotation);
 +
 +#endif
-diff -up gnome-desktop-2.21.90/libgnome-desktop/monitor-db.c.add-randr-12 gnome-desktop-2.21.90/libgnome-desktop/monitor-db.c
---- gnome-desktop-2.21.90/libgnome-desktop/monitor-db.c.add-randr-12	2008-02-12 11:34:19.000000000 -0500
-+++ gnome-desktop-2.21.90/libgnome-desktop/monitor-db.c	2008-02-12 11:36:53.000000000 -0500
-@@ -0,0 +1 @@
+diff -up /dev/null gnome-desktop-2.21.91/libgnome-desktop/monitor-db.c
+--- /dev/null	2008-02-12 08:56:47.229685651 -0500
++++ gnome-desktop-2.21.91/libgnome-desktop/monitor-db.c	2008-02-12 11:44:30.000000000 -0500
+@@ -0,0 +1,1200 @@
++#include <stdlib.h>
++#include <string.h>
++#include <glib.h>
++#include "libgnomeui/monitor-db.h"
++#include "edid.h"
++
++/* Code to load and save monitor configurations
++ *
++ * A monitor configuration is a list of monitors and associated
++ * outputs, along with information about mode and rotation.
++ *
++ * A monitor is identified by a string like EDID-SUN-0x0567
++ * which is decoded as "We got this information from EDID" - the manufacturer
++ * was "SUN" and the product code was 0x0567.
++ *
++ * Do we put this in gconf?
++ *
++ * The database itself is an XML file with entries like this:
++ *
++ *     <configuration>
++ *          <output name="VGA0">
++ *               <monitor>EDID-SUN-0x0567-12341234</monitor>
++ *               <mode>
++ *                      <state>on</state>
++ *                      <width>1024</width>
++ *                      <height>768</height>
++ *                      <rotation>0</rotation>
++ *               </mode>
++ *          </output>
++ *          <output name="LVDS">
++ *               <monitor>EDID-CMO-0x1210</monitor>
++ *               <mode>
++ *                    <...>
++ *               </mode>
++ *          <output>
++ *     </configuration>    
++ *         
++ */
++
++/* A helper wrapper around the GMarkup parser stuff */
++static gboolean parse_file_gmarkup (const gchar *file,
++				    const GMarkupParser *parser,
++				    gpointer data,
++				    GError **err);
++
++typedef struct CrtcAssignment CrtcAssignment;
++
++static void            crtc_assignment_apply (CrtcAssignment *assign);
++static CrtcAssignment *crtc_assignment_new   (RWScreen       *screen,
++					      Output        **outputs);
++static void            crtc_assignment_free  (CrtcAssignment *assign);
++
++
++typedef struct Parser Parser;
++
++/* Parser for monitor configurations */
++struct Parser
++{
++    Output *output;
++    Configuration *configuration;
++    GPtrArray *outputs;
++    GPtrArray *configurations;
++    GQueue *stack;
++};
++
++static int
++parse_int (const char *text)
++{
++    return strtol (text, NULL, 0);
++}
++
++static gboolean
++stack_is (Parser *parser,
++	  const char *s1,
++	  ...)
++{
++    GList *stack = NULL;
++    const char *s;
++    GList *l1, *l2;
++    va_list args;
++    
++    stack = g_list_prepend (stack, (gpointer)s1);
++    
++    va_start (args, s1);
++    
++    s = va_arg (args, const char *);
++    while (s)
++    {
++	stack = g_list_prepend (stack, (gpointer)s);
++	s = va_arg (args, const char *);
++    }
++	
++    l1 = stack;
++    l2 = parser->stack->head;
++    
++    while (l1 && l2)
++    {
++	if (strcmp (l1->data, l2->data) != 0)
++	{
++	    g_list_free (stack);
++	    return FALSE;
++	}
++	
++	l1 = l1->next;
++	l2 = l2->next;
++    }
++    
++    g_list_free (stack);
++    
++    return (!l1 && !l2);
++}
++
++static void
++handle_start_element (GMarkupParseContext *context,
++		      const gchar         *name,
++		      const gchar        **attr_names,
++		      const gchar        **attr_values,
++		      gpointer             user_data,
++		      GError             **err)
++{
++    Parser *parser = user_data;
++
++    if (strcmp (name, "output") == 0)
++    {
++	int i;
++	g_assert (parser->output == NULL);
++
++	parser->output = g_new0 (Output, 1);
++	parser->output->rotation = 0;
++	
++	for (i = 0; attr_names[i] != NULL; ++i)
++	{
++	    if (strcmp (attr_names[i], "name") == 0)
++	    {
++		parser->output->name = g_strdup (attr_values[i]);
++		break;
++	    }
++	}
++
++	if (!parser->output->name)
++	{
++	    /* This really shouldn't happen, but it's better to make
++	     * something up than to crash later.
++	     */
++	    g_warning ("Malformed monitor configuration file");
++	    
++	    parser->output->name = g_strdup ("default");
++	}	
++	parser->output->connected = FALSE;
++	parser->output->on = FALSE;
++    }
++    else if (strcmp (name, "configuration") == 0)
++    {
++	g_assert (parser->configuration == NULL);
++	
++	parser->configuration = g_new0 (Configuration, 1);
++	parser->configuration->outputs = g_new0 (Output *, 1);
++    }
++
++    g_queue_push_tail (parser->stack, g_strdup (name));
++}
++
++static void
++handle_end_element (GMarkupParseContext *context,
++		    const gchar         *name,
++		    gpointer             user_data,
++		    GError             **err)
++{
++    Parser *parser = user_data;
++    
++    if (strcmp (name, "output") == 0)
++    {
++	if (parser->output->rotation == 0)
++	    parser->output->rotation = RW_ROTATION_0;
++	
++	g_ptr_array_add (parser->outputs, parser->output);
++
++	parser->output = NULL;
++    }
++    else if (strcmp (name, "configuration") == 0)
++    {
++	g_ptr_array_add (parser->outputs, NULL);
++	parser->configuration->outputs =
++	    (Output **)g_ptr_array_free (parser->outputs, FALSE);
++	parser->outputs = g_ptr_array_new ();
++	g_ptr_array_add (parser->configurations, parser->configuration);
++	parser->configuration = NULL;
++    }
++    
++    g_free (g_queue_pop_tail (parser->stack));
++}
++
++static void
++handle_text (GMarkupParseContext *context,
++	     const gchar         *text,
++	     gsize                text_len,
++	     gpointer             user_data,
++	     GError             **err)
++{
++    Parser *parser = user_data;
++    
++    if (stack_is (parser, "vendor", "output", "configuration", NULL))
++    {
++	parser->output->connected = TRUE;
++	
++	strncpy (parser->output->vendor, text, 3);
++	parser->output->vendor[3] = 0;
++    }
++    else if (stack_is (parser, "product", "output", "configuration", NULL))
++    {
++	parser->output->connected = TRUE;
++
++	parser->output->product = parse_int (text);
++    }
++    else if (stack_is (parser, "serial", "output", "configuration", NULL))
++    {
++	parser->output->connected = TRUE;
++
++	parser->output->serial = parse_int (text);
++    }
++    else if (stack_is (parser, "width", "output", "configuration", NULL))
++    {
++	parser->output->on = TRUE;
++
++	parser->output->width = parse_int (text);
++    }
++    else if (stack_is (parser, "x", "output", "configuration", NULL))
++    {
++	parser->output->on = TRUE;
++
++	parser->output->x = parse_int (text);
++    }
++    else if (stack_is (parser, "y", "output", "configuration", NULL))
++    {
++	parser->output->on = TRUE;
++
++	parser->output->y = parse_int (text);
++    }
++    else if (stack_is (parser, "height", "output", "configuration", NULL))
++    {
++	parser->output->on = TRUE;
++
++	parser->output->height = parse_int (text);
++    }
++    else if (stack_is (parser, "rate", "output", "configuration", NULL))
++    {
++	parser->output->on = TRUE;
++
++	parser->output->rate = parse_int (text);
++    }
++    else if (stack_is (parser, "rotation", "output", "configuration", NULL))
++    {
++	if (strcmp (text, "normal") == 0)
++	{
++	    parser->output->rotation |= RW_ROTATION_0;
++	}
++	else if (strcmp (text, "left") == 0)
++	{
++	    parser->output->rotation |= RW_ROTATION_90;
++	}
++	else if (strcmp (text, "upside_down") == 0)
++	{
++	    parser->output->rotation |= RW_ROTATION_180;
++	}
++	else if (strcmp (text, "right") == 0)
++	{
++	    parser->output->rotation |= RW_ROTATION_270;
++	}
++    }
++    else if (stack_is (parser, "reflect_x", "output", "configuration", NULL))
++    {
++	if (strcmp (text, "yes") == 0)
++	{
++	    parser->output->rotation |= RW_REFLECT_X;
++	}
++    }
++    else if (stack_is (parser, "reflect_y", "output", "configuration", NULL))
++    {
++	if (strcmp (text, "yes") == 0)
++	{
++	    parser->output->rotation |= RW_REFLECT_Y;
++	}
++    }
++    else
++    {
++	/* Ignore other properties so we can expand the format in the future */
++    }
++}
++
++static void
++output_free (Output *output)
++{
++    g_free (output);
++}
++
++void
++configuration_free (Configuration *config)
++{
++    int i;
++
++    for (i = 0; config->outputs[i] != NULL; ++i)
++	output_free (config->outputs[i]);
++}
++
++static void
++parser_free (Parser *parser)
++{
++    int i;
++    GList *list;
++
++    if (parser->output)
++	output_free (parser->output);
++
++    if (parser->configuration)
++	configuration_free (parser->configuration);
++
++    for (i = 0; i < parser->outputs->len; ++i)
++    {
++	Output *output = parser->outputs->pdata[i];
++
++	output_free (output);
++    }
++
++    g_ptr_array_free (parser->outputs, TRUE);
++
++    for (i = 0; i < parser->configurations->len; ++i)
++    {
++	Configuration *config = parser->configurations->pdata[i];
++
++	configuration_free (config);
++    }
++
++    g_ptr_array_free (parser->configurations, TRUE);
++
++    for (list = parser->stack->head; list; list = list->next)
++	g_free (list->data);
++    g_queue_free (parser->stack);
++    
++    g_free (parser);
++}
++
++static Configuration **
++configurations_read (const gchar *filename, GError **error)
++{
++    Parser *parser = g_new0 (Parser, 1);
++    Configuration **result;
++    GMarkupParser callbacks = {
++	handle_start_element,
++	handle_end_element,
++	handle_text,
++	NULL, /* passthrough */
++	NULL, /* error */
++    };
++
++    parser->configurations = g_ptr_array_new ();
++    parser->outputs = g_ptr_array_new ();
++    parser->stack = g_queue_new ();
++    
++    if (!parse_file_gmarkup (filename, &callbacks, parser, error))
++    {
++	result = NULL;
++
++	g_print ("parse error\n");
++	
++	g_assert (parser->outputs);
++	goto out;
++    }
++
++    g_assert (parser->outputs);
++    
++    g_ptr_array_add (parser->configurations, NULL);
++    result = (Configuration **)g_ptr_array_free (parser->configurations, FALSE);
++    parser->configurations = g_ptr_array_new ();
++    
++    g_assert (parser->outputs);
++out:
++    parser_free (parser);
++
++    return result;
++}
++
++Configuration *
++configuration_new_current (RWScreen *screen)
++{
++    Configuration *config = g_new0 (Configuration, 1);
++    GPtrArray *a = g_ptr_array_new ();
++    int i;
++    RWOutput **rw_outputs = rw_screen_list_outputs (screen);
++	
++    for (i = 0; rw_outputs[i] != NULL; ++i)
++    {
++	RWOutput *rw_output = rw_outputs[i];
++	Output *output = g_new0 (Output, 1);
++	RWMode *mode = NULL;
++	const guint8 *edid_data = rw_output_get_edid_data (rw_output);
++	RWCrtc *crtc;
++
++	output->name = g_strdup (rw_output_get_name (rw_output));
++	output->connected = rw_output_is_connected (rw_output);
++
++	if (!output->connected)
++	{
++	    output->x = -1;
++	    output->y = -1;
++	    output->width = -1;
++	    output->height = -1;
++	    output->rate = -1;
++	    output->rotation = RW_ROTATION_0;
++	}
++	else
++	{
++	    if (edid_data)
++	    {
++		MonitorInfo *info = decode_edid (edid_data);
++		
++		memcpy (output->vendor, info->manufacturer_code,
++			sizeof (output->vendor));
++		
++		output->product = info->product_code;
++		output->serial = info->serial_number;
++		output->aspect = info->aspect_ratio;
++		
++		g_free (info);
++	    }
++	    else
++	    {
++		strcpy (output->vendor, "???");
++		output->product = 0;
++		output->serial = 0;
++	    }
++	    
++	    crtc = rw_output_get_crtc (rw_output);
++	    
++	    if (crtc)
++	    {
++		output->on = TRUE;
++		
++		mode = rw_crtc_get_current_mode (crtc);
++
++		rw_crtc_get_position (crtc, &output->x, &output->y);
++		output->width = rw_mode_get_width (mode);
++		output->height = rw_mode_get_height (mode);
++		output->rate = rw_mode_get_freq (mode);
++		output->rotation = rw_crtc_get_current_rotation (crtc);
++	    }
++	    else
++	    {
++		output->on = FALSE;
++	    }
++
++	    /* Get preferred size for the monitor */
++	    mode = rw_output_get_preferred_mode (rw_output);
++	    
++	    if (!mode)
++	    {
++		RWMode **modes = rw_output_list_modes (rw_output);
++		
++		/* FIXME: we should pick the "best" mode here, where best is
++		 * sorted wrt
++		 *
++		 * - closest aspect ratio
++		 * - mode area
++		 * - refresh rate
++		 * - We may want to extend randrwrap so that get_preferred
++		 *   returns that - although that could also depend on
++		 *   the crtc.
++		 */
++		if (modes[0])
++		    mode = modes[0];
++	    }
++	    
++	    if (mode)
++	    {
++		output->pref_width = rw_mode_get_width (mode);
++		output->pref_height = rw_mode_get_height (mode);
++	    }
++	    else
++	    {
++		/* Pick some random numbers. This should basically never happen */
++		output->pref_width = 1024;
++		output->pref_height = 768;
++	    }
++	}
 + 
-diff -up /dev/null gnome-desktop-2.21.90/libgnome-desktop/randrwrap.c
++	g_ptr_array_add (a, output);
++    }
++
++    g_ptr_array_add (a, NULL);
++    
++    config->outputs = (Output **)g_ptr_array_free (a, FALSE);
++
++    g_assert (configuration_match (config, config));
++    
++    return config;
++}
++
++static void
++configurations_free (Configuration **configurations)
++{
++    int i;
++
++    for (i = 0; configurations[i] != NULL; ++i)
++	configuration_free (configurations[i]);
++
++    g_free (configurations);
++}
++
++static gboolean
++parse_file_gmarkup (const gchar *filename,
++		    const GMarkupParser *parser,
++		    gpointer data,
++		    GError **err)
++{
++    GMarkupParseContext *context = NULL;
++    gchar *contents = NULL;
++    gboolean result = TRUE;
++    guint len;
++
++    if (!g_file_get_contents (filename, &contents, &len, err))
++    {
++	result = FALSE;
++	goto out;
++    }
++    
++    context = g_markup_parse_context_new (parser, 0, data, NULL);
++
++    if (!g_markup_parse_context_parse (context, contents, len, err))
++    {
++	result = FALSE;
++	goto out;
++    }
++
++    if (!g_markup_parse_context_end_parse (context, err))
++    {
++	result = FALSE;
++	goto out;
++    }
++
++out:
++    if (contents)
++	g_free (contents);
++
++    if (context)
++	g_markup_parse_context_free (context);
++
++    return result;
++}
++
++static gboolean
++output_match (Output *output1, Output *output2)
++{
++    if (strcmp (output1->name, output2->name) != 0)
++	return FALSE;
++
++    if (strcmp (output1->vendor, output2->vendor) != 0)
++	return FALSE;
++
++    if (output1->product != output2->product)
++	return FALSE;
++
++    if (output1->serial != output2->serial)
++	return FALSE;
++
++    if (output1->connected != output2->connected)
++	return FALSE;
++    
++    return TRUE;
++}
++
++static Output *
++find_output (Configuration *config, const char *name)
++{
++    int i;
++
++    for (i = 0; config->outputs[i] != NULL; ++i)
++    {
++	Output *output = config->outputs[i];
++	
++	if (strcmp (name, output->name) == 0)
++	    return output;
++    }
++
++    return NULL;
++}
++
++gboolean
++configuration_match (Configuration *c1, Configuration *c2)
++{
++    int i;
++
++    for (i = 0; c1->outputs[i] != NULL; ++i)
++    {
++	Output *output1 = c1->outputs[i];
++	Output *output2;
++
++	output2 = find_output (c2, output1->name);
++	if (!output2 || !output_match (output1, output2))
++	    return FALSE;
++    }
++    
++    return TRUE;
++}
++
++gboolean
++configuration_applicable   (Configuration  *configuration,
++			    RWScreen       *screen)
++{
++    CrtcAssignment *assign = crtc_assignment_new (screen, configuration->outputs);
++
++    if (assign)
++    {
++	crtc_assignment_free (assign);
++
++	return TRUE;
++    }
++
++    return FALSE;
++}
++
++static Configuration *
++configuration_find (Configuration **haystack,
++		    Configuration  *needle)
++{
++    int i;
++
++    for (i = 0; haystack[i] != NULL; ++i)
++    {
++	if (configuration_match (haystack[i], needle))
++	    return haystack[i];
++    }
++
++    return NULL;
++}
++
++/* Database management */
++static gboolean
++do_free (gpointer data)
++{
++    g_free (data);
++    return FALSE;
++}
++
++static gchar *
++idle_free (gchar *s)
++{
++    g_idle_add (do_free, s);
++
++    return s;
++}
++
++static const gchar *
++get_filename (void)
++{
++    return idle_free (
++	g_build_filename (
++	    g_get_home_dir(), ".gnome2", "monitors.xml", NULL));
++}
++
++static const char *
++get_rotation_name (RWRotation r)
++{
++    if (r & RW_ROTATION_0)
++	return "normal";
++    if (r & RW_ROTATION_90)
++	return "left";
++    if (r & RW_ROTATION_180)
++	return "upside_down";
++    if (r & RW_ROTATION_270)
++	return "right";
++
++    return "normal";
++}
++
++static const char *
++yes_no (int x)
++{
++    return x? "yes" : "no";
++}
++
++static const char *
++get_reflect_x (RWRotation r)
++{
++    return yes_no (r & RW_REFLECT_X);
++}
++
++static const char *
++get_reflect_y (RWRotation r)
++{
++    return yes_no (r & RW_REFLECT_Y);
++}
++
++static void
++emit_configuration (Configuration *config,
++		    GString *string)
++{
++    int j;
++	
++    g_string_append_printf (string, "<configuration>\n");
++    
++    for (j = 0; config->outputs[j] != NULL; ++j)
++    {
++	Output *output = config->outputs[j];
++	
++	g_string_append_printf (
++	    string, "    <output name=\"%s\">\n", output->name);
++	
++	if (output->connected && *output->vendor != '\0')
++	{
++	    g_string_append_printf (
++		string, "        <vendor>%s</vendor>\n", output->vendor);
++	    g_string_append_printf (
++		string, "        <product>0x%04x</product>\n", output->product);
++	    g_string_append_printf (
++		string, "        <serial>0x%08x</serial>\n", output->serial);
++	}
++	
++	/* An unconnected output which is on does not make sense */
++	if (output->connected && output->on)
++	{
++	    g_string_append_printf (
++		string, "        <width>%d</width>\n", output->width);
++	    g_string_append_printf (
++		string, "        <height>%d</height>\n", output->height);
++	    g_string_append_printf (
++		string, "        <rate>%d</rate>\n", output->rate);
++	    g_string_append_printf (
++		string, "        <x>%d</x>\n", output->x);
++	    g_string_append_printf (
++		string, "        <y>%d</y>\n", output->y);
++	    g_string_append_printf (
++		string, "        <rotation>%s</rotation>\n", get_rotation_name (output->rotation));
++	    g_string_append_printf (
++		string, "        <reflect_x>%s</reflect_x>\n", get_reflect_x (output->rotation));
++	    g_string_append_printf (
++		string, "        <reflect_y>%s</reflect_y>\n", get_reflect_y (output->rotation));
++	}
++	
++	g_string_append_printf (string, "    </output>\n");
++    }
++    
++    g_string_append_printf (string, "</configuration>\n");
++}
++
++gboolean
++configuration_save (Configuration *configuration, GError **err)
++{
++    Configuration **configurations;
++    GString *output = g_string_new("");
++    int i;
++
++    configurations = configurations_read (get_filename(), NULL);
++    
++    if (configurations)
++    {
++	for (i = 0; configurations[i] != NULL; ++i)
++	{
++	    if (!configuration_match (configurations[i], configuration))
++		emit_configuration (configurations[i], output);
++	}
++
++	configurations_free (configurations);
++    }
++
++    emit_configuration (configuration, output);
++
++    return g_file_set_contents (get_filename(), output->str, -1, err);
++}
++
++static gboolean
++apply_configuration (Configuration *conf, RWScreen *screen)
++{
++    CrtcAssignment *assignment;
++    GTimer *timer;
++
++    timer = g_timer_new ();
++    
++    assignment = crtc_assignment_new (screen, conf->outputs);
++
++    g_print ("Computed CRTC assignment in %.2f ms\n",
++	     1000 * g_timer_elapsed (timer, NULL));
++    
++    if (assignment)
++    {
++	crtc_assignment_apply (assignment);
++	    
++	crtc_assignment_free (assignment);
++
++	return TRUE;
++    }
++    else
++    {
++	g_print (" ... no assignment found\n");
++    }
++
++    return FALSE;
++}
++
++gboolean
++configuration_apply_stored (RWScreen *screen)
++{
++    char *file = g_build_filename (
++	g_get_home_dir(), ".gnome2", "monitors.xml", NULL);
++    Configuration **configs = configurations_read (file, NULL);
++    Configuration *current = configuration_new_current (screen);
++    Configuration *found;
++    gboolean result;
++
++    if (configs)
++    {
++	if ((found = configuration_find (configs, current)))
++	{
++	    apply_configuration (found, screen);
++	    result = TRUE;
++	}
++	else
++	{
++	    result = FALSE;
++	    g_print ("Not found\n");
++	}
++	
++	configurations_free (configs);
++    }
++	
++    g_free (file);
++    configuration_free (current);
++
++    return result;
++}
++
++
++/*
++ * CRTC assignment
++ */
++typedef struct CrtcInfo CrtcInfo;
++
++struct CrtcInfo
++{
++    RWMode    *mode;
++    int        x;
++    int        y;
++    RWRotation rotation;
++    GPtrArray *outputs;
++};
++
++struct CrtcAssignment
++{
++    RWScreen *screen;
++    GHashTable *info;
++};
++
++static gboolean
++can_clone (CrtcInfo *info,
++	   RWOutput *output)
++{
++    int i;
++
++    for (i = 0; i < info->outputs->len; ++i)
++    {
++	RWOutput *clone = info->outputs->pdata[i];
++
++	if (!rw_output_can_clone (clone, output))
++	    return FALSE;
++    }
++
++    return TRUE;
++}
++
++static gboolean
++crtc_assignment_assign (CrtcAssignment *assign,
++			RWCrtc         *crtc,
++			RWMode         *mode,
++			int             x,
++			int             y,
++			RWRotation      rotation,
++			RWOutput       *output)
++{
++    /* FIXME: We should reject stuff that is outside the screen ranges */
++    
++    CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
++
++    if (!rw_crtc_can_drive_output (crtc, output) ||
++	!rw_output_supports_mode (output, mode)  ||
++	!rw_crtc_supports_rotation (crtc, rotation))
++    {
++	return FALSE;
++    }
++
++    if (info)
++    {
++	if (info->mode == mode		&&
++	    info->x == x		&&
++	    info->y == y		&&
++	    info->rotation == rotation  &&
++	    can_clone (info, output))
++	{
++	    g_ptr_array_add (info->outputs, output);
++
++	    return TRUE;
++	}
++    }
++    else
++    {	
++	CrtcInfo *info = g_new (CrtcInfo, 1);
++	
++	info->mode = mode;
++	info->x = x;
++	info->y = y;
++	info->rotation = rotation;
++	info->outputs = g_ptr_array_new ();
++	
++	g_ptr_array_add (info->outputs, output);
++	
++	g_hash_table_insert (assign->info, crtc, info);
++	    
++	return TRUE;
++    }
++    
++    return FALSE;
++}
++
++static void
++crtc_assignment_unassign (CrtcAssignment *assign,
++			  RWCrtc         *crtc,
++			  RWOutput       *output)
++{
++    CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
++
++    if (info)
++    {
++	g_ptr_array_remove (info->outputs, output);
++
++	if (info->outputs->len == 0)
++	    g_hash_table_remove (assign->info, crtc);
++    }
++}
++
++static void
++crtc_assignment_free (CrtcAssignment *assign)
++{
++    g_hash_table_destroy (assign->info);
++
++    g_free (assign);
++}
++
++static void
++configure_crtc (gpointer key,
++		gpointer value,
++		gpointer data)
++{
++    RWCrtc *crtc = key;
++    CrtcInfo *info = value;
++    GTimer *timer = g_timer_new ();
++
++    g_print ("Configuring crtc %x with ", rw_crtc_get_id (crtc));
++
++    if (info->mode)
++    {
++	int n_outputs = info->outputs->len;
++	
++	g_print ("mode %x, %d outputs (%d %d %d %d), and rotation %d ", 
++		 rw_mode_get_id (info->mode),
++		 n_outputs,
++		 info->x, info->y,
++		 rw_mode_get_width (info->mode),
++		 rw_mode_get_height (info->mode),
++		 info->rotation);
++    }
++    else
++    {
++	g_print ("no mode ");
++    }
++    
++    if (rw_crtc_set_config (crtc,
++			    info->x, info->y,
++			    info->mode,
++			    info->rotation,
++			    (RWOutput **)info->outputs->pdata,
++			    info->outputs->len))
++    {
++	g_print ("succeeded");
++    }
++    else
++    {
++	g_print ("failed");
++    }
++
++    g_print (" in %f seconds\n", g_timer_elapsed (timer, NULL));
++}
++
++static gboolean
++crtc_is_rotated (CrtcInfo *info)
++{
++    if ((info->rotation & RW_ROTATION_270)		||
++	(info->rotation & RW_ROTATION_90))
++    {
++	g_print ("rotated: %d\n", info->rotation);
++	return TRUE;
++    }
++    return FALSE;
++}
++
++static void
++crtc_assignment_apply (CrtcAssignment *assign)
++{
++    GList *active_crtcs = g_hash_table_get_keys (assign->info);
++    RWCrtc **all_crtcs = rw_screen_list_crtcs (assign->screen);
++    GList *list;
++    int width, height;
++    GTimer *timer;
++    int i;
++    int min_width, max_width, min_height, max_height;
++
++    /* Compute size of the screen */
++    width = height = 1;
++    for (list = active_crtcs; list != NULL; list = list->next)
++    {
++	RWCrtc *crtc = list->data;
++	CrtcInfo *info = g_hash_table_lookup (assign->info, crtc);
++	int w, h;
++
++	w = rw_mode_get_width (info->mode);
++	h = rw_mode_get_height (info->mode);
++	
++	if (crtc_is_rotated (info))
++	{
++	    int tmp = h;
++	    h = w;
++	    w = tmp;
++	}
++	
++	width = MAX (width, info->x + w);
++	height = MAX (height, info->y + h);
++    }
++    g_list_free (active_crtcs);
++
++    g_print ("w, h: %d %d\n", width, height);
++    
++    rw_screen_get_ranges (
++	assign->screen, &min_width, &max_width, &min_height, &max_height);
++
++    width = MAX (min_width, width);
++    width = MIN (max_width, width);
++    height = MAX (min_height, height);
++    height = MIN (max_height, height);
++    
++    /* Turn off all crtcs currently displaying outside the new screen */
++    for (i = 0; all_crtcs[i] != NULL; ++i)
++    {
++	RWCrtc *crtc = all_crtcs[i];
++	RWMode *mode = rw_crtc_get_current_mode (crtc);
++	int x, y;
++
++	if (mode)
++	{
++	    rw_crtc_get_position (crtc, &x, &y);
++
++	    if (x + rw_mode_get_width (mode) > width		||
++		y + rw_mode_get_height (mode) > height)
++	    {
++		rw_crtc_set_config (crtc, 0, 0, NULL, RW_ROTATION_0, NULL, 0);
++	    }
++	}
++    }
++
++    /* Turn off all CRTC's that are not in the assignment */
++    for (i = 0; all_crtcs[i] != NULL; ++i)
++    {
++	RWCrtc *crtc = all_crtcs[i];
++	
++	if (!g_hash_table_lookup (assign->info, crtc))
++	    rw_crtc_set_config (crtc, 0, 0, NULL, RW_ROTATION_0, NULL, 0);
++    }
++
++    /* FIXME: What do we do about physical size?
++     *
++     * As far as this function is concerned, probably just pass the problem up to
++     * the callers. There, the best possibility might be to pick the sum of
++     * physical sizes, but the reality is that the physical size of an X screen is
++     * a meaningless concept in a randr 1.2 world.
++     */
++    timer = g_timer_new ();
++    g_print ("setting size to %d %d\n", width, height);
++    
++    rw_screen_set_size (assign->screen, width, height, 300, 230);
++
++    gdk_flush ();
++    
++    g_print ("time to set screen size: %f\n", g_timer_elapsed (timer, NULL));
++
++    g_timer_reset (timer);
++    
++    g_hash_table_foreach (assign->info, configure_crtc, NULL);
++
++    gdk_flush ();
++    
++    g_print ("time to configure crtc's: %f\n", g_timer_elapsed (timer, NULL));
++
++    g_timer_destroy (timer);
++}
++
++/* Check whether the given set of settings can be used
++ * at the same time -- ie. whether there is an assignment
++ * of CRTC's to outputs.
++ *
++ * Brute force - the number of objects involved is small
++ * enough that it doesn't matter.
++ */
++static gboolean
++real_assign_crtcs (RWScreen *screen,
++		   Output **outputs,
++		   CrtcAssignment *assignment)
++{
++    RWCrtc **crtcs = rw_screen_list_crtcs (screen);
++    Output *output;
++    int i;
++
++    output = *outputs;
++    if (!output)
++	return TRUE;
++
++    /* It is always allowed for an output to be turned off */
++    if (!output->on)
++    {
++	return real_assign_crtcs (screen, outputs + 1, assignment);
++    }
++    
++    for (i = 0; crtcs[i] != NULL; ++i)
++    {
++	RWCrtc *crtc = crtcs[i];
++	RWOutput *rw_output = rw_screen_get_output_by_name (screen, output->name);
++	RWMode **modes = rw_output_list_modes (rw_output);
++	int j;
++
++	for (j = 0; modes[j] != NULL; ++j)
++	{
++	    RWMode *mode = modes[j];
++	    
++	    if (rw_mode_get_width (mode) == output->width	&&
++		rw_mode_get_height (mode) == output->height	&&
++		rw_mode_get_freq (mode) == output->rate)
++	    {
++		if (crtc_assignment_assign (
++			assignment, crtc, modes[j],
++			output->x, output->y,
++			output->rotation,
++			rw_output))
++		{
++		    if (real_assign_crtcs (screen, outputs + 1, assignment))
++			return TRUE;
++		    
++		    crtc_assignment_unassign (assignment, crtc, rw_output);
++		}
++	    }
++#if 0
++	    else
++	    {
++		g_print ("rejected %d x %d x %d for %s\n",
++			 rw_mode_get_width (mode),
++			 rw_mode_get_height (mode),
++			 rw_mode_get_freq (mode),
++			 output->name);
++
++		g_print ("desired: %d x %d x %d\n",
++			 output->width, output->height, output->rate);
++	    }
++#endif
++	}
++    }
++
++    return FALSE;
++}
++
++static void
++crtc_info_free (CrtcInfo *info)
++{
++    g_ptr_array_free (info->outputs, TRUE);
++    g_free (info);
++}
++
++static CrtcAssignment *
++crtc_assignment_new (RWScreen *screen, Output **outputs)
++{
++    CrtcAssignment *assignment = g_new0 (CrtcAssignment, 1);
++
++    assignment->info = g_hash_table_new_full (
++	g_direct_hash, g_direct_equal, NULL, (GFreeFunc)crtc_info_free);
++
++    if (real_assign_crtcs (screen, outputs, assignment))
++    {
++	assignment->screen = screen;
++	
++	return assignment;
++    }
++    else
++    {
++	crtc_assignment_free (assignment);
++    
++	return NULL;
++    }
++}
+diff -up /dev/null gnome-desktop-2.21.91/libgnome-desktop/randrwrap.c
 --- /dev/null	2008-02-12 08:56:47.229685651 -0500
-+++ gnome-desktop-2.21.90/libgnome-desktop/randrwrap.c	2008-02-12 09:12:16.000000000 -0500
++++ gnome-desktop-2.21.91/libgnome-desktop/randrwrap.c	2008-02-12 11:44:30.000000000 -0500
 @@ -0,0 +1,1042 @@
 +#define I_KNOW_THIS_IS_UNSTABLE_AND_ONLY_IN_FEDORA
 +#include "libgnomeui/randrwrap.h"
@@ -1188,9 +2433,9 @@
 +    return 0;
 +}
 +#endif
-diff -up gnome-desktop-2.21.90/libgnome-desktop/Makefile.am.add-randr-12 gnome-desktop-2.21.90/libgnome-desktop/Makefile.am
---- gnome-desktop-2.21.90/libgnome-desktop/Makefile.am.add-randr-12	2008-01-27 18:44:20.000000000 -0500
-+++ gnome-desktop-2.21.90/libgnome-desktop/Makefile.am	2008-02-12 11:35:10.000000000 -0500
+diff -up gnome-desktop-2.21.91/libgnome-desktop/Makefile.am.add-randr-12 gnome-desktop-2.21.91/libgnome-desktop/Makefile.am
+--- gnome-desktop-2.21.91/libgnome-desktop/Makefile.am.add-randr-12	2008-02-11 13:35:11.000000000 -0500
++++ gnome-desktop-2.21.91/libgnome-desktop/Makefile.am	2008-02-12 11:37:35.000000000 -0500
 @@ -20,7 +20,9 @@ libgnome_desktop_2_la_SOURCES = \
  	gnome-desktop-item.c	\
  	gnome-ditem-edit.c	\




More information about the fedora-extras-commits mailing list