diff --git a/libgnome-desktop/ChangeLog b/libgnome-desktop/ChangeLog index 747f8ae..3166b49 100644 --- a/libgnome-desktop/ChangeLog +++ b/libgnome-desktop/ChangeLog @@ -1,3 +1,43 @@ +2008-12-12 Vincent Untz + + * gnome-rr-config.c: (crtc_assignment_new): + * gnome-rr.c: (gnome_rr_crtc_set_config): fix translator comments, to + really fix bug #563831. + +2008-12-10 Vincent Untz + + * gnome-rr-config.c: (has_similar_mode): kill since it's unused and + creates a warning + +2008-12-10 Vincent Untz + + * gnome-rr-config.c: (crtc_assignment_new): + * gnome-rr.c: (gnome_rr_crtc_set_config): + Fix build, thanks to Frederic Peters for the quick + notice. Fix bug #563926 and bug #563927. + +2008-12-09 Federico Mena Quintero + + Fix http://bugzilla.gnome.org/show_bug.cgi?id=563831 + + * gnome-rr.c (gnome_rr_crtc_set_config): Make an error string more + friendly to translation. + + * gnome-rr-config.c (crtc_assignment_new): Likewise. + +2008-10-16 Federico Mena Quintero + + Add error reporting to the GnomeRR API. + + * libgnomeui/gnome-rr.h (GnomeRRError): New enum with error codes + for the GnomeRR API. + + * gnome-rr.c (gnome_rr_error_quark): New public function. + +Wed Oct 8 21:05:22 2008 Søren Sandmann + + * Various new RR API to support fn-F7 support + ==================== 2.24.0 ==================== 2008-09-22 Vincent Untz diff --git a/libgnome-desktop/gnome-rr-config.c b/libgnome-desktop/gnome-rr-config.c index 4c0800a..7880c7e 100644 --- a/libgnome-desktop/gnome-rr-config.c +++ b/libgnome-desktop/gnome-rr-config.c @@ -24,6 +24,8 @@ #define GNOME_DESKTOP_USE_UNSTABLE_API +#include +#include #include #include #include @@ -66,9 +68,11 @@ static gboolean parse_file_gmarkup (const gchar *file, typedef struct CrtcAssignment CrtcAssignment; -static gboolean crtc_assignment_apply (CrtcAssignment *assign); +static gboolean crtc_assignment_apply (CrtcAssignment *assign, + GError **error); static CrtcAssignment *crtc_assignment_new (GnomeRRScreen *screen, - GnomeOutputInfo **outputs); + GnomeOutputInfo **outputs, + GError **error); static void crtc_assignment_free (CrtcAssignment *assign); static void output_free (GnomeOutputInfo *output); static GnomeOutputInfo *output_copy (GnomeOutputInfo *output); @@ -746,6 +750,42 @@ output_match (GnomeOutputInfo *output1, GnomeOutputInfo *output2) return TRUE; } +static gboolean +output_equal (GnomeOutputInfo *output1, GnomeOutputInfo *output2) +{ + g_assert (output1 != NULL); + g_assert (output2 != NULL); + + if (!output_match (output1, output2)) + return FALSE; + + if (output1->on != output2->on) + return FALSE; + + if (output1->on) + { + if (output1->width != output2->width) + return FALSE; + + if (output1->height != output2->height) + return FALSE; + + if (output1->rate != output2->rate) + return FALSE; + + if (output1->x != output2->x) + return FALSE; + + if (output1->y != output2->y) + return FALSE; + + if (output1->rotation != output2->rotation) + return FALSE; + } + + return TRUE; +} + static GnomeOutputInfo * find_output (GnomeRRConfig *config, const char *name) { @@ -762,6 +802,9 @@ find_output (GnomeRRConfig *config, const char *name) return NULL; } +/* Match means "these configurations apply to the same hardware + * setups" + */ gboolean gnome_rr_config_match (GnomeRRConfig *c1, GnomeRRConfig *c2) { @@ -780,6 +823,28 @@ gnome_rr_config_match (GnomeRRConfig *c1, GnomeRRConfig *c2) return TRUE; } +/* Equal means "the configurations will result in the same + * modes being set on the outputs" + */ +gboolean +gnome_rr_config_equal (GnomeRRConfig *c1, + GnomeRRConfig *c2) +{ + int i; + + for (i = 0; c1->outputs[i] != NULL; ++i) + { + GnomeOutputInfo *output1 = c1->outputs[i]; + GnomeOutputInfo *output2; + + output2 = find_output (c2, output1->name); + if (!output2 || !output_equal (output1, output2)) + return FALSE; + } + + return TRUE; +} + static GnomeOutputInfo ** make_outputs (GnomeRRConfig *config) { @@ -820,12 +885,19 @@ make_outputs (GnomeRRConfig *config) gboolean gnome_rr_config_applicable (GnomeRRConfig *configuration, - GnomeRRScreen *screen) + GnomeRRScreen *screen, + GError **error) { - GnomeOutputInfo **outputs = make_outputs (configuration); - CrtcAssignment *assign = crtc_assignment_new (screen, outputs); + GnomeOutputInfo **outputs; + CrtcAssignment *assign; gboolean result; + g_return_val_if_fail (configuration != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + outputs = make_outputs (configuration); + assign = crtc_assignment_new (screen, outputs, error); + if (assign) { result = TRUE; @@ -841,21 +913,6 @@ gnome_rr_config_applicable (GnomeRRConfig *configuration, return result; } -static GnomeRRConfig * -gnome_rr_config_find (GnomeRRConfig **haystack, - GnomeRRConfig *needle) -{ - int i; - - for (i = 0; haystack[i] != NULL; ++i) - { - if (gnome_rr_config_match (haystack[i], needle)) - return haystack[i]; - } - - return NULL; -} - /* Database management */ static gchar * @@ -992,14 +1049,19 @@ gnome_rr_config_sanitize (GnomeRRConfig *config) gboolean -gnome_rr_config_save (GnomeRRConfig *configuration, GError **err) +gnome_rr_config_save (GnomeRRConfig *configuration, GError **error) { GnomeRRConfig **configurations; - GString *output = g_string_new(""); + GString *output; int i; gchar *filename; gboolean result; + g_return_val_if_fail (configuration != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + output = g_string_new (""); + configurations = configurations_read (NULL); /* NULL-GError */ g_string_append_printf (output, "\n"); @@ -1020,7 +1082,7 @@ gnome_rr_config_save (GnomeRRConfig *configuration, GError **err) g_string_append_printf (output, "\n"); filename = get_config_filename (); - result = g_file_set_contents (filename, output->str, -1, err); + result = g_file_set_contents (filename, output->str, -1, error); g_free (filename); if (result) @@ -1037,22 +1099,82 @@ gnome_rr_config_save (GnomeRRConfig *configuration, GError **err) return result; } -static gboolean -apply_configuration (GnomeRRConfig *conf, GnomeRRScreen *screen) +static GnomeRRConfig * +gnome_rr_config_copy (GnomeRRConfig *config) +{ + GnomeRRConfig *copy = g_new0 (GnomeRRConfig, 1); + int i; + GPtrArray *array = g_ptr_array_new (); + + copy->clone = config->clone; + + for (i = 0; config->outputs[i] != NULL; ++i) + g_ptr_array_add (array, output_copy (config->outputs[i])); + + g_ptr_array_add (array, NULL); + copy->outputs = (GnomeOutputInfo **)g_ptr_array_free (array, FALSE); + + return copy; +} + +GnomeRRConfig * +gnome_rr_config_new_stored (GnomeRRScreen *screen, GError **error) +{ + GnomeRRConfig *current; + GnomeRRConfig **configs; + GnomeRRConfig *result; + + g_return_val_if_fail (screen != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + current = gnome_rr_config_new_current (screen); + + configs = configurations_read (error); + + result = NULL; + if (configs) + { + int i; + + for (i = 0; configs[i] != NULL; ++i) + { + if (gnome_rr_config_match (configs[i], current)) + { + result = gnome_rr_config_copy (configs[i]); + break; + } + } + + if (result == NULL) + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_MATCHING_CONFIG, + _("none of the saved display configurations matched the active configuration")); + + configurations_free (configs); + } + + gnome_rr_config_free (current); + + return result; +} + +gboolean +gnome_rr_config_apply (GnomeRRConfig *config, + GnomeRRScreen *screen, + GError **error) { CrtcAssignment *assignment; GnomeOutputInfo **outputs; gboolean result = FALSE; - outputs = make_outputs (conf); + outputs = make_outputs (config); - assignment = crtc_assignment_new (screen, outputs); + assignment = crtc_assignment_new (screen, outputs, error); outputs_free (outputs); if (assignment) { - if (crtc_assignment_apply (assignment)) + if (crtc_assignment_apply (assignment, error)) result = TRUE; crtc_assignment_free (assignment); @@ -1064,44 +1186,42 @@ apply_configuration (GnomeRRConfig *conf, GnomeRRScreen *screen) } gboolean -gnome_rr_config_apply_stored (GnomeRRScreen *screen) +gnome_rr_config_apply_stored (GnomeRRScreen *screen, GError **error) { - GnomeRRConfig **configs; - GnomeRRConfig *current; - GnomeRRConfig *found; - gboolean result = TRUE; + GnomeRRConfig *stored; + GError *my_error; - if (!screen) - return FALSE; + g_return_val_if_fail (screen != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - configs = configurations_read (NULL); /* NULL-GError */ + my_error = NULL; + if (!gnome_rr_screen_refresh (screen, &my_error)) { + if (my_error) { + g_propagate_error (error, my_error); + return FALSE; /* This is a genuine error */ + } - gnome_rr_screen_refresh (screen); - - current = gnome_rr_config_new_current (screen); + /* This means the screen didn't change, so just proceed */ + } - if (configs) + stored = gnome_rr_config_new_stored (screen, error); + + if (stored) { - if ((found = gnome_rr_config_find (configs, current))) - { - apply_configuration (found, screen); + gboolean result; - result = TRUE; - } - else - { - result = FALSE; - } + result = gnome_rr_config_apply (stored, screen, error); + + gnome_rr_config_free (stored); - configurations_free (configs); + return result; + } + else + { + return FALSE; } - - gnome_rr_config_free (current); - - return result; } - /* * CRTC assignment */ @@ -1214,6 +1334,11 @@ crtc_assignment_free (CrtcAssignment *assign) g_free (assign); } +typedef struct { + gboolean has_error; + GError **error; +} ConfigureCrtcState; + static void configure_crtc (gpointer key, gpointer value, @@ -1221,13 +1346,19 @@ configure_crtc (gpointer key, { GnomeRRCrtc *crtc = key; CrtcInfo *info = value; - - gnome_rr_crtc_set_config (crtc, - info->x, info->y, - info->mode, - info->rotation, - (GnomeRROutput **)info->outputs->pdata, - info->outputs->len); + ConfigureCrtcState *state = data; + + if (state->has_error) + return; + + if (!gnome_rr_crtc_set_config (crtc, + info->x, info->y, + info->mode, + info->rotation, + (GnomeRROutput **)info->outputs->pdata, + info->outputs->len, + state->error)) + state->has_error = TRUE; } static gboolean @@ -1368,7 +1499,7 @@ get_required_virtual_size (CrtcAssignment *assign, int *width, int *height) } static CrtcAssignment * -crtc_assignment_new (GnomeRRScreen *screen, GnomeOutputInfo **outputs) +crtc_assignment_new (GnomeRRScreen *screen, GnomeOutputInfo **outputs, GError **error) { CrtcAssignment *assignment = g_new0 (CrtcAssignment, 1); @@ -1388,6 +1519,15 @@ crtc_assignment_new (GnomeRRScreen *screen, GnomeOutputInfo **outputs) if (width < min_width || width > max_width || height < min_height || height > max_height) { + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_BOUNDS_ERROR, + /* Translators: the "requested", "minimum", and + * "maximum" words here are not keywords; please + * translate them as usual. */ + _("required virtual size does not fit available size: " + "requested=(%d, %d), minimum=(%d, %d), maximum=(%d, %d)"), + width, height, + min_width, min_height, + max_width, max_height); goto fail; } @@ -1395,6 +1535,9 @@ crtc_assignment_new (GnomeRRScreen *screen, GnomeOutputInfo **outputs) return assignment; } + else + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_CRTC_ASSIGNMENT, + _("could not find a suitable configuration of screens")); fail: crtc_assignment_free (assignment); @@ -1403,7 +1546,7 @@ fail: } static gboolean -crtc_assignment_apply (CrtcAssignment *assign) +crtc_assignment_apply (CrtcAssignment *assign, GError **error) { GnomeRRCrtc **all_crtcs = gnome_rr_screen_list_crtcs (assign->screen); int width, height; @@ -1425,6 +1568,8 @@ crtc_assignment_apply (CrtcAssignment *assign) width = MIN (max_width, width); height = MAX (min_height, height); height = MIN (max_height, height); + + /* FMQ: do we need to check the sizes instead of clamping them? */ /* Turn off all crtcs that are currently displaying outside the new screen, * or are not used in the new setup @@ -1452,7 +1597,7 @@ crtc_assignment_apply (CrtcAssignment *assign) if (x + w > width || y + h > height || !g_hash_table_lookup (assign->info, crtc)) { - if (!gnome_rr_crtc_set_config (crtc, 0, 0, NULL, GNOME_RR_ROTATION_0, NULL, 0)) + if (!gnome_rr_crtc_set_config (crtc, 0, 0, NULL, GNOME_RR_ROTATION_0, NULL, 0, error)) { success = FALSE; break; @@ -1473,9 +1618,16 @@ crtc_assignment_apply (CrtcAssignment *assign) if (success) { + ConfigureCrtcState state; + gnome_rr_screen_set_size (assign->screen, width, height, width_mm, height_mm); + + state.has_error = FALSE; + state.error = error; - g_hash_table_foreach (assign->info, configure_crtc, NULL); + g_hash_table_foreach (assign->info, configure_crtc, &state); + + success = !state.has_error; } return success; diff --git a/libgnome-desktop/gnome-rr.c b/libgnome-desktop/gnome-rr.c index 6a37d32..109b89e 100644 --- a/libgnome-desktop/gnome-rr.c +++ b/libgnome-desktop/gnome-rr.c @@ -24,6 +24,8 @@ #define GNOME_DESKTOP_USE_UNSTABLE_API +#include +#include #include "libgnomeui/gnome-rr.h" #include #include @@ -50,6 +52,8 @@ struct ScreenInfo GnomeRRMode ** modes; GnomeRRScreen * screen; + + GnomeRRMode ** clone_modes; }; struct GnomeRRScreen @@ -118,14 +122,16 @@ struct GnomeRRMode static GnomeRRCrtc * crtc_new (ScreenInfo *info, RRCrtc id); static void crtc_free (GnomeRRCrtc *crtc); -static void crtc_initialize (GnomeRRCrtc *crtc, - XRRScreenResources *res); +static gboolean crtc_initialize (GnomeRRCrtc *crtc, + XRRScreenResources *res, + GError **error); /* GnomeRROutput */ static GnomeRROutput *output_new (ScreenInfo *info, RROutput id); -static void output_initialize (GnomeRROutput *output, - XRRScreenResources *res); +static gboolean output_initialize (GnomeRROutput *output, + XRRScreenResources *res, + GError **error); static void output_free (GnomeRROutput *output); /* GnomeRRMode */ @@ -136,6 +142,22 @@ static void mode_initialize (GnomeRRMode *mode, static void mode_free (GnomeRRMode *mode); +/* Errors */ + +/** + * gnome_rr_error_quark: + * + * Returns the #GQuark that will be used for #GError values returned by the + * GnomeRR API. + * + * Return value: a #GQuark used to identify errors coming from the GnomeRR API. + */ +GQuark +gnome_rr_error_quark (void) +{ + return g_quark_from_static_string ("gnome-rr-error-quark"); +} + /* Screen */ static GnomeRROutput * gnome_rr_output_by_id (ScreenInfo *info, RROutput id) @@ -222,14 +244,90 @@ screen_info_free (ScreenInfo *info) mode_free (*mode); g_free (info->modes); } + + if (info->clone_modes) + { + /* The modes themselves were freed above */ + g_free (info->clone_modes); + } g_free (info); } static gboolean +has_similar_mode (GnomeRROutput *output, GnomeRRMode *mode) +{ + int i; + GnomeRRMode **modes = gnome_rr_output_list_modes (output); + int width = gnome_rr_mode_get_width (mode); + int height = gnome_rr_mode_get_height (mode); + + for (i = 0; modes[i] != NULL; ++i) + { + GnomeRRMode *m = modes[i]; + + if (gnome_rr_mode_get_width (m) == width && + gnome_rr_mode_get_height (m) == height) + { + return TRUE; + } + } + + return FALSE; +} + +static void +gather_clone_modes (ScreenInfo *info) +{ + int i; + GPtrArray *result = g_ptr_array_new (); + + for (i = 0; info->outputs[i] != NULL; ++i) + { + int j; + GnomeRROutput *output1, *output2; + + output1 = info->outputs[i]; + + if (!output1->connected) + continue; + + for (j = 0; output1->modes[j] != NULL; ++j) + { + GnomeRRMode *mode = output1->modes[j]; + gboolean valid; + int k; + + valid = TRUE; + for (k = 0; info->outputs[k] != NULL; ++k) + { + output2 = info->outputs[k]; + + if (!output2->connected) + continue; + + if (!has_similar_mode (output2, mode)) + { + valid = FALSE; + break; + } + } + + if (valid) + g_ptr_array_add (result, mode); + } + } + + g_ptr_array_add (result, NULL); + + info->clone_modes = (GnomeRRMode **)g_ptr_array_free (result, FALSE); +} + +static gboolean fill_out_screen_info (Display *xdisplay, Window xroot, - ScreenInfo *info) + ScreenInfo *info, + GError **error) { XRRScreenResources *resources; @@ -244,14 +342,18 @@ fill_out_screen_info (Display *xdisplay, &(info->max_width), &(info->max_height))) { /* XRR caught an error */ - return False; + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR, + _("could not get the range of screen sizes")); + return FALSE; } gdk_flush (); if (gdk_error_trap_pop ()) { /* Unhandled X Error was generated */ - return False; + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_UNKNOWN, + _("unhandled X error while getting the range of screen sizes")); + return FALSE; } #if 0 @@ -311,10 +413,16 @@ fill_out_screen_info (Display *xdisplay, /* Initialize */ for (crtc = info->crtcs; *crtc; ++crtc) - crtc_initialize (*crtc, resources); + { + if (!crtc_initialize (*crtc, resources, error)) + return FALSE; + } for (output = info->outputs; *output; ++output) - output_initialize (*output, resources); + { + if (!output_initialize (*output, resources, error)) + return FALSE; + } for (i = 0; i < resources->nmode; ++i) { @@ -322,6 +430,8 @@ fill_out_screen_info (Display *xdisplay, mode_initialize (mode, &(resources->modes[i])); } + + gather_clone_modes (info); return TRUE; } @@ -330,13 +440,14 @@ fill_out_screen_info (Display *xdisplay, #if 0 g_print ("Couldn't get screen resources\n"); #endif - + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR, + _("could not get the screen resources (CRTCs, outputs, modes)")); return FALSE; } } static ScreenInfo * -screen_info_new (GnomeRRScreen *screen) +screen_info_new (GnomeRRScreen *screen, GError **error) { ScreenInfo *info = g_new0 (ScreenInfo, 1); @@ -347,36 +458,36 @@ screen_info_new (GnomeRRScreen *screen) info->modes = NULL; info->screen = screen; - if (fill_out_screen_info (screen->xdisplay, screen->xroot, info)) + if (fill_out_screen_info (screen->xdisplay, screen->xroot, info, error)) { return info; } else { - g_free (info); + screen_info_free (info); return NULL; } } static gboolean -screen_update (GnomeRRScreen *screen, gboolean force_callback) +screen_update (GnomeRRScreen *screen, gboolean force_callback, GError **error) { ScreenInfo *info; gboolean changed = FALSE; g_assert (screen != NULL); - - info = screen_info_new (screen); - if (info) - { - if (info->resources->configTimestamp != screen->info->resources->configTimestamp) + + info = screen_info_new (screen, error); + if (!info) + return FALSE; + + if (info->resources->configTimestamp != screen->info->resources->configTimestamp) changed = TRUE; - screen_info_free (screen->info); + screen_info_free (screen->info); - screen->info = info; - } - + screen->info = info; + if ((changed || force_callback) && screen->callback) screen->callback (screen, screen->data); @@ -404,7 +515,7 @@ screen_on_event (GdkXEvent *xevent, /* FIXME: we may need to be more discriminating in * what causes 'changed' events */ - screen_update (screen, TRUE); + screen_update (screen, TRUE, NULL); /* NULL-GError */ } /* Pass the event on to GTK+ */ @@ -417,11 +528,14 @@ screen_on_event (GdkXEvent *xevent, GnomeRRScreen * gnome_rr_screen_new (GdkScreen *gdk_screen, GnomeRRScreenChanged callback, - gpointer data) + gpointer data, + GError **error) { Display *dpy = GDK_SCREEN_XDISPLAY (gdk_screen); int event_base; int ignore; + + g_return_val_if_fail (error == NULL || *error == NULL, NULL); if (XRRQueryExtension (dpy, &event_base, &ignore)) { @@ -438,7 +552,7 @@ gnome_rr_screen_new (GdkScreen *gdk_screen, screen->randr_event_base = event_base; - screen->info = screen_info_new (screen); + screen->info = screen_info_new (screen, error); if (!screen->info) { g_free (screen); @@ -459,8 +573,13 @@ gnome_rr_screen_new (GdkScreen *gdk_screen, gdk_window_add_filter (screen->gdk_root, screen_on_event, screen); return screen; } - - return NULL; + else + { + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_RANDR_EXTENSION, + _("RANDR extension is not present")); + + return NULL; + } } void @@ -511,10 +630,25 @@ gnome_rr_screen_get_ranges (GnomeRRScreen *screen, *max_height = screen->info->max_height; } +/** + * gnome_rr_screen_refresh + * @screen: a #GnomeRRScreen + * @error: location to store error, or %NULL + * + * Refreshes the screen configuration, and calls the screen's callback if it + * exists and if the screen's configuration changed. + * + * Return value: TRUE if the screen's configuration changed; otherwise, the + * function returns FALSE and a NULL error if the configuration didn't change, + * or FALSE and a non-NULL error if there was an error while refreshing the + * configuration. + */ gboolean -gnome_rr_screen_refresh (GnomeRRScreen *screen) +gnome_rr_screen_refresh (GnomeRRScreen *screen, + GError **error) { - return screen_update (screen, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + return screen_update (screen, FALSE, error); } GnomeRRMode ** @@ -526,6 +660,15 @@ gnome_rr_screen_list_modes (GnomeRRScreen *screen) return screen->info->modes; } +GnomeRRMode ** +gnome_rr_screen_list_clone_modes (GnomeRRScreen *screen) +{ + g_return_val_if_fail (screen != NULL, NULL); + g_return_val_if_fail (screen->info != NULL, NULL); + + return screen->info->clone_modes; +} + GnomeRRCrtc ** gnome_rr_screen_list_crtcs (GnomeRRScreen *screen) { @@ -647,8 +790,8 @@ read_edid_data (GnomeRROutput *output) return NULL; } -static void -output_initialize (GnomeRROutput *output, XRRScreenResources *res) +static gboolean +output_initialize (GnomeRROutput *output, XRRScreenResources *res, GError **error) { XRROutputInfo *info = XRRGetOutputInfo ( DISPLAY (output), res, output->id); @@ -661,8 +804,11 @@ output_initialize (GnomeRROutput *output, XRRScreenResources *res) if (!info || !output->info) { - /* FIXME */ - return; + /* FIXME: see the comment in crtc_initialize() */ + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR, + _("could not get information about output %d"), + (int) output->id); + return FALSE; } output->name = g_strdup (info->name); /* FIXME: what is nameLen used for? */ @@ -714,6 +860,8 @@ output_initialize (GnomeRROutput *output, XRRScreenResources *res) output->edid_data = read_edid_data (output); XRRFreeOutputInfo (info); + + return TRUE; } static void @@ -927,22 +1075,38 @@ gnome_rr_crtc_set_config (GnomeRRCrtc *crtc, GnomeRRMode *mode, GnomeRRRotation rotation, GnomeRROutput **outputs, - int n_outputs) + int n_outputs, + GError **error) { ScreenInfo *info; GArray *output_ids; + Status status; gboolean result; int i; g_return_val_if_fail (crtc != NULL, FALSE); g_return_val_if_fail (mode != NULL || outputs == NULL || n_outputs == 0, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); info = crtc->info; if (mode) { - g_return_val_if_fail (x + mode->width <= info->max_width, FALSE); - g_return_val_if_fail (y + mode->height <= info->max_height, FALSE); + if (x + mode->width > info->max_width + || y + mode->height > info->max_height) + { + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_BOUNDS_ERROR, + /* Translators: the "position", "size", and "maximum" + * words here are not keywords; please translate them + * as usual. */ + _("requested position/size for CRTC %d is outside the allowed limit: " + "position=(%d, %d), size=(%d, %d), maximum=(%d, %d)"), + (int) crtc->id, + x, y, + mode->width, mode->height, + info->max_width, info->max_height); + return FALSE; + } } output_ids = g_array_new (FALSE, FALSE, sizeof (RROutput)); @@ -953,15 +1117,24 @@ gnome_rr_crtc_set_config (GnomeRRCrtc *crtc, g_array_append_val (output_ids, outputs[i]->id); } - result = XRRSetCrtcConfig (DISPLAY (crtc), info->resources, crtc->id, + status = XRRSetCrtcConfig (DISPLAY (crtc), info->resources, crtc->id, CurrentTime, x, y, mode ? mode->id : None, xrotation_from_rotation (rotation), (RROutput *)output_ids->data, - output_ids->len) == RRSetConfigSuccess; + output_ids->len); g_array_free (output_ids, TRUE); + + if (status == RRSetConfigSuccess) + result = TRUE; + else { + result = FALSE; + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR, + _("could not set the configuration for CRTC %d"), + (int) crtc->id); + } return result; } @@ -1049,9 +1222,10 @@ crtc_new (ScreenInfo *info, RROutput id) return crtc; } -static void +static gboolean crtc_initialize (GnomeRRCrtc *crtc, - XRRScreenResources *res) + XRRScreenResources *res, + GError **error) { XRRCrtcInfo *info = XRRGetCrtcInfo (DISPLAY (crtc), res, crtc->id); GPtrArray *a; @@ -1064,7 +1238,12 @@ crtc_initialize (GnomeRRCrtc *crtc, if (!info) { /* FIXME: We need to reaquire the screen resources */ - return; + /* FIXME: can we actually catch BadRRCrtc, and does it make sense to emit that? */ + + g_set_error (error, GNOME_RR_ERROR, GNOME_RR_ERROR_RANDR_ERROR, + _("could not get information about CRTC %d"), + (int) crtc->id); + return FALSE; } /* GnomeRRMode */ @@ -1102,6 +1281,8 @@ crtc_initialize (GnomeRRCrtc *crtc, crtc->rotations = gnome_rr_rotation_from_xrotation (info->rotations); XRRFreeCrtcInfo (info); + + return TRUE; } static void diff --git a/libgnome-desktop/libgnomeui/gnome-rr-config.h b/libgnome-desktop/libgnomeui/gnome-rr-config.h index 6a8302d..a59db55 100644 --- a/libgnome-desktop/libgnomeui/gnome-rr-config.h +++ b/libgnome-desktop/libgnomeui/gnome-rr-config.h @@ -34,6 +34,13 @@ typedef struct GnomeOutputInfo GnomeOutputInfo; typedef struct GnomeRRConfig GnomeRRConfig; +/* FIXME: + * + * This structure is a Frankenstein monster where all of the fields + * are generated by the system, but some of them can be changed by + * the client. + */ + struct GnomeOutputInfo { char * name; @@ -66,14 +73,28 @@ struct GnomeRRConfig }; GnomeRRConfig *gnome_rr_config_new_current (GnomeRRScreen *screen); +GnomeRRConfig *gnome_rr_config_new_stored (GnomeRRScreen *screen, + GError **error); void gnome_rr_config_free (GnomeRRConfig *configuration); gboolean gnome_rr_config_match (GnomeRRConfig *config1, GnomeRRConfig *config2); +gboolean gnome_rr_config_equal (GnomeRRConfig *config1, + GnomeRRConfig *config2); gboolean gnome_rr_config_save (GnomeRRConfig *configuration, - GError **err); + GError **error); void gnome_rr_config_sanitize (GnomeRRConfig *configuration); -gboolean gnome_rr_config_apply_stored (GnomeRRScreen *screen); +gboolean gnome_rr_config_apply (GnomeRRConfig *configuration, + GnomeRRScreen *screen, + GError **error); +gboolean gnome_rr_config_apply_stored (GnomeRRScreen *screen, + GError **error); gboolean gnome_rr_config_applicable (GnomeRRConfig *configuration, - GnomeRRScreen *screen); + GnomeRRScreen *screen, + GError **error); + +/* A utility function that isn't really in the spirit of this file, but I don't + * don't know a better place for it. + */ +GnomeRRMode **gnome_rr_create_clone_modes (GnomeRRScreen *screen); #endif diff --git a/libgnome-desktop/libgnomeui/gnome-rr.h b/libgnome-desktop/libgnomeui/gnome-rr.h index 01b4f45..38b1af8 100644 --- a/libgnome-desktop/libgnomeui/gnome-rr.h +++ b/libgnome-desktop/libgnomeui/gnome-rr.h @@ -48,14 +48,31 @@ typedef enum GNOME_RR_REFLECT_Y = (1 << 5) } GnomeRRRotation; +/* Error codes */ + +#define GNOME_RR_ERROR (gnome_rr_error_quark ()) + +GQuark gnome_rr_error_quark (void); + +typedef enum { + GNOME_RR_ERROR_UNKNOWN, /* generic "fail" */ + GNOME_RR_ERROR_NO_RANDR_EXTENSION, /* RANDR extension is not present */ + GNOME_RR_ERROR_RANDR_ERROR, /* generic/undescribed error from the underlying XRR API */ + GNOME_RR_ERROR_BOUNDS_ERROR, /* requested bounds of a CRTC are outside the maximum size */ + GNOME_RR_ERROR_CRTC_ASSIGNMENT, /* could not assign CRTCs to outputs */ + GNOME_RR_ERROR_NO_MATCHING_CONFIG, /* none of the saved configurations matched the current configuration */ +} GnomeRRError; + /* GnomeRRScreen */ GnomeRRScreen * gnome_rr_screen_new (GdkScreen *screen, GnomeRRScreenChanged callback, - gpointer data); + gpointer data, + GError **error); void gnome_rr_screen_destroy (GnomeRRScreen *screen); GnomeRROutput **gnome_rr_screen_list_outputs (GnomeRRScreen *screen); GnomeRRCrtc ** gnome_rr_screen_list_crtcs (GnomeRRScreen *screen); GnomeRRMode ** gnome_rr_screen_list_modes (GnomeRRScreen *screen); +GnomeRRMode ** gnome_rr_screen_list_clone_modes (GnomeRRScreen *screen); void gnome_rr_screen_set_size (GnomeRRScreen *screen, int width, int height, @@ -63,7 +80,8 @@ void gnome_rr_screen_set_size (GnomeRRScreen *scree int mm_height); GnomeRRCrtc * gnome_rr_screen_get_crtc_by_id (GnomeRRScreen *screen, guint32 id); -gboolean gnome_rr_screen_refresh (GnomeRRScreen *screen); +gboolean gnome_rr_screen_refresh (GnomeRRScreen *screen, + GError **error); GnomeRROutput * gnome_rr_screen_get_output_by_id (GnomeRRScreen *screen, guint32 id); GnomeRROutput * gnome_rr_screen_get_output_by_name (GnomeRRScreen *screen, @@ -109,7 +127,8 @@ gboolean gnome_rr_crtc_set_config (GnomeRRCrtc *crtc, GnomeRRMode *mode, GnomeRRRotation rotation, GnomeRROutput **outputs, - int n_outputs); + int n_outputs, + GError **error); gboolean gnome_rr_crtc_can_drive_output (GnomeRRCrtc *crtc, GnomeRROutput *output); GnomeRRMode * gnome_rr_crtc_get_current_mode (GnomeRRCrtc *crtc); diff --git a/po/POTFILES.in b/po/POTFILES.in index 3bf18ac..84c9122 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -7,3 +7,5 @@ libgnome-desktop/display-name.c libgnome-desktop/gnome-desktop-item.c libgnome-desktop/gnome-ditem-edit.c libgnome-desktop/gnome-hint.c +libgnome-desktop/gnome-rr.c +libgnome-desktop/gnome-rr-config.c