diff --git a/capplets/display/ChangeLog b/capplets/display/ChangeLog index d8460ba..633fa45 100644 --- a/capplets/display/ChangeLog +++ b/capplets/display/ChangeLog @@ -1,3 +1,98 @@ +2008-12-18 Federico Mena Quintero + + * xrandr-capplet.c (get_output_for_window): Include "off" outputs + in the intersected rectangles. This makes the capplet not select + a new output when changing virtual desktops. + +2008-12-18 Federico Mena Quintero + + https://bugzilla.novell.com/show_bug.cgi?id=433939 - It's not + obvious how to turn on a new monitor. + + * display-capplet.glade: Add On/Off radio buttons for the selected + monitor, as it is hard to find that the on/off state is actually + set by the Resolution combo. + + * xrandr-capplet.c (rebuild_gui): Don't set sensitivity of + resolution_combo here... + (rebuild_resolution_combo): ... but do it here instead. This is + so that we can match the state of the monitor on/off buttons. + (rebuild_on_off_radios): New function. We set the on/off radio + buttons based on the "on" state of the current output. + (monitor_on_off_toggled_cb): New callback; we toggle the current + output's on/off state. + (rebuild_resolution_combo): Desensitize the resolution combo when + the output is off. Don't add an "Off" item to it, either. + +2008-12-16 Federico Mena Quintero + + https://bugzilla.novell.com/show_bug.cgi?id=450141 - Help button + in the Display capplet does nothing. + + * xrandr-capplet.c (run_application): Hide the Help button as we + have no help to show for this capplet yet. + (hide_help_button): New function. + +2008-12-15 Federico Mena Quintero + + * xrandr-capplet.c (on_screen_changed): Use + select_current_output_from_dialog_position() instead of selecting + an output ourselves. + +2008-12-15 Federico Mena Quintero + + * xrandr-capplet.c (select_current_output_from_dialog_position): + New function. + (dialog_map_event_cb): New GtkWidget::map-event handler for the + toplevel dialog. When the dialog gets mapped, we make the current + output be the one which actually contains the dialog window, so + that the user can edit the monitor which he's looking at. + +2008-12-15 Federico Mena Quintero + + * display-capplet.glade: Put the "Monitor" label inside an event + box, so we can change the background color of the event box. Give + names to both widgets: current_monitor_label, + current_monitor_event_box. + + * xrandr-capplet.c (rebuild_gui): When a monitor is selected, + update the "Monitor" label to include the monitor's name and color + so the user will know which monitor he is editing. + (rebuild_current_monitor_label): New function. + (struct App): New fields current_monitor_label, + current_monitor_event_box. + +2008-12-12 Federico Mena Quintero + + https://bugzilla.novell.com/show_bug.cgi?id=381030 - Prettify the + Display capplet's dialog + + * display-capplet.glade: Use the HIG's recommended colons, + capitalization, and spacing. Use headers to separate the Monitor + options from the Panel icon option. Add instructions on how to + operate the draggable monitors. + +2008-12-12 Federico Mena Quintero + + * xrandr-capplet.c (on_clone_changed): If we turn off "mirror + screens", and if the monitors are still overlapping, lay out the + monitors from left to right so that the user will know that all + the monitors are present. Previously you had to know that you had + to un-overlap them by hand. + (lay_out_outputs_horizontally): New function. + +2008-12-03 Federico Mena Quintero + + * xrandr-capplet.c (rebuild_rotation_combo): Pass a NULL error + argument to gnome_rr_config_applicable; we should really show why + that rotation is not available. + (apply): Use the new DBus interface from the XRANDR plugin in + g-s-d instead of an X client message. Display an error if g-s-d + couldn't apply the monitor configuration. + (gnome_randr_atom): Removed. + (on_detect_displays): Display an error if detecting the displays fails. + (run_application): Display error messages. + 2008-09-06 Jens Granseuer Patch by: Bruce Cowan diff --git a/capplets/display/Makefile.am b/capplets/display/Makefile.am index 193fd65..d8f7d10 100644 --- a/capplets/display/Makefile.am +++ b/capplets/display/Makefile.am @@ -15,8 +15,8 @@ gnome_display_properties_SOURCES = \ gnome_display_properties_LDFLAGS = -export-dynamic gnome_display_properties_LDADD = \ - $(DISPLAY_CAPPLET_LIBS) \ - $(top_builddir)/capplets/common/libcommon.la + $(top_builddir)/capplets/common/libcommon.la \ + $(DISPLAY_CAPPLET_LIBS) @INTLTOOL_DESKTOP_RULE@ diff --git a/capplets/display/display-capplet.glade b/capplets/display/display-capplet.glade index 45d6e4e..7500993 100644 --- a/capplets/display/display-capplet.glade +++ b/capplets/display/display-capplet.glade @@ -1,265 +1,538 @@ - - - + + + - - 18 - Monitor Resolution Settings - GDK_WINDOW_TYPE_HINT_DIALOG - False - - - True - - - True - 24 - - - True - 12 - - - True - True - Mirror Screens - True - 0 - True - - - False - False - - - - - True - - - - - - 1 - - - - - True - 12 - 12 - 24 - 24 - - - True - 2 - 4 - 12 - 12 - - - True - True - 0 - True - - - - - - 3 - 4 - GTK_FILL - - - - - - True - Normal + + + 5 + Display Settings + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 2 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-help + True + GTK_RELIEF_NORMAL + True + -11 + + + + + + True + True + True + gtk-apply + True + GTK_RELIEF_NORMAL + True + -10 + + + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + -7 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + False + 12 + + + + True + <i>Drag the monitors to set their place</i> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 0 + 0 + + + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + True + _Mirror screens + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + _Detect Monitors + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + GTK_PACK_END + + + + + 0 + False + False + + + + + + True + True + False + + + + True + <b>Monitor</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + + + 0 + False + False + + + + + + True + 3 + 5 + False + 6 + 12 + + + + True + Include _panel + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 3 + 5 + 1 + 2 + shrink|fill + + + + + + + True + _Resolution: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 1 + 2 + shrink|fill + + + + + + + True + Re_fresh rate: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 1 + 2 + 2 + 3 + shrink|fill + + + + + + + True + R_otation: + True + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 3 + 4 + 2 + 3 + shrink|fill + + + + + + + True + False + True + + + 2 + 3 + 1 + 2 + expand|shrink|fill + + + + + + + True + False + True + + + 2 + 3 + 2 + 3 + + + + + + + True + Normal Left Right Upside-down - - - 3 - 4 - 1 - 2 - GTK_FILL - - - - - True - 0 - R_otation - True - - - 2 - 3 - 1 - 2 - GTK_FILL - - - - - - True - 0 - Include _Panel - True - panel_checkbox - - - 2 - 3 - GTK_FILL - - - - - - True - - - 1 - 2 - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - - - 1 - 2 - GTK_FILL - - - - - True - 0 - Re_fresh Rate: - True - - - 1 - 2 - GTK_FILL - - - - - - True - 0 - _Resolution - True - - - GTK_FILL - - - - - - - - False - 2 - - - - - True - True - _Detect Displays - True - 0 - - - False - False - 3 - - - - - True - True - _Show Displays in Panel - True - 0 - True - - - 4 - - - - - - - 1 - - - - - True - GTK_BUTTONBOX_END - - - True - True - True - gtk-help - True - -11 - - - - - True - True - True - gtk-apply - True - -10 - - - 1 - - - - - True - True - True - gtk-close - True - -7 - - - 2 - - - - - False - GTK_PACK_END - - - - - + False + True + + + 4 + 5 + 2 + 3 + + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + + + + 0 + 1 + 0 + 3 + fill + + + + + + True + False + 12 + + + + True + True + On + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + Off + True + GTK_RELIEF_NORMAL + True + False + False + True + monitor_on_radio + + + 0 + False + False + + + + + 1 + 5 + 0 + 1 + fill + fill + + + + + 0 + False + True + + + + + + True + <b>Panel icon</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + True + _Show displays in panel + True + GTK_RELIEF_NORMAL + True + False + False + True + + + + + 0 + False + False + + + + + 0 + True + True + + + + + + diff --git a/capplets/display/scrollarea.c b/capplets/display/scrollarea.c index 3d3d8b6..666b70c 100644 --- a/capplets/display/scrollarea.c +++ b/capplets/display/scrollarea.c @@ -816,7 +816,7 @@ foo_scroll_area_size_allocate (GtkWidget *widget, -widget->allocation.x, -widget->allocation.y); invalid = gdk_region_rectangle (allocation); gdk_region_offset (invalid, -allocation->x, -allocation->y); - gdk_region_subtract (invalid, old_allocation); + gdk_region_xor (invalid, old_allocation); allocation_to_canvas_region (scroll_area, invalid); foo_scroll_area_invalidate_region (scroll_area, invalid); gdk_region_destroy (old_allocation); diff --git a/capplets/display/xrandr-capplet.c b/capplets/display/xrandr-capplet.c index ae6b80b..0505d65 100644 --- a/capplets/display/xrandr-capplet.c +++ b/capplets/display/xrandr-capplet.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include typedef struct App App; typedef struct GrabInfo GrabInfo; @@ -45,12 +47,15 @@ struct App GnomeOutputInfo *current_output; GtkWidget *dialog; + GtkWidget *current_monitor_event_box; + GtkWidget *current_monitor_label; + GtkWidget *monitor_on_radio; + GtkWidget *monitor_off_radio; GtkListStore *resolution_store; GtkWidget *resolution_combo; GtkWidget *refresh_combo; GtkWidget *rotation_combo; GtkWidget *panel_checkbox; - GtkWidget *panel_label; GtkWidget *clone_checkbox; GtkWidget *show_icon_checkbox; @@ -61,26 +66,25 @@ struct App static void rebuild_gui (App *app); static void on_rate_changed (GtkComboBox *box, gpointer data); +static gboolean output_overlaps (GnomeOutputInfo *output, GnomeRRConfig *config); +static void select_current_output_from_dialog_position (App *app); +static void monitor_on_off_toggled_cb (GtkToggleButton *toggle, gpointer data); -#if 0 static void -show_error (const GError *err) +error_message (App *app, const char *primary_text, const char *secondary_text) { - if (!err) - return; + GtkWidget *dialog; - GtkWidget *dialog = gtk_message_dialog_new ( - NULL, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_WARNING, - GTK_BUTTONS_OK, err->message); - - gtk_window_set_title (GTK_WINDOW (dialog), ""); + dialog = gtk_message_dialog_new ((app && app->dialog) ? GTK_WINDOW (app->dialog) : NULL, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + "%s", primary_text); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", secondary_text); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } -#endif static gboolean do_free (gpointer data) @@ -113,7 +117,6 @@ on_screen_changed (GnomeRRScreen *scr, GnomeRRConfig *current; App *app = data; int i; - GnomeOutputInfo *best; current = gnome_rr_config_new_current (app->screen); @@ -157,25 +160,7 @@ on_screen_changed (GnomeRRScreen *scr, } #endif - /* Select an output */ - best = NULL; - for (i = 0; app->current_configuration->outputs[i] != NULL; ++i) - { - GnomeOutputInfo *output = app->current_configuration->outputs[i]; - - if (output->connected) - { - char *cur_name = - app->current_output? app->current_output->name : NULL; - - if ((cur_name && strcmp (output->name, cur_name) == 0) || !best) - best = output; - } - } - - app->current_output = best; - - rebuild_gui (app); + select_current_output_from_dialog_position (app); } static void @@ -264,16 +249,14 @@ add_key (GtkWidget *widget, if (!info.found) { GtkTreeIter iter; - gtk_list_store_append (store, &iter); - - gtk_list_store_set (store, &iter, - 0, text, - 1, width, - 2, height, - 3, rate, - 4, width * height, - 5, rotation, - -1); + gtk_list_store_insert_with_values (store, &iter, -1, + 0, text, + 1, width, + 2, height, + 3, rate, + 4, width * height, + 5, rotation, + -1); retval = TRUE; } @@ -302,80 +285,6 @@ combo_select (GtkWidget *widget, const char *text) return TRUE; } -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 GnomeRRMode ** -list_clone_modes (GnomeRRConfig *config, GnomeRRScreen *screen) -{ - int i; - GPtrArray *result; - GnomeRRMode **modes; - - for (i = 0; config->outputs[i] != NULL; ++i) - { - if (config->outputs[i]->connected) - { - GnomeRROutput *output = - gnome_rr_screen_get_output_by_name (screen, config->outputs[i]->name); - - modes = gnome_rr_output_list_modes (output); - } - } - - if (!modes) - return NULL; - - result = g_ptr_array_new (); - - for (i = 0; modes[i] != NULL; ++i) - { - gboolean valid = TRUE; - int j; - - for (j = 0; config->outputs[j] != NULL; ++j) - { - if (config->outputs[j]->connected) - { - GnomeRROutput *output = gnome_rr_screen_get_output_by_name ( - screen, config->outputs[j]->name); - - if (!has_similar_mode (output, modes[i])) - { - valid = FALSE; - break; - } - } - } - - if (valid) - g_ptr_array_add (result, modes[i]); - } - - g_ptr_array_add (result, NULL); - - return (GnomeRRMode **)g_ptr_array_free (result, FALSE); -} - static GnomeRRMode ** get_current_modes (App *app) { @@ -383,7 +292,7 @@ get_current_modes (App *app) if (app->current_configuration->clone) { - return list_clone_modes (app->current_configuration, app->screen); + return gnome_rr_screen_list_clone_modes (app->screen); } else { @@ -435,7 +344,8 @@ rebuild_rotation_combo (App *app) app->current_output->rotation = info->rotation; - if (gnome_rr_config_applicable (app->current_configuration, app->screen)) + /* NULL-GError --- FIXME: we should say why this rotation is not available! */ + if (gnome_rr_config_applicable (app->current_configuration, app->screen, NULL)) { add_key (app->rotation_combo, info->name, 0, 0, 0, info->rotation); @@ -450,8 +360,6 @@ rebuild_rotation_combo (App *app) combo_select (app->rotation_combo, N_("Normal")); } -#define idle_free_printf(x) idle_free (g_strdup_printf (x)) - static void rebuild_rate_combo (App *app) { @@ -512,6 +420,7 @@ count_active_outputs (App *app) return count; } +#if 0 static int count_all_outputs (GnomeRRConfig *config) { @@ -522,6 +431,77 @@ count_all_outputs (GnomeRRConfig *config) return i; } +#endif + +static void +rebuild_current_monitor_label (App *app) +{ + char *str; + gboolean free_str; + GdkColor color; + gboolean use_color; + + if (app->current_output) + { + str = g_strdup_printf (_("Monitor: %s"), app->current_output->display_name); + free_str = TRUE; + gnome_rr_labeler_get_color_for_output (app->labeler, app->current_output, &color); + use_color = TRUE; + } + else + { + str = _("Monitor"); + free_str = FALSE; + use_color = FALSE; + } + + gtk_label_set_markup (GTK_LABEL (app->current_monitor_label), str); + + if (free_str) + g_free (str); + + if (use_color) + gtk_widget_modify_bg (app->current_monitor_event_box, app->current_monitor_event_box->state, &color); + + gtk_event_box_set_visible_window (GTK_EVENT_BOX (app->current_monitor_event_box), use_color); +} + +static void +rebuild_on_off_radios (App *app) +{ + gboolean sensitive; + gboolean on_active; + gboolean off_active; + + g_signal_handlers_block_by_func (app->monitor_on_radio, G_CALLBACK (monitor_on_off_toggled_cb), app); + g_signal_handlers_block_by_func (app->monitor_off_radio, G_CALLBACK (monitor_on_off_toggled_cb), app); + + if (app->current_output) + { + if (count_active_outputs (app) > 1 || !app->current_output->on) + sensitive = TRUE; + else + sensitive = FALSE; + + on_active = app->current_output->on; + off_active = !on_active; + } + else + { + sensitive = FALSE; + on_active = FALSE; + off_active = FALSE; + } + + gtk_widget_set_sensitive (app->monitor_on_radio, sensitive); + gtk_widget_set_sensitive (app->monitor_off_radio, sensitive); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->monitor_on_radio), on_active); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (app->monitor_off_radio), off_active); + + g_signal_handlers_unblock_by_func (app->monitor_on_radio, G_CALLBACK (monitor_on_off_toggled_cb), app); + g_signal_handlers_unblock_by_func (app->monitor_off_radio, G_CALLBACK (monitor_on_off_toggled_cb), app); +} static void rebuild_resolution_combo (App *app) @@ -533,8 +513,16 @@ rebuild_resolution_combo (App *app) clear_combo (app->resolution_combo); - if (!(modes = get_current_modes (app))) + if (!(modes = get_current_modes (app)) + || !app->current_output->on) + { + gtk_widget_set_sensitive (app->resolution_combo, FALSE); return; + } + + g_assert (app->current_output != NULL); + + gtk_widget_set_sensitive (app->resolution_combo, TRUE); best_w = 0; best_h = 0; @@ -556,20 +544,9 @@ rebuild_resolution_combo (App *app) } } - if (count_active_outputs (app) > 1 || !app->current_output->on) - add_key (app->resolution_combo, _("Off"), 0, 0, 0, 0); - - if (!app->current_output->on) - { - current = "Off"; - } - else - { - current = idle_free (g_strdup_printf (_("%d x %d"), - app->current_output->width, - app->current_output->height)); - } - + current = idle_free (g_strdup_printf (_("%d x %d"), + app->current_output->width, + app->current_output->height)); if (!combo_select (app->resolution_combo, current)) { @@ -597,12 +574,12 @@ rebuild_gui (App *app) g_debug ("rebuild gui, is on: %d", app->current_output->on); #endif + rebuild_current_monitor_label (app); + rebuild_on_off_radios (app); rebuild_resolution_combo (app); rebuild_rate_combo (app); rebuild_rotation_combo (app); - gtk_widget_set_sensitive (app->resolution_combo, sensitive); - #if 0 g_debug ("sensitive: %d, on: %d", sensitive, app->current_output->on); #endif @@ -682,6 +659,34 @@ on_rate_changed (GtkComboBox *box, gpointer data) } static void +monitor_on_off_toggled_cb (GtkToggleButton *toggle, gpointer data) +{ + App *app = data; + gboolean is_on; + + if (!app->current_output) + return; + + if (!gtk_toggle_button_get_active (toggle)) + return; + + if (GTK_WIDGET (toggle) == app->monitor_on_radio) + is_on = TRUE; + else if (GTK_WIDGET (toggle) == app->monitor_off_radio) + is_on = FALSE; + else + { + g_assert_not_reached (); + return; + } + + app->current_output->on = is_on; + + rebuild_gui (app); + foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)); +} + +static void on_resolution_changed (GtkComboBox *box, gpointer data) { App *app = data; @@ -727,6 +732,47 @@ on_resolution_changed (GtkComboBox *box, gpointer data) } static void +lay_out_outputs_horizontally (App *app) +{ + int i; + int x; + + /* Lay out all the monitors horizontally when "mirror screens" is turned + * off, to avoid having all of them overlapped initially. We put the + * outputs turned off on the right-hand side. + */ + + x = 0; + + /* First pass, all "on" outputs */ + + for (i = 0; app->current_configuration->outputs[i]; ++i) + { + GnomeOutputInfo *output; + + output = app->current_configuration->outputs[i]; + if (output->connected && output->on) + output->x = x; + + x += output->width; + } + + /* Second pass, all the black screens */ + + for (i = 0; app->current_configuration->outputs[i]; ++i) + { + GnomeOutputInfo *output; + + output = app->current_configuration->outputs[i]; + if (!(output->connected && output->on)) + output->x = x; + + x += output->width; + } + +} + +static void on_clone_changed (GtkWidget *box, gpointer data) { App *app = data; @@ -747,6 +793,11 @@ on_clone_changed (GtkWidget *box, gpointer data) } } } + else + { + if (output_overlaps (app->current_output, app->current_configuration)) + lay_out_outputs_horizontally (app); + } rebuild_gui (app); } @@ -1411,7 +1462,7 @@ paint_output (App *app, cairo_t *cr, int i) } else if (output->rotation & GNOME_RR_ROTATION_90) { - angle = G_PI / 2; + angle = 1.5 * G_PI; } else if (output->rotation & GNOME_RR_ROTATION_180) { @@ -1419,7 +1470,7 @@ paint_output (App *app, cairo_t *cr, int i) } else if (output->rotation & GNOME_RR_ROTATION_270) { - angle = 1.5 * G_PI; + angle = G_PI / 2; } else { @@ -1565,20 +1616,6 @@ make_text_combo (GtkWidget *widget, int sort_column) } } -static Atom -gnome_randr_atom (void) -{ - static Atom atom = None; - - if (!atom) - { - atom = XInternAtom (gdk_x11_get_default_xdisplay(), - "_GNOME_RANDR_ATOM", FALSE); - } - - return atom; -} - static void compute_virtual_size_for_configuration (GnomeRRConfig *config, int *ret_width, int *ret_height) { @@ -1636,7 +1673,9 @@ check_required_virtual_size (App *app) static void apply (App *app) { - GError *err = NULL; + GError *error = NULL; + DBusGConnection *connection; + DBusGProxy *proxy; gnome_rr_config_sanitize (app->current_configuration); @@ -1644,25 +1683,40 @@ apply (App *app) foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)); - if (gnome_rr_config_save (app->current_configuration, &err)) + if (!gnome_rr_config_save (app->current_configuration, &error)) { - XEvent message; + error_message (app, _("Could not save the monitor configuration"), error->message); + g_error_free (error); + return; + } + + connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (connection == NULL) { + error_message (app, _("Could not get session bus while applying display configuration"), error->message); + g_error_free (error); + return; + } - message.xclient.type = ClientMessage; - message.xclient.message_type = gnome_randr_atom(); - message.xclient.format = 8; + proxy = dbus_g_proxy_new_for_name (connection, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/XRANDR", + "org.gnome.SettingsDaemon.XRANDR"); + if (!proxy) { + error_message (app, _("Could not get org.gnome.SettingsDaemon.XRANDR"), NULL); + return; -#if 0 - g_debug ("Sending client message"); -#endif + } - XSendEvent (gdk_x11_get_default_xdisplay(), - gdk_x11_get_default_root_xwindow(), - FALSE, - StructureNotifyMask, &message); + if (!dbus_g_proxy_call (proxy, "ApplyConfiguration", &error, G_TYPE_INVALID, G_TYPE_INVALID)) { + error_message (app, _("Could not apply the selected configuration"), error->message); + g_error_free (error); } + + g_object_unref (proxy); + dbus_g_connection_unref (connection); } +#if 0 /* Returns whether the graphics driver doesn't advertise RANDR 1.2 features, and just 1.0 */ static gboolean driver_is_randr_10 (GnomeRRConfig *config) @@ -1683,13 +1737,21 @@ driver_is_randr_10 (GnomeRRConfig *config) return (count_all_outputs (config) == 1 && strcmp (config->outputs[0]->name, "default") == 0); } +#endif static void on_detect_displays (GtkWidget *widget, gpointer data) { App *app = data; + GError *error; - gnome_rr_screen_refresh (app->screen); + error = NULL; + if (!gnome_rr_screen_refresh (app->screen, &error)) { + if (error) { + error_message (app, _("Could not detect displays"), error->message); + g_error_free (error); + } + } } #define SHOW_ICON_KEY "/apps/gnome_settings_daemon/xrandr/show_notification_icon" @@ -1705,6 +1767,162 @@ on_show_icon_toggled (GtkWidget *widget, gpointer data) gtk_toggle_button_get_active (tb), NULL); } +static GnomeOutputInfo * +get_nearest_output (GnomeRRConfig *configuration, int x, int y) +{ + int i; + int nearest_index; + int nearest_dist; + + nearest_index = -1; + nearest_dist = G_MAXINT; + + for (i = 0; configuration->outputs[i] != NULL; i++) + { + GnomeOutputInfo *output; + int dist_x, dist_y; + + output = configuration->outputs[i]; + + if (!(output->connected && output->on)) + continue; + + if (x < output->x) + dist_x = output->x - x; + else if (x >= output->x + output->width) + dist_x = x - (output->x + output->width) + 1; + else + dist_x = 0; + + if (y < output->y) + dist_y = output->y - y; + else if (y >= output->y + output->height) + dist_y = y - (output->y + output->height) + 1; + else + dist_y = 0; + + if (MIN (dist_x, dist_y) < nearest_dist) + { + nearest_dist = MIN (dist_x, dist_y); + nearest_index = i; + } + } + + if (nearest_index != -1) + return configuration->outputs[nearest_index]; + else + return NULL; + +} + +/* Gets the output that contains the largest intersection with the window. + * Logic stolen from gdk_screen_get_monitor_at_window(). + */ +static GnomeOutputInfo * +get_output_for_window (GnomeRRConfig *configuration, GdkWindow *window) +{ + GdkRectangle win_rect; + int i; + int largest_area; + int largest_index; + + gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width, &win_rect.height, NULL); + gdk_window_get_origin (window, &win_rect.x, &win_rect.y); + + largest_area = 0; + largest_index = -1; + + for (i = 0; configuration->outputs[i] != NULL; i++) + { + GnomeOutputInfo *output; + GdkRectangle output_rect, intersection; + + output = configuration->outputs[i]; + + output_rect.x = output->x; + output_rect.y = output->y; + output_rect.width = output->width; + output_rect.height = output->height; + + if (output->connected && gdk_rectangle_intersect (&win_rect, &output_rect, &intersection)) + { + int area; + + area = intersection.width * intersection.height; + if (area > largest_area) + { + largest_area = area; + largest_index = i; + } + } + } + + if (largest_index != -1) + return configuration->outputs[largest_index]; + else + return get_nearest_output (configuration, + win_rect.x + win_rect.width / 2, + win_rect.y + win_rect.height / 2); +} + +/* We select the current output, i.e. select the one being edited, based on + * which output is showing the configuration dialog. + */ +static void +select_current_output_from_dialog_position (App *app) +{ + if (GTK_WIDGET_REALIZED (app->dialog)) + { + GnomeOutputInfo *output; + + output = get_output_for_window (app->current_configuration, app->dialog->window); + + if (output) + app->current_output = output; + } + + rebuild_gui (app); +} + +/* This is a GtkWidget::map-event handler. We wait for the display-properties + * dialog to be mapped, and then we select the output which corresponds to the + * monitor on which the dialog is being shown. + */ +static gboolean +dialog_map_event_cb (GtkWidget *widget, GdkEventAny *event, gpointer data) +{ + App *app = data; + + select_current_output_from_dialog_position (app); + return FALSE; +} + +static void +hide_help_button (App *app) +{ + GtkWidget *action_area; + GList *children; + GList *l; + + action_area = gtk_dialog_get_action_area (GTK_DIALOG (app->dialog)); + children = gtk_container_get_children (GTK_CONTAINER (action_area)); + + for (l = children; l; l = l->next) + { + GtkWidget *child; + int response; + + child = GTK_WIDGET (l->data); + + response = gtk_dialog_get_response_for_widget (GTK_DIALOG (app->dialog), child); + if (response == GTK_RESPONSE_HELP) + { + gtk_widget_hide (child); + return; + } + } +} + static void run_application (App *app) { @@ -1714,6 +1932,7 @@ run_application (App *app) #define GLADE_FILE GLADEDIR "/display-capplet.glade" GladeXML *xml; GtkWidget *align; + GError *error; xml = glade_xml_new (GLADE_FILE, NULL, NULL); if (!xml) @@ -1722,11 +1941,13 @@ run_application (App *app) return; } + error = NULL; app->screen = gnome_rr_screen_new (gdk_screen_get_default (), - on_screen_changed, app); + on_screen_changed, app, &error); if (!app->screen) { - g_error ("Could not get screen info"); + error_message (NULL, _("Could not get screen information"), error->message); + g_error_free (error); g_object_unref (xml); return; } @@ -1734,11 +1955,23 @@ run_application (App *app) app->client = gconf_client_get_default (); app->dialog = glade_xml_get_widget (xml, "dialog"); + g_signal_connect_after (app->dialog, "map-event", + G_CALLBACK (dialog_map_event_cb), app); gtk_window_set_default_icon_name ("gnome-display-properties"); gtk_window_set_icon_name (GTK_WINDOW (app->dialog), "gnome-display-properties"); + app->current_monitor_event_box = glade_xml_get_widget (xml, "current_monitor_event_box"); + app->current_monitor_label = glade_xml_get_widget (xml, "current_monitor_label"); + + app->monitor_on_radio = glade_xml_get_widget (xml, "monitor_on_radio"); + app->monitor_off_radio = glade_xml_get_widget (xml, "monitor_off_radio"); + g_signal_connect (app->monitor_on_radio, "toggled", + G_CALLBACK (monitor_on_off_toggled_cb), app); + g_signal_connect (app->monitor_off_radio, "toggled", + G_CALLBACK (monitor_on_off_toggled_cb), app); + app->resolution_combo = glade_xml_get_widget (xml, "resolution_combo"); g_signal_connect (app->resolution_combo, "changed", G_CALLBACK (on_resolution_changed), app); @@ -1766,7 +1999,6 @@ run_application (App *app) g_signal_connect (app->show_icon_checkbox, "toggled", G_CALLBACK (on_show_icon_toggled), app); app->panel_checkbox = glade_xml_get_widget (xml, "panel_checkbox"); - app->panel_label = glade_xml_get_widget (xml, "panel_label"); make_text_combo (app->resolution_combo, 4); make_text_combo (app->refresh_combo, 3); @@ -1791,11 +2023,11 @@ run_application (App *app) gtk_container_add (GTK_CONTAINER (align), app->area); + /* Until we have help to show, we'll just hide the Help button */ + hide_help_button (app); + on_screen_changed (app->screen, app); - rebuild_gui (app); - gtk_widget_hide (app->panel_checkbox); - gtk_widget_hide (app->panel_label); g_object_unref (xml); restart: