Bug Summary

File:capplets/display/xrandr-capplet.c
Warning:line 1009, column 10
3rd function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name xrandr-capplet.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/capplets/display -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/libxml2 -I /usr/include/cafe-desktop-2.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dconf -I ../../capplets/common -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/libxml2 -I /usr/include/cafe-desktop-2.0 -I /usr/include/startup-notification-1.0 -I /usr/include/dconf -I ../../ -D G_LOG_DOMAIN="display-properties" -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/polkit-1 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/gio-unix-2.0 -D SBINDIR="/usr/sbin" -D CAFELOCALEDIR="/usr/share/locale" -D CAFECC_DATA_DIR="/usr/share/cafe-control-center" -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/capplets/display -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-16-094050-112929-1 -x c xrandr-capplet.c
1/* Monitor Settings. A preference panel for configuring monitors
2 *
3 * Copyright (C) 2007, 2008 Red Hat, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Author: Soren Sandmann <sandmann@redhat.com>
20 */
21
22#include <config.h>
23#include <string.h>
24#include <stdlib.h>
25#include <sys/wait.h>
26
27#include <ctk/ctk.h>
28#include "scrollarea.h"
29#define CAFE_DESKTOP_USE_UNSTABLE_API
30#include <libcafe-desktop/cafe-desktop-utils.h>
31#include <libcafe-desktop/cafe-rr.h>
32#include <libcafe-desktop/cafe-rr-config.h>
33#include <libcafe-desktop/cafe-rr-labeler.h>
34#include <cdk/cdkx.h>
35#include <X11/Xlib.h>
36#include <glib/gi18n.h>
37#include <gio/gio.h>
38
39#include "capplet-util.h"
40
41typedef struct App App;
42typedef struct GrabInfo GrabInfo;
43
44struct App
45{
46 CafeRRScreen *screen;
47 CafeRRConfig *current_configuration;
48 CafeRRLabeler *labeler;
49 CafeRROutputInfo *current_output;
50
51 CtkWidget *dialog;
52 CtkWidget *current_monitor_event_box;
53 CtkWidget *current_monitor_label;
54 CtkWidget *monitor_on_radio;
55 CtkWidget *monitor_off_radio;
56 CtkWidget *resolution_combo;
57 CtkWidget *refresh_combo;
58 CtkWidget *rotation_combo;
59 CtkWidget *panel_checkbox;
60 CtkWidget *clone_checkbox;
61 CtkWidget *show_icon_checkbox;
62 CtkWidget *primary_button;
63
64 /* We store the event timestamp when the Apply button is clicked */
65 CtkWidget *apply_button;
66 guint32 apply_button_clicked_timestamp;
67
68 CtkWidget *area;
69 gboolean ignore_gui_changes;
70 GSettings *settings;
71
72 /* These are used while we are waiting for the ApplyConfiguration method to be executed over D-bus */
73 GDBusConnection *connection;
74 GDBusProxy *proxy;
75
76 enum {
77 APPLYING_VERSION_1,
78 APPLYING_VERSION_2
79 } apply_configuration_state;
80};
81
82/* Response codes for custom buttons in the main dialog */
83enum {
84 RESPONSE_MAKE_DEFAULT = 1
85};
86
87static void rebuild_gui (App *app);
88static void on_clone_changed (CtkWidget *box, gpointer data);
89static void on_rate_changed (CtkComboBox *box, gpointer data);
90static gboolean output_overlaps (CafeRROutputInfo *output, CafeRRConfig *config);
91static void select_current_output_from_dialog_position (App *app);
92static void monitor_on_off_toggled_cb (CtkToggleButton *toggle, gpointer data);
93static void get_geometry (CafeRROutputInfo *output, int *w, int *h);
94static void apply_configuration_returned_cb (GObject *source_object, GAsyncResult *res, gpointer data);
95static gboolean get_clone_size (CafeRRScreen *screen, int *width, int *height);
96static gboolean output_info_supports_mode (App *app, CafeRROutputInfo *info, int width, int height);
97
98static void
99error_message (App *app, const char *primary_text, const char *secondary_text)
100{
101 CtkWidget *dialog;
102
103 dialog = ctk_message_dialog_new ((app && app->dialog) ? CTK_WINDOW (app->dialog)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->dialog)), ((ctk_window_get_type ()))))))
: NULL((void*)0),
104 CTK_DIALOG_MODAL | CTK_DIALOG_DESTROY_WITH_PARENT,
105 CTK_MESSAGE_ERROR,
106 CTK_BUTTONS_CLOSE,
107 "%s", primary_text);
108
109 if (secondary_text)
110 ctk_message_dialog_format_secondary_text (CTK_MESSAGE_DIALOG (dialog)((((CtkMessageDialog*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((dialog)), ((ctk_message_dialog_get_type ())
)))))
, "%s", secondary_text);
111
112 ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
);
113 ctk_widget_destroy (dialog);
114}
115
116static gboolean
117do_free (gpointer data)
118{
119 g_free (data);
120 return FALSE(0);
121}
122
123static gchar *
124idle_free (gchar *s)
125{
126 g_idle_add (do_free, s);
127
128 return s;
129}
130
131static void
132on_screen_changed (CafeRRScreen *scr,
133 gpointer data)
134{
135 CafeRRConfig *current;
136 App *app = data;
137
138 current = cafe_rr_config_new_current (app->screen, NULL((void*)0));
139
140 if (app->current_configuration)
141 g_object_unref (app->current_configuration);
142
143 app->current_configuration = current;
144 app->current_output = NULL((void*)0);
145
146 if (app->labeler) {
147 cafe_rr_labeler_hide (app->labeler);
148 g_object_unref (app->labeler);
149 }
150
151 app->labeler = cafe_rr_labeler_new (app->current_configuration);
152
153 select_current_output_from_dialog_position (app);
154}
155
156static void
157on_viewport_changed (FooScrollArea *scroll_area,
158 CdkRectangle *old_viewport,
159 CdkRectangle *new_viewport)
160{
161 foo_scroll_area_set_size (scroll_area,
162 new_viewport->width,
163 new_viewport->height);
164
165 foo_scroll_area_invalidate (scroll_area);
166}
167
168static void
169layout_set_font (PangoLayout *layout, const char *font)
170{
171 PangoFontDescription *desc =
172 pango_font_description_from_string (font);
173
174 if (desc)
175 {
176 pango_layout_set_font_description (layout, desc);
177
178 pango_font_description_free (desc);
179 }
180}
181
182static void
183clear_combo (CtkWidget *widget)
184{
185 CtkComboBox *box = CTK_COMBO_BOX (widget)((((CtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_combo_box_get_type ()))))))
;
186 CtkTreeModel *model = ctk_combo_box_get_model (box);
187 CtkListStore *store = CTK_LIST_STORE (model)((((CtkListStore*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((model)), ((ctk_list_store_get_type ()))))))
;
188
189 ctk_list_store_clear (store);
190}
191
192typedef struct
193{
194 const char *text;
195 gboolean found;
196 CtkTreeIter iter;
197} ForeachInfo;
198
199static gboolean
200foreach (CtkTreeModel *model,
201 CtkTreePath *path,
202 CtkTreeIter *iter,
203 gpointer data)
204{
205 ForeachInfo *info = data;
206 char *text = NULL((void*)0);
207
208 ctk_tree_model_get (model, iter, 0, &text, -1);
209
210 g_assert (text != NULL)do { if (text != ((void*)0)) ; else g_assertion_message_expr (
"display-properties", "xrandr-capplet.c", 210, ((const char*)
(__func__)), "text != NULL"); } while (0)
;
211
212 if (strcmp (info->text, text) == 0)
213 {
214 info->found = TRUE(!(0));
215 info->iter = *iter;
216 return TRUE(!(0));
217 }
218
219 return FALSE(0);
220}
221
222static void
223add_key (CtkWidget *widget,
224 const char *text,
225 int width, int height, int rate,
226 CafeRRRotation rotation)
227{
228 ForeachInfo info;
229 CtkComboBox *box = CTK_COMBO_BOX (widget)((((CtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_combo_box_get_type ()))))))
;
230 CtkTreeModel *model = ctk_combo_box_get_model (box);
231 CtkListStore *store = CTK_LIST_STORE (model)((((CtkListStore*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((model)), ((ctk_list_store_get_type ()))))))
;
232
233 info.text = text;
234 info.found = FALSE(0);
235
236 ctk_tree_model_foreach (model, foreach, &info);
237
238 if (!info.found)
239 {
240 CtkTreeIter iter;
241 ctk_list_store_insert_with_values (store, &iter, -1,
242 0, text,
243 1, width,
244 2, height,
245 3, rate,
246 4, width * height,
247 5, rotation,
248 -1);
249
250 }
251}
252
253static gboolean
254combo_select (CtkWidget *widget, const char *text)
255{
256 CtkComboBox *box = CTK_COMBO_BOX (widget)((((CtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_combo_box_get_type ()))))))
;
257 CtkTreeModel *model = ctk_combo_box_get_model (box);
258 ForeachInfo info;
259
260 info.text = text;
261 info.found = FALSE(0);
262
263 ctk_tree_model_foreach (model, foreach, &info);
264
265 if (!info.found)
266 return FALSE(0);
267
268 ctk_combo_box_set_active_iter (box, &info.iter);
269 return TRUE(!(0));
270}
271
272static CafeRRMode **
273get_current_modes (App *app)
274{
275 CafeRROutput *output;
276
277 if (cafe_rr_config_get_clone (app->current_configuration))
278 {
279 return cafe_rr_screen_list_clone_modes (app->screen);
280 }
281 else
282 {
283 if (!app->current_output)
284 return NULL((void*)0);
285
286 output = cafe_rr_screen_get_output_by_name (app->screen,
287 cafe_rr_output_info_get_name (app->current_output));
288
289 if (!output)
290 return NULL((void*)0);
291
292 return cafe_rr_output_list_modes (output);
293 }
294}
295
296static void
297rebuild_rotation_combo (App *app)
298{
299 typedef struct
300 {
301 CafeRRRotation rotation;
302 const char * name;
303 } RotationInfo;
304 static const RotationInfo rotations[] = {
305 { CAFE_RR_ROTATION_0, N_("Normal")("Normal") },
306 { CAFE_RR_ROTATION_90, N_("Left")("Left") },
307 { CAFE_RR_ROTATION_270, N_("Right")("Right") },
308 { CAFE_RR_ROTATION_180, N_("Upside Down")("Upside Down") },
309 };
310 const char *selection;
311 CafeRRRotation current;
312 int i;
313
314 clear_combo (app->rotation_combo);
315
316 ctk_widget_set_sensitive (app->rotation_combo,
317 app->current_output && cafe_rr_output_info_is_active (app->current_output));
318
319 if (!app->current_output)
320 return;
321
322 current = cafe_rr_output_info_get_rotation (app->current_output);
323
324 selection = NULL((void*)0);
325 for (i = 0; i < G_N_ELEMENTS (rotations)(sizeof (rotations) / sizeof ((rotations)[0])); ++i)
326 {
327 const RotationInfo *info = &(rotations[i]);
328
329 cafe_rr_output_info_set_rotation (app->current_output, info->rotation);
330
331 /* NULL-GError --- FIXME: we should say why this rotation is not available! */
332 if (cafe_rr_config_applicable (app->current_configuration, app->screen, NULL((void*)0)))
333 {
334 add_key (app->rotation_combo, _(info->name)gettext (info->name), 0, 0, 0, info->rotation);
335
336 if (info->rotation == current)
337 selection = _(info->name)gettext (info->name);
338 }
339 }
340
341 cafe_rr_output_info_set_rotation (app->current_output, current);
342
343 if (!(selection && combo_select (app->rotation_combo, selection)))
344 combo_select (app->rotation_combo, _("Normal")gettext ("Normal"));
345}
346
347static char *
348make_rate_string (int hz)
349{
350 return g_strdup_printf (_("%d Hz")gettext ("%d Hz"), hz);
351}
352
353static void
354rebuild_rate_combo (App *app)
355{
356 CafeRRMode **modes;
357 int best;
358 int i;
359
360 clear_combo (app->refresh_combo);
361
362 ctk_widget_set_sensitive (
363 app->refresh_combo, app->current_output && cafe_rr_output_info_is_active (app->current_output));
364
365 if (!app->current_output
366 || !(modes = get_current_modes (app)))
367 return;
368
369 best = -1;
370 for (i = 0; modes[i] != NULL((void*)0); ++i)
371 {
372 CafeRRMode *mode = modes[i];
373 int width, height, rate;
374 int output_width, output_height;
375
376 cafe_rr_output_info_get_geometry (app->current_output, NULL((void*)0), NULL((void*)0), &output_width, &output_height);
377
378 width = cafe_rr_mode_get_width (mode);
379 height = cafe_rr_mode_get_height (mode);
380 rate = cafe_rr_mode_get_freq (mode);
381
382 if (width == output_width &&
383 height == output_height)
384 {
385 add_key (app->refresh_combo,
386 idle_free (make_rate_string (rate)),
387 0, 0, rate, -1);
388
389 if (rate > best)
390 best = rate;
391 }
392 }
393
394 if (!combo_select (app->refresh_combo, idle_free (make_rate_string (cafe_rr_output_info_get_refresh_rate (app->current_output)))))
395 combo_select (app->refresh_combo, idle_free (make_rate_string (best)));
396}
397
398static int
399count_active_outputs (App *app)
400{
401 int i, count = 0;
402 CafeRROutputInfo **outputs = cafe_rr_config_get_outputs (app->current_configuration);
403
404 for (i = 0; outputs[i] != NULL((void*)0); ++i)
405 {
406 if (cafe_rr_output_info_is_active (outputs[i]))
407 count++;
408 }
409
410 return count;
411}
412
413/* Computes whether "Mirror Screens" (clone mode) is supported based on these criteria:
414 *
415 * 1. There is an available size for cloning.
416 *
417 * 2. There are 2 or more connected outputs that support that size.
418 */
419static gboolean
420mirror_screens_is_supported (App *app)
421{
422 int clone_width, clone_height;
423 gboolean have_clone_size;
424 gboolean mirror_is_supported;
425
426 mirror_is_supported = FALSE(0);
427
428 have_clone_size = get_clone_size (app->screen, &clone_width, &clone_height);
429
430 if (have_clone_size) {
431 int i;
432 int num_outputs_with_clone_size;
433 CafeRROutputInfo **outputs = cafe_rr_config_get_outputs (app->current_configuration);
434
435 num_outputs_with_clone_size = 0;
436
437 for (i = 0; outputs[i] != NULL((void*)0); i++)
438 {
439 /* We count the connected outputs that support the clone size. It
440 * doesn't matter if those outputs aren't actually On currently; we
441 * will turn them on in on_clone_changed().
442 */
443 if (cafe_rr_output_info_is_connected (outputs[i]) && output_info_supports_mode (app, outputs[i], clone_width, clone_height))
444 num_outputs_with_clone_size++;
445 }
446
447 if (num_outputs_with_clone_size >= 2)
448 mirror_is_supported = TRUE(!(0));
449 }
450
451 return mirror_is_supported;
452}
453
454static void
455rebuild_mirror_screens (App *app)
456{
457 gboolean mirror_is_active;
458 gboolean mirror_is_supported;
459
460 g_signal_handlers_block_by_func (app->clone_checkbox, G_CALLBACK (on_clone_changed), app)g_signal_handlers_block_matched ((app->clone_checkbox), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (((GCallback) (on_clone_changed))), (app))
;
461
462 mirror_is_active = app->current_configuration && cafe_rr_config_get_clone (app->current_configuration);
463
464 /* If mirror_is_active, then it *must* be possible to turn mirroring off */
465 mirror_is_supported = mirror_is_active || mirror_screens_is_supported (app);
466
467 ctk_toggle_button_set_active (CTK_TOGGLE_BUTTON (app->clone_checkbox)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->clone_checkbox)), ((ctk_toggle_button_get_type (
)))))))
, mirror_is_active);
468 ctk_widget_set_sensitive (app->clone_checkbox, mirror_is_supported);
469
470 g_signal_handlers_unblock_by_func (app->clone_checkbox, G_CALLBACK (on_clone_changed), app)g_signal_handlers_unblock_matched ((app->clone_checkbox), (
GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA)
, 0, 0, ((void*)0), (((GCallback) (on_clone_changed))), (app)
)
;
471}
472
473static void
474rebuild_current_monitor_label (App *app)
475{
476 char *str, *tmp;
477 CdkRGBA color;
478 gboolean use_color;
479
480 if (app->current_output)
481 {
482 if (cafe_rr_config_get_clone (app->current_configuration))
483 tmp = g_strdup (_("Mirror Screens"))g_strdup_inline (gettext ("Mirror Screens"));
484 else
485 tmp = g_strdup_printf (_("Monitor: %s")gettext ("Monitor: %s"), cafe_rr_output_info_get_display_name (app->current_output));
486
487 str = g_strdup_printf ("<b>%s</b>", tmp);
488 cafe_rr_labeler_get_rgba_for_output (app->labeler, app->current_output, &color);
489 use_color = TRUE(!(0));
490 g_free (tmp);
491 }
492 else
493 {
494 str = g_strdup_printf ("<b>%s</b>", _("Monitor")gettext ("Monitor"));
495 use_color = FALSE(0);
496 }
497
498 ctk_label_set_markup (CTK_LABEL (app->current_monitor_label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->current_monitor_label)), ((ctk_label_get_type ()
))))))
, str);
499 g_free (str);
500
501 if (use_color)
502 {
503 CdkRGBA black = { 0, 0, 0, 1.0 };
504
505 ctk_widget_override_background_color (app->current_monitor_event_box, ctk_widget_get_state_flags (app->current_monitor_event_box), &color);
506
507 /* Make the label explicitly black. We don't want it to follow the
508 * theme's colors, since the label is always shown against a light
509 * pastel background. See bgo#556050
510 */
511 ctk_widget_override_color (app->current_monitor_label, ctk_widget_get_state_flags (app->current_monitor_label), &black);
512 }
513
514 ctk_event_box_set_visible_window (CTK_EVENT_BOX (app->current_monitor_event_box)((((CtkEventBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->current_monitor_event_box)), ((ctk_event_box_get_type
()))))))
, use_color);
515}
516
517static void
518rebuild_on_off_radios (App *app)
519{
520 gboolean sensitive;
521 gboolean on_active;
522 gboolean off_active;
523
524 g_signal_handlers_block_by_func (app->monitor_on_radio, G_CALLBACK (monitor_on_off_toggled_cb), app)g_signal_handlers_block_matched ((app->monitor_on_radio), (
GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA)
, 0, 0, ((void*)0), (((GCallback) (monitor_on_off_toggled_cb)
)), (app))
;
525 g_signal_handlers_block_by_func (app->monitor_off_radio, G_CALLBACK (monitor_on_off_toggled_cb), app)g_signal_handlers_block_matched ((app->monitor_off_radio),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (monitor_on_off_toggled_cb
))), (app))
;
526
527 sensitive = FALSE(0);
528 on_active = FALSE(0);
529 off_active = FALSE(0);
530
531 if (!cafe_rr_config_get_clone (app->current_configuration) && app->current_output)
532 {
533 if (count_active_outputs (app) > 1 || !cafe_rr_output_info_is_active (app->current_output))
534 sensitive = TRUE(!(0));
535 else
536 sensitive = FALSE(0);
537
538 on_active = cafe_rr_output_info_is_active (app->current_output);
539 off_active = !on_active;
540 }
541
542 ctk_widget_set_sensitive (app->monitor_on_radio, sensitive);
543 ctk_widget_set_sensitive (app->monitor_off_radio, sensitive);
544
545 ctk_toggle_button_set_active (CTK_TOGGLE_BUTTON (app->monitor_on_radio)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->monitor_on_radio)), ((ctk_toggle_button_get_type
()))))))
, on_active);
546 ctk_toggle_button_set_active (CTK_TOGGLE_BUTTON (app->monitor_off_radio)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->monitor_off_radio)), ((ctk_toggle_button_get_type
()))))))
, off_active);
547
548 g_signal_handlers_unblock_by_func (app->monitor_on_radio, G_CALLBACK (monitor_on_off_toggled_cb), app)g_signal_handlers_unblock_matched ((app->monitor_on_radio)
, (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (monitor_on_off_toggled_cb
))), (app))
;
549 g_signal_handlers_unblock_by_func (app->monitor_off_radio, G_CALLBACK (monitor_on_off_toggled_cb), app)g_signal_handlers_unblock_matched ((app->monitor_off_radio
), (GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (monitor_on_off_toggled_cb
))), (app))
;
550}
551
552static char *
553make_resolution_string (int width, int height)
554{
555 return g_strdup_printf (_("%d x %d")gettext ("%d x %d"), width, height);
556}
557
558static void
559find_best_mode (CafeRRMode **modes, int *out_width, int *out_height)
560{
561 int i;
562
563 *out_width = 0;
564 *out_height = 0;
565
566 for (i = 0; modes[i] != NULL((void*)0); i++)
567 {
568 int w, h;
569
570 w = cafe_rr_mode_get_width (modes[i]);
571 h = cafe_rr_mode_get_height (modes[i]);
572
573 if (w * h > *out_width * *out_height)
574 {
575 *out_width = w;
576 *out_height = h;
577 }
578 }
579}
580
581static void
582rebuild_resolution_combo (App *app)
583{
584 int i;
585 CafeRRMode **modes;
586 const char *current;
587 int output_width, output_height;
588
589 clear_combo (app->resolution_combo);
590
591 if (!(modes = get_current_modes (app))
592 || !app->current_output
593 || !cafe_rr_output_info_is_active (app->current_output))
594 {
595 ctk_widget_set_sensitive (app->resolution_combo, FALSE(0));
596 return;
597 }
598
599 g_assert (app->current_output != NULL)do { if (app->current_output != ((void*)0)) ; else g_assertion_message_expr
("display-properties", "xrandr-capplet.c", 599, ((const char
*) (__func__)), "app->current_output != NULL"); } while (0
)
;
600
601 cafe_rr_output_info_get_geometry (app->current_output, NULL((void*)0), NULL((void*)0), &output_width, &output_height);
602 g_assert (output_width != 0 && output_height != 0)do { if (output_width != 0 && output_height != 0) ; else
g_assertion_message_expr ("display-properties", "xrandr-capplet.c"
, 602, ((const char*) (__func__)), "output_width != 0 && output_height != 0"
); } while (0)
;
603
604 ctk_widget_set_sensitive (app->resolution_combo, TRUE(!(0)));
605
606 for (i = 0; modes[i] != NULL((void*)0); ++i)
607 {
608 int width, height;
609
610 width = cafe_rr_mode_get_width (modes[i]);
611 height = cafe_rr_mode_get_height (modes[i]);
612
613 add_key (app->resolution_combo,
614 idle_free (make_resolution_string (width, height)),
615 width, height, 0, -1);
616 }
617
618 current = idle_free (make_resolution_string (output_width, output_height));
619
620 if (!combo_select (app->resolution_combo, current))
621 {
622 int best_w, best_h;
623
624 find_best_mode (modes, &best_w, &best_h);
625 combo_select (app->resolution_combo, idle_free (make_resolution_string (best_w, best_h)));
626 }
627}
628
629static void
630rebuild_gui (App *app)
631{
632 gboolean sensitive;
633
634 /* We would break spectacularly if we recursed, so
635 * just assert if that happens
636 */
637 g_assert (app->ignore_gui_changes == FALSE)do { if (app->ignore_gui_changes == (0)) ; else g_assertion_message_expr
("display-properties", "xrandr-capplet.c", 637, ((const char
*) (__func__)), "app->ignore_gui_changes == FALSE"); } while
(0)
;
638
639 app->ignore_gui_changes = TRUE(!(0));
640
641 sensitive = app->current_output ? TRUE(!(0)) : FALSE(0);
642
643#if 0
644 g_debug ("rebuild gui, is on: %d", cafe_rr_output_info_is_active (app->current_output));
645#endif
646
647 rebuild_mirror_screens (app);
648 rebuild_current_monitor_label (app);
649 rebuild_on_off_radios (app);
650 rebuild_resolution_combo (app);
651 rebuild_rate_combo (app);
652 rebuild_rotation_combo (app);
653
654#if 0
655 g_debug ("sensitive: %d, on: %d", sensitive, cafe_rr_output_info_is_active (app->current_output));
656#endif
657 ctk_widget_set_sensitive (app->panel_checkbox, sensitive);
658
659 ctk_widget_set_sensitive (app->primary_button, app->current_output && !cafe_rr_output_info_get_primary(app->current_output));
660
661 app->ignore_gui_changes = FALSE(0);
662}
663
664static gboolean
665get_mode (CtkWidget *widget, int *width, int *height, int *freq, CafeRRRotation *rot)
666{
667 CtkTreeIter iter;
668 CtkTreeModel *model;
669 CtkComboBox *box = CTK_COMBO_BOX (widget)((((CtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_combo_box_get_type ()))))))
;
670 int dummy;
671
672 if (!ctk_combo_box_get_active_iter (box, &iter))
673 return FALSE(0);
674
675 if (!width)
676 width = &dummy;
677
678 if (!height)
679 height = &dummy;
680
681 if (!freq)
682 freq = &dummy;
683
684 if (!rot)
685 rot = (CafeRRRotation *)&dummy;
686
687 model = ctk_combo_box_get_model (box);
688 ctk_tree_model_get (model, &iter,
689 1, width,
690 2, height,
691 3, freq,
692 5, rot,
693 -1);
694
695 return TRUE(!(0));
696
697}
698
699static void
700on_rotation_changed (CtkComboBox *box, gpointer data)
701{
702 App *app = data;
703 CafeRRRotation rotation;
704
705 if (!app->current_output)
706 return;
707
708 if (get_mode (app->rotation_combo, NULL((void*)0), NULL((void*)0), NULL((void*)0), &rotation))
709 cafe_rr_output_info_set_rotation (app->current_output, rotation);
710
711 foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)((((FooScrollArea*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->area)), ((foo_scroll_area_get_type ()))))))
);
712}
713
714static void
715on_rate_changed (CtkComboBox *box, gpointer data)
716{
717 App *app = data;
718 int rate;
719
720 if (!app->current_output)
721 return;
722
723 if (get_mode (app->refresh_combo, NULL((void*)0), NULL((void*)0), &rate, NULL((void*)0)))
724 cafe_rr_output_info_set_refresh_rate (app->current_output, rate);
725
726 foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)((((FooScrollArea*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->area)), ((foo_scroll_area_get_type ()))))))
);
727}
728
729static void
730select_resolution_for_current_output (App *app)
731{
732 CafeRRMode **modes;
733 int width, height;
734 int x, y;
735 cafe_rr_output_info_get_geometry (app->current_output, &x, &y, NULL((void*)0), NULL((void*)0));
736
737 width = cafe_rr_output_info_get_preferred_width (app->current_output);
738 height = cafe_rr_output_info_get_preferred_height (app->current_output);
739
740 if (width != 0 && height != 0)
741 {
742 cafe_rr_output_info_set_geometry (app->current_output, x, y, width, height);
743 return;
744 }
745
746 modes = get_current_modes (app);
747 if (!modes)
748 return;
749
750 find_best_mode (modes, &width, &height);
751
752 cafe_rr_output_info_set_geometry (app->current_output, x, y, width, height);
753}
754
755static void
756monitor_on_off_toggled_cb (CtkToggleButton *toggle, gpointer data)
757{
758 App *app = data;
759 gboolean is_on;
760
761 if (!app->current_output)
762 return;
763
764 if (!ctk_toggle_button_get_active (toggle))
765 return;
766
767 if (CTK_WIDGET (toggle)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toggle)), ((ctk_widget_get_type ()))))))
== app->monitor_on_radio)
768 is_on = TRUE(!(0));
769 else if (CTK_WIDGET (toggle)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toggle)), ((ctk_widget_get_type ()))))))
== app->monitor_off_radio)
770 is_on = FALSE(0);
771 else
772 {
773 g_assert_not_reached ()do { g_assertion_message_expr ("display-properties", "xrandr-capplet.c"
, 773, ((const char*) (__func__)), ((void*)0)); } while (0)
;
774 return;
775 }
776
777 cafe_rr_output_info_set_active (app->current_output, is_on);
778
779 if (is_on)
780 select_resolution_for_current_output (app); /* The refresh rate will be picked in rebuild_rate_combo() */
781
782 rebuild_gui (app);
783 foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)((((FooScrollArea*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->area)), ((foo_scroll_area_get_type ()))))))
);
784}
785
786static void
787realign_outputs_after_resolution_change (App *app, CafeRROutputInfo *output_that_changed, int old_width, int old_height)
788{
789 /* We find the outputs that were below or to the right of the output that
790 * changed, and realign them; we also do that for outputs that shared the
791 * right/bottom edges with the output that changed. The outputs that are
792 * above or to the left of that output don't need to change.
793 */
794
795 int i;
796 int old_right_edge, old_bottom_edge;
797 int dx, dy;
798 int x, y, width, height;
799 CafeRROutputInfo **outputs;
800
801 g_assert (app->current_configuration != NULL)do { if (app->current_configuration != ((void*)0)) ; else g_assertion_message_expr
("display-properties", "xrandr-capplet.c", 801, ((const char
*) (__func__)), "app->current_configuration != NULL"); } while
(0)
;
802
803 cafe_rr_output_info_get_geometry (output_that_changed, &x, &y, &width, &height);
804 if (width == old_width && height == old_height)
805 return;
806
807 old_right_edge = x + old_width;
808 old_bottom_edge = y + old_height;
809
810 dx = width - old_width;
811 dy = height - old_height;
812
813 outputs = cafe_rr_config_get_outputs (app->current_configuration);
814
815 for (i = 0; outputs[i] != NULL((void*)0); i++)
816 {
817 int output_x, output_y;
818 int output_width, output_height;
819
820 if (outputs[i] == output_that_changed || cafe_rr_output_info_is_connected (outputs[i]))
821 continue;
822
823 cafe_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height);
824
825 if (output_x >= old_right_edge)
826 output_x += dx;
827 else if (output_x + output_width == old_right_edge)
828 output_x = x + width - output_width;
829
830
831 if (output_y >= old_bottom_edge)
832 output_y += dy;
833 else if (output_y + output_height == old_bottom_edge)
834 output_y = y + height - output_height;
835
836 cafe_rr_output_info_set_geometry (outputs[i], output_x, output_y, output_width, output_height);
837 }
838}
839
840static void
841on_resolution_changed (CtkComboBox *box, gpointer data)
842{
843 App *app = data;
844 int old_width, old_height;
845 int x, y;
846 int width;
847 int height;
848
849 if (!app->current_output)
850 return;
851
852 cafe_rr_output_info_get_geometry (app->current_output, &x, &y, &old_width, &old_height);
853
854 if (get_mode (app->resolution_combo, &width, &height, NULL((void*)0), NULL((void*)0)))
855 {
856 cafe_rr_output_info_set_geometry (app->current_output, x, y, width, height);
857
858 if (width == 0 || height == 0)
859 cafe_rr_output_info_set_active (app->current_output, FALSE(0));
860 else
861 cafe_rr_output_info_set_active (app->current_output, TRUE(!(0)));
862 }
863
864 realign_outputs_after_resolution_change (app, app->current_output, old_width, old_height);
865
866 rebuild_rate_combo (app);
867 rebuild_rotation_combo (app);
868
869 foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)((((FooScrollArea*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->area)), ((foo_scroll_area_get_type ()))))))
);
870}
871
872static void
873lay_out_outputs_horizontally (App *app)
874{
875 int i;
876 int x;
877 CafeRROutputInfo **outputs;
878
879 /* Lay out all the monitors horizontally when "mirror screens" is turned
880 * off, to avoid having all of them overlapped initially. We put the
881 * outputs turned off on the right-hand side.
882 */
883
884 x = 0;
885
886 /* First pass, all "on" outputs */
887 outputs = cafe_rr_config_get_outputs (app->current_configuration);
888
889 for (i = 0; outputs[i]; ++i)
890 {
891 int width, height;
892 if (cafe_rr_output_info_is_connected (outputs[i]) &&cafe_rr_output_info_is_active (outputs[i]))
893 {
894 cafe_rr_output_info_get_geometry (outputs[i], NULL((void*)0), NULL((void*)0), &width, &height);
895 cafe_rr_output_info_set_geometry (outputs[i], x, 0, width, height);
896 x += width;
897 }
898 }
899
900 /* Second pass, all the black screens */
901
902 for (i = 0; outputs[i]; ++i)
903 {
904 int width, height;
905 if (!(cafe_rr_output_info_is_connected (outputs[i]) && cafe_rr_output_info_is_active (outputs[i])))
906 {
907 cafe_rr_output_info_get_geometry (outputs[i], NULL((void*)0), NULL((void*)0), &width, &height);
908 cafe_rr_output_info_set_geometry (outputs[i], x, 0, width, height);
909 x += width;
910 }
911 }
912
913}
914
915/* FIXME: this function is copied from cafe-settings-daemon/plugins/xrandr/gsd-xrandr-manager.c.
916 * Do we need to put this function in cafe-desktop for public use?
917 */
918static gboolean
919get_clone_size (CafeRRScreen *screen, int *width, int *height)
920{
921 CafeRRMode **modes = cafe_rr_screen_list_clone_modes (screen);
922 int best_w, best_h;
923 int i;
924
925 best_w = 0;
926 best_h = 0;
927
928 for (i = 0; modes[i] != NULL((void*)0); ++i) {
8
Assuming the condition is false
929 CafeRRMode *mode = modes[i];
930 int w, h;
931
932 w = cafe_rr_mode_get_width (mode);
933 h = cafe_rr_mode_get_height (mode);
934
935 if (w * h > best_w * best_h) {
936 best_w = w;
937 best_h = h;
938 }
939 }
940
941 if (best_w
8.1
'best_w' is <= 0
> 0 && best_h > 0) {
942 if (width)
943 *width = best_w;
944 if (height)
945 *height = best_h;
946
947 return TRUE(!(0));
948 }
949
950 return FALSE(0);
9
Returning without writing to '*width'
951}
952
953static gboolean
954output_info_supports_mode (App *app, CafeRROutputInfo *info, int width, int height)
955{
956 CafeRROutput *output;
957 CafeRRMode **modes;
958 int i;
959
960 if (!cafe_rr_output_info_is_connected (info))
961 return FALSE(0);
962
963 output = cafe_rr_screen_get_output_by_name (app->screen, cafe_rr_output_info_get_name (info));
964 if (!output)
965 return FALSE(0);
966
967 modes = cafe_rr_output_list_modes (output);
968
969 for (i = 0; modes[i]; i++) {
970 if (cafe_rr_mode_get_width (modes[i]) == width
971 && cafe_rr_mode_get_height (modes[i]) == height)
972 return TRUE(!(0));
973 }
974
975 return FALSE(0);
976}
977
978static void
979on_clone_changed (CtkWidget *box, gpointer data)
980{
981 App *app = data;
982
983 cafe_rr_config_set_clone (app->current_configuration, ctk_toggle_button_get_active (CTK_TOGGLE_BUTTON (app->clone_checkbox)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->clone_checkbox)), ((ctk_toggle_button_get_type (
)))))))
));
984
985 if (cafe_rr_config_get_clone (app->current_configuration))
1
Assuming the condition is true
2
Taking true branch
986 {
987 int i;
988 int width, height;
3
'width' declared without an initial value
989 CafeRROutputInfo **outputs = cafe_rr_config_get_outputs (app->current_configuration);
990
991 for (i = 0; outputs[i]; ++i)
4
Loop condition is true. Entering loop body
992 {
993 if (cafe_rr_output_info_is_connected(outputs[i]))
5
Assuming the condition is true
6
Taking true branch
994 {
995 app->current_output = outputs[i];
996 break;
997 }
998 }
999
1000 /* Turn on all the connected screens that support the best clone mode.
1001 * The user may hit "Mirror Screens", but he shouldn't have to turn on
1002 * all the required outputs as well.
1003 */
1004
1005 get_clone_size (app->screen, &width, &height);
7
Calling 'get_clone_size'
10
Returning from 'get_clone_size'
1006
1007 for (i = 0; outputs[i]; i++) {
11
Loop condition is true. Entering loop body
1008 int x, y;
1009 if (output_info_supports_mode (app, outputs[i], width, height)) {
12
3rd function call argument is an uninitialized value
1010 cafe_rr_output_info_set_active (outputs[i], TRUE(!(0)));
1011 cafe_rr_output_info_get_geometry (outputs[i], &x, &y, NULL((void*)0), NULL((void*)0));
1012 cafe_rr_output_info_set_geometry (outputs[i], x, y, width, height);
1013 }
1014 }
1015 }
1016 else
1017 {
1018 if (output_overlaps (app->current_output, app->current_configuration))
1019 lay_out_outputs_horizontally (app);
1020 }
1021
1022 rebuild_gui (app);
1023}
1024
1025static void
1026get_geometry (CafeRROutputInfo *output, int *w, int *h)
1027{
1028 CafeRRRotation rotation;
1029
1030 if (cafe_rr_output_info_is_active (output))
1031 {
1032 cafe_rr_output_info_get_geometry (output, NULL((void*)0), NULL((void*)0), w, h);
1033 }
1034 else
1035 {
1036 *h = cafe_rr_output_info_get_preferred_height (output);
1037 *w = cafe_rr_output_info_get_preferred_width (output);
1038 }
1039 rotation = cafe_rr_output_info_get_rotation (output);
1040 if ((rotation & CAFE_RR_ROTATION_90) || (rotation & CAFE_RR_ROTATION_270))
1041 {
1042 int tmp;
1043 tmp = *h;
1044 *h = *w;
1045 *w = tmp;
1046 }
1047}
1048
1049#define SPACE15 15
1050#define MARGIN15 15
1051
1052static GList *
1053list_connected_outputs (App *app, int *total_w, int *total_h)
1054{
1055 int i, dummy;
1056 GList *result = NULL((void*)0);
1057 CafeRROutputInfo **outputs;
1058
1059 if (!total_w)
1060 total_w = &dummy;
1061 if (!total_h)
1062 total_h = &dummy;
1063
1064 *total_w = 0;
1065 *total_h = 0;
1066
1067 outputs = cafe_rr_config_get_outputs(app->current_configuration);
1068 for (i = 0; outputs[i] != NULL((void*)0); ++i)
1069 {
1070 if (cafe_rr_output_info_is_connected (outputs[i]))
1071 {
1072 int w, h;
1073
1074 result = g_list_prepend (result, outputs[i]);
1075
1076 get_geometry (outputs[i], &w, &h);
1077
1078 *total_w += w;
1079 *total_h += h;
1080 }
1081 }
1082
1083 return g_list_reverse (result);
1084}
1085
1086static int
1087get_n_connected (App *app)
1088{
1089 GList *connected_outputs = list_connected_outputs (app, NULL((void*)0), NULL((void*)0));
1090 int n = g_list_length (connected_outputs);
1091
1092 g_list_free (connected_outputs);
1093
1094 return n;
1095}
1096
1097static double
1098compute_scale (App *app)
1099{
1100 int available_w, available_h;
1101 int total_w, total_h;
1102 int n_monitors;
1103 CdkRectangle viewport;
1104 GList *connected_outputs;
1105
1106 foo_scroll_area_get_viewport (FOO_SCROLL_AREA (app->area)((((FooScrollArea*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->area)), ((foo_scroll_area_get_type ()))))))
, &viewport);
1107
1108 connected_outputs = list_connected_outputs (app, &total_w, &total_h);
1109
1110 n_monitors = g_list_length (connected_outputs);
1111
1112 g_list_free (connected_outputs);
1113
1114 available_w = viewport.width - 2 * MARGIN15 - (n_monitors - 1) * SPACE15;
1115 available_h = viewport.height - 2 * MARGIN15 - (n_monitors - 1) * SPACE15;
1116
1117 return MIN ((double)available_w / total_w, (double)available_h / total_h)((((double)available_w / total_w) < ((double)available_h /
total_h)) ? ((double)available_w / total_w) : ((double)available_h
/ total_h))
;
1118}
1119
1120typedef struct Edge
1121{
1122 CafeRROutputInfo *output;
1123 int x1, y1;
1124 int x2, y2;
1125} Edge;
1126
1127typedef struct Snap
1128{
1129 Edge *snapper; /* Edge that should be snapped */
1130 Edge *snappee;
1131 int dy, dx;
1132} Snap;
1133
1134static void
1135add_edge (CafeRROutputInfo *output, int x1, int y1, int x2, int y2, GArray *edges)
1136{
1137 Edge e;
1138
1139 e.x1 = x1;
1140 e.x2 = x2;
1141 e.y1 = y1;
1142 e.y2 = y2;
1143 e.output = output;
1144
1145 g_array_append_val (edges, e)g_array_append_vals (edges, &(e), 1);
1146}
1147
1148static void
1149list_edges_for_output (CafeRROutputInfo *output, GArray *edges)
1150{
1151 int x, y, w, h;
1152
1153 cafe_rr_output_info_get_geometry (output, &x, &y, &w, &h);
1154 get_geometry(output, &w, &h); // accounts for rotation
1155
1156 /* Top, Bottom, Left, Right */
1157 add_edge (output, x, y, x + w, y, edges);
1158 add_edge (output, x, y + h, x + w, y + h, edges);
1159 add_edge (output, x, y, x, y + h, edges);
1160 add_edge (output, x + w, y, x + w, y + h, edges);
1161}
1162
1163static void
1164list_edges (CafeRRConfig *config, GArray *edges)
1165{
1166 int i;
1167 CafeRROutputInfo **outputs = cafe_rr_config_get_outputs (config);
1168
1169 for (i = 0; outputs[i]; ++i)
1170 {
1171 if (cafe_rr_output_info_is_connected (outputs[i]))
1172 list_edges_for_output (outputs[i], edges);
1173 }
1174}
1175
1176static gboolean
1177overlap (int s1, int e1, int s2, int e2)
1178{
1179 return (!(e1 < s2 || s1 >= e2));
1180}
1181
1182static gboolean
1183horizontal_overlap (Edge *snapper, Edge *snappee)
1184{
1185 if (snapper->y1 != snapper->y2 || snappee->y1 != snappee->y2)
1186 return FALSE(0);
1187
1188 return overlap (snapper->x1, snapper->x2, snappee->x1, snappee->x2);
1189}
1190
1191static gboolean
1192vertical_overlap (Edge *snapper, Edge *snappee)
1193{
1194 if (snapper->x1 != snapper->x2 || snappee->x1 != snappee->x2)
1195 return FALSE(0);
1196
1197 return overlap (snapper->y1, snapper->y2, snappee->y1, snappee->y2);
1198}
1199
1200static void
1201add_snap (GArray *snaps, Snap snap)
1202{
1203 if (ABS (snap.dx)(((snap.dx) < 0) ? -(snap.dx) : (snap.dx)) <= 200 || ABS (snap.dy)(((snap.dy) < 0) ? -(snap.dy) : (snap.dy)) <= 200)
1204 g_array_append_val (snaps, snap)g_array_append_vals (snaps, &(snap), 1);
1205}
1206
1207static void
1208add_edge_snaps (Edge *snapper, Edge *snappee, GArray *snaps)
1209{
1210 Snap snap;
1211
1212 snap.snapper = snapper;
1213 snap.snappee = snappee;
1214
1215 if (horizontal_overlap (snapper, snappee))
1216 {
1217 snap.dx = 0;
1218 snap.dy = snappee->y1 - snapper->y1;
1219
1220 add_snap (snaps, snap);
1221 }
1222 else if (vertical_overlap (snapper, snappee))
1223 {
1224 snap.dy = 0;
1225 snap.dx = snappee->x1 - snapper->x1;
1226
1227 add_snap (snaps, snap);
1228 }
1229
1230 /* Corner snaps */
1231 /* 1->1 */
1232 snap.dx = snappee->x1 - snapper->x1;
1233 snap.dy = snappee->y1 - snapper->y1;
1234
1235 add_snap (snaps, snap);
1236
1237 /* 1->2 */
1238 snap.dx = snappee->x2 - snapper->x1;
1239 snap.dy = snappee->y2 - snapper->y1;
1240
1241 add_snap (snaps, snap);
1242
1243 /* 2->2 */
1244 snap.dx = snappee->x2 - snapper->x2;
1245 snap.dy = snappee->y2 - snapper->y2;
1246
1247 add_snap (snaps, snap);
1248
1249 /* 2->1 */
1250 snap.dx = snappee->x1 - snapper->x2;
1251 snap.dy = snappee->y1 - snapper->y2;
1252
1253 add_snap (snaps, snap);
1254}
1255
1256static void
1257list_snaps (CafeRROutputInfo *output, GArray *edges, GArray *snaps)
1258{
1259 int i;
1260
1261 for (i = 0; i < edges->len; ++i)
1262 {
1263 Edge *output_edge = &(g_array_index (edges, Edge, i)(((Edge*) (void *) (edges)->data) [(i)]));
1264
1265 if (output_edge->output == output)
1266 {
1267 int j;
1268
1269 for (j = 0; j < edges->len; ++j)
1270 {
1271 Edge *edge = &(g_array_index (edges, Edge, j)(((Edge*) (void *) (edges)->data) [(j)]));
1272
1273 if (edge->output != output)
1274 add_edge_snaps (output_edge, edge, snaps);
1275 }
1276 }
1277 }
1278}
1279
1280#if 0
1281static void
1282print_edge (Edge *edge)
1283{
1284 g_debug ("(%d %d %d %d)", edge->x1, edge->y1, edge->x2, edge->y2);
1285}
1286#endif
1287
1288static gboolean
1289corner_on_edge (int x, int y, Edge *e)
1290{
1291 if (x == e->x1 && x == e->x2 && y >= e->y1 && y <= e->y2)
1292 return TRUE(!(0));
1293
1294 if (y == e->y1 && y == e->y2 && x >= e->x1 && x <= e->x2)
1295 return TRUE(!(0));
1296
1297 return FALSE(0);
1298}
1299
1300static gboolean
1301edges_align (Edge *e1, Edge *e2)
1302{
1303 if (corner_on_edge (e1->x1, e1->y1, e2))
1304 return TRUE(!(0));
1305
1306 if (corner_on_edge (e2->x1, e2->y1, e1))
1307 return TRUE(!(0));
1308
1309 return FALSE(0);
1310}
1311
1312static gboolean
1313output_is_aligned (CafeRROutputInfo *output, GArray *edges)
1314{
1315 gboolean result = FALSE(0);
1316 int i;
1317
1318 for (i = 0; i < edges->len; ++i)
1319 {
1320 Edge *output_edge = &(g_array_index (edges, Edge, i)(((Edge*) (void *) (edges)->data) [(i)]));
1321
1322 if (output_edge->output == output)
1323 {
1324 int j;
1325
1326 for (j = 0; j < edges->len; ++j)
1327 {
1328 Edge *edge = &(g_array_index (edges, Edge, j)(((Edge*) (void *) (edges)->data) [(j)]));
1329
1330 /* We are aligned if an output edge matches
1331 * an edge of another output
1332 */
1333 if (edge->output != output_edge->output)
1334 {
1335 if (edges_align (output_edge, edge))
1336 {
1337 result = TRUE(!(0));
1338 goto done;
1339 }
1340 }
1341 }
1342 }
1343 }
1344done:
1345
1346 return result;
1347}
1348
1349static void
1350get_output_rect (CafeRROutputInfo *output, CdkRectangle *rect)
1351{
1352 cafe_rr_output_info_get_geometry (output, &rect->x, &rect->y, &rect->width, &rect->height);
1353 get_geometry (output, &rect->width, &rect->height); // accounts for rotation
1354}
1355
1356static gboolean
1357output_overlaps (CafeRROutputInfo *output, CafeRRConfig *config)
1358{
1359 int i;
1360 CdkRectangle output_rect;
1361 CafeRROutputInfo **outputs;
1362
1363 get_output_rect (output, &output_rect);
1364
1365 outputs = cafe_rr_config_get_outputs (config);
1366 for (i = 0; outputs[i]; ++i)
1367 {
1368 if (outputs[i] != output && cafe_rr_output_info_is_connected (outputs[i]))
1369 {
1370 CdkRectangle other_rect;
1371
1372 get_output_rect (outputs[i], &other_rect);
1373 if (cdk_rectangle_intersect (&output_rect, &other_rect, NULL((void*)0)))
1374 return TRUE(!(0));
1375 }
1376 }
1377
1378 return FALSE(0);
1379}
1380
1381static gboolean
1382cafe_rr_config_is_aligned (CafeRRConfig *config, GArray *edges)
1383{
1384 int i;
1385 gboolean result = TRUE(!(0));
1386 CafeRROutputInfo **outputs;
1387
1388 outputs = cafe_rr_config_get_outputs(config);
1389 for (i = 0; outputs[i]; ++i)
1390 {
1391 if (cafe_rr_output_info_is_connected (outputs[i]))
1392 {
1393 if (!output_is_aligned (outputs[i], edges))
1394 return FALSE(0);
1395
1396 if (output_overlaps (outputs[i], config))
1397 return FALSE(0);
1398 }
1399 }
1400
1401 return result;
1402}
1403
1404struct GrabInfo
1405{
1406 int grab_x;
1407 int grab_y;
1408 int output_x;
1409 int output_y;
1410};
1411
1412static gboolean
1413is_corner_snap (const Snap *s)
1414{
1415 return s->dx != 0 && s->dy != 0;
1416}
1417
1418static int
1419compare_snaps (gconstpointer v1, gconstpointer v2)
1420{
1421 const Snap *s1 = v1;
1422 const Snap *s2 = v2;
1423 int sv1 = MAX (ABS (s1->dx), ABS (s1->dy))((((((s1->dx) < 0) ? -(s1->dx) : (s1->dx))) > (
(((s1->dy) < 0) ? -(s1->dy) : (s1->dy)))) ? ((((s1
->dx) < 0) ? -(s1->dx) : (s1->dx))) : ((((s1->
dy) < 0) ? -(s1->dy) : (s1->dy))))
;
1424 int sv2 = MAX (ABS (s2->dx), ABS (s2->dy))((((((s2->dx) < 0) ? -(s2->dx) : (s2->dx))) > (
(((s2->dy) < 0) ? -(s2->dy) : (s2->dy)))) ? ((((s2
->dx) < 0) ? -(s2->dx) : (s2->dx))) : ((((s2->
dy) < 0) ? -(s2->dy) : (s2->dy))))
;
1425 int d;
1426
1427 d = sv1 - sv2;
1428
1429 /* This snapping algorithm is good enough for rock'n'roll, but
1430 * this is probably a better:
1431 *
1432 * First do a horizontal/vertical snap, then
1433 * with the new coordinates from that snap,
1434 * do a corner snap.
1435 *
1436 * Right now, it's confusing that corner snapping
1437 * depends on the distance in an axis that you can't actually see.
1438 *
1439 */
1440 if (d == 0)
1441 {
1442 if (is_corner_snap (s1) && !is_corner_snap (s2))
1443 return -1;
1444 else if (is_corner_snap (s2) && !is_corner_snap (s1))
1445 return 1;
1446 else
1447 return 0;
1448 }
1449 else
1450 {
1451 return d;
1452 }
1453}
1454
1455/* Sets a mouse cursor for a widget's window. As a hack, you can pass
1456 * CDK_BLANK_CURSOR to mean "set the cursor to NULL" (i.e. reset the widget's
1457 * window's cursor to its default).
1458 */
1459static void
1460set_cursor (CtkWidget *widget, CdkCursorType type)
1461{
1462 CdkCursor *cursor;
1463 CdkWindow *window;
1464
1465 if (type == CDK_BLANK_CURSOR)
1466 cursor = NULL((void*)0);
1467 else
1468 cursor = cdk_cursor_new_for_display (ctk_widget_get_display (widget), type);
1469
1470 window = ctk_widget_get_window (widget);
1471
1472 if (window)
1473 cdk_window_set_cursor (window, cursor);
1474
1475 if (cursor)
1476 g_object_unref (cursor);
1477}
1478
1479static void
1480set_monitors_tooltip (App *app, gboolean is_dragging)
1481{
1482 const char *text;
1483
1484 if (is_dragging)
1485 text = NULL((void*)0);
1486 else
1487 text = _("Select a monitor to change its properties; drag it to rearrange its placement.")gettext ("Select a monitor to change its properties; drag it to rearrange its placement."
)
;
1488
1489 ctk_widget_set_tooltip_text (app->area, text);
1490}
1491
1492static void
1493on_output_event (FooScrollArea *area,
1494 FooScrollAreaEvent *event,
1495 gpointer data)
1496{
1497 CafeRROutputInfo *output = data;
1498 App *app = g_object_get_data (G_OBJECT (area)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((area)), (((GType) ((20) << (2))))))))
, "app");
1499
1500 /* If the mouse is inside the outputs, set the cursor to "you can move me". See
1501 * on_canvas_event() for where we reset the cursor to the default if it
1502 * exits the outputs' area.
1503 */
1504 if (!cafe_rr_config_get_clone (app->current_configuration) && get_n_connected (app) > 1)
1505 set_cursor (CTK_WIDGET (area)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((area)), ((ctk_widget_get_type ()))))))
, CDK_FLEUR);
1506
1507 if (event->type == FOO_BUTTON_PRESS)
1508 {
1509 GrabInfo *info;
1510
1511 app->current_output = output;
1512
1513 rebuild_gui (app);
1514 set_monitors_tooltip (app, TRUE(!(0)));
1515
1516 if (!cafe_rr_config_get_clone (app->current_configuration) && get_n_connected (app) > 1)
1517 {
1518 int output_x, output_y;
1519 cafe_rr_output_info_get_geometry (output, &output_x, &output_y, NULL((void*)0), NULL((void*)0));
1520
1521 foo_scroll_area_begin_grab (area, on_output_event, data);
1522
1523 info = g_new0 (GrabInfo, 1)((GrabInfo *) g_malloc0_n ((1), sizeof (GrabInfo)));
1524 info->grab_x = event->x;
1525 info->grab_y = event->y;
1526 info->output_x = output_x;
1527 info->output_y = output_y;
1528
1529 g_object_set_data (G_OBJECT (output)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), (((GType) ((20) << (2))))))))
, "grab-info", info);
1530 }
1531
1532 foo_scroll_area_invalidate (area);
1533 }
1534 else
1535 {
1536 if (foo_scroll_area_is_grabbed (area))
1537 {
1538 GrabInfo *info = g_object_get_data (G_OBJECT (output)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), (((GType) ((20) << (2))))))))
, "grab-info");
1539 double scale = compute_scale (app);
1540 int old_x, old_y;
1541 int width, height;
1542 int new_x, new_y;
1543 int i;
1544 GArray *edges, *snaps, *new_edges;
1545
1546 cafe_rr_output_info_get_geometry (output, &old_x, &old_y, &width, &height);
1547 new_x = info->output_x + (event->x - info->grab_x) / scale;
1548 new_y = info->output_y + (event->y - info->grab_y) / scale;
1549
1550 cafe_rr_output_info_set_geometry (output, new_x, new_y, width, height);
1551
1552 edges = g_array_new (TRUE(!(0)), TRUE(!(0)), sizeof (Edge));
1553 snaps = g_array_new (TRUE(!(0)), TRUE(!(0)), sizeof (Snap));
1554 new_edges = g_array_new (TRUE(!(0)), TRUE(!(0)), sizeof (Edge));
1555
1556 list_edges (app->current_configuration, edges);
1557 list_snaps (output, edges, snaps);
1558
1559 g_array_sort (snaps, compare_snaps);
1560
1561 cafe_rr_output_info_set_geometry (output, new_x, new_y, width, height);
1562
1563 for (i = 0; i < snaps->len; ++i)
1564 {
1565 Snap *snap = &(g_array_index (snaps, Snap, i)(((Snap*) (void *) (snaps)->data) [(i)]));
1566 GArray *new_edges = g_array_new (TRUE(!(0)), TRUE(!(0)), sizeof (Edge));
1567
1568 cafe_rr_output_info_set_geometry (output, new_x + snap->dx, new_y + snap->dy, width, height);
1569
1570 g_array_set_size (new_edges, 0);
1571 list_edges (app->current_configuration, new_edges);
1572
1573 if (cafe_rr_config_is_aligned (app->current_configuration, new_edges))
1574 {
1575 g_array_free (new_edges, TRUE(!(0)));
1576 break;
1577 }
1578 else
1579 {
1580 cafe_rr_output_info_set_geometry (output, info->output_x, info->output_y, width, height);
1581 }
1582 }
1583
1584 g_array_free (new_edges, TRUE(!(0)));
1585 g_array_free (snaps, TRUE(!(0)));
1586 g_array_free (edges, TRUE(!(0)));
1587
1588 if (event->type == FOO_BUTTON_RELEASE)
1589 {
1590 foo_scroll_area_end_grab (area);
1591 set_monitors_tooltip (app, FALSE(0));
1592
1593 g_free (g_object_get_data (G_OBJECT (output)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), (((GType) ((20) << (2))))))))
, "grab-info"));
1594 g_object_set_data (G_OBJECT (output)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), (((GType) ((20) << (2))))))))
, "grab-info", NULL((void*)0));
1595
1596#if 0
1597 g_debug ("new position: %d %d %d %d", output->x, output->y, output->width, output->height);
1598#endif
1599 }
1600
1601 foo_scroll_area_invalidate (area);
1602 }
1603 }
1604}
1605
1606static void
1607on_canvas_event (FooScrollArea *area,
1608 FooScrollAreaEvent *event,
1609 gpointer data)
1610{
1611 /* If the mouse exits the outputs, reset the cursor to the default. See
1612 * on_output_event() for where we set the cursor to the movement cursor if
1613 * it is over one of the outputs.
1614 */
1615 set_cursor (CTK_WIDGET (area)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((area)), ((ctk_widget_get_type ()))))))
, CDK_BLANK_CURSOR);
1616}
1617
1618static PangoLayout *
1619get_display_name (App *app,
1620 CafeRROutputInfo *output)
1621{
1622 char *text;
1623 PangoLayout * layout;
1624
1625 if (cafe_rr_config_get_clone (app->current_configuration)) {
1626 /* Translators: this is the feature where what you see on your laptop's
1627 * screen is the same as your external monitor. Here, "Mirror" is being
1628 * used as an adjective, not as a verb. For example, the Spanish
1629 * translation could be "Pantallas en Espejo", *not* "Espejar Pantallas".
1630 */
1631 text = g_strdup_printf (_("Mirror Screens")gettext ("Mirror Screens"));
1632 }
1633 else {
1634 text = g_strdup_printf ("<b>%s</b>\n<small>%s</small>", cafe_rr_output_info_get_display_name (output), cafe_rr_output_info_get_name (output));
1635 }
1636 layout = ctk_widget_create_pango_layout (CTK_WIDGET (app->area)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->area)), ((ctk_widget_get_type ()))))))
, text);
1637 pango_layout_set_markup (layout, text, -1);
1638 g_free (text);
1639 pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
1640 return layout;
1641}
1642
1643static void
1644paint_background (FooScrollArea *area,
1645 cairo_t *cr)
1646{
1647 CdkRectangle viewport;
1648 CtkWidget *widget;
1649 CtkStyleContext *widget_style;
1650 CdkRGBA *base_color = NULL((void*)0);
1651 CdkRGBA dark_color;
1652
1653 widget = CTK_WIDGET (area)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((area)), ((ctk_widget_get_type ()))))))
;
1654
1655 foo_scroll_area_get_viewport (area, &viewport);
1656
1657 widget_style = ctk_widget_get_style_context (widget);
1658
1659 ctk_style_context_save (widget_style);
1660 ctk_style_context_set_state (widget_style, CTK_STATE_FLAG_SELECTED);
1661 ctk_style_context_get (widget_style,
1662 ctk_style_context_get_state (widget_style),
1663 CTK_STYLE_PROPERTY_BACKGROUND_COLOR"background-color", &base_color,
1664 NULL((void*)0));
1665 ctk_style_context_restore (widget_style);
1666 cdk_cairo_set_source_rgba(cr, base_color);
1667 cdk_rgba_free (base_color);
1668
1669 cairo_rectangle (cr,
1670 viewport.x, viewport.y,
1671 viewport.width, viewport.height);
1672
1673 cairo_fill_preserve (cr);
1674
1675 foo_scroll_area_add_input_from_fill (area, cr, on_canvas_event, NULL((void*)0));
1676
1677 ctk_style_context_save (widget_style);
1678 ctk_style_context_set_state (widget_style, CTK_STATE_FLAG_SELECTED);
1679 cafe_desktop_ctk_style_get_dark_color (widget_style,
1680 ctk_style_context_get_state (widget_style),
1681 &dark_color);
1682 ctk_style_context_restore (widget_style);
1683 cdk_cairo_set_source_rgba (cr, &dark_color);
1684
1685 cairo_stroke (cr);
1686}
1687
1688static void
1689paint_output (App *app, cairo_t *cr, int i)
1690{
1691 int w, h;
1692 double scale = compute_scale (app);
1693 double x, y;
1694 int output_x, output_y;
1695 CafeRRRotation rotation;
1696 int total_w, total_h;
1697 GList *connected_outputs = list_connected_outputs (app, &total_w, &total_h);
1698 CafeRROutputInfo *output = g_list_nth_data (connected_outputs, i);
1699 PangoLayout *layout = get_display_name (app, output);
1700 PangoRectangle ink_extent, log_extent;
1701 CdkRectangle viewport;
1702 CdkRGBA output_color;
1703 double r, g, b;
1704 double available_w;
1705 double factor;
1706
1707 cairo_save (cr);
1708
1709 foo_scroll_area_get_viewport (FOO_SCROLL_AREA (app->area)((((FooScrollArea*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->area)), ((foo_scroll_area_get_type ()))))))
, &viewport);
1710
1711 get_geometry (output, &w, &h);
1712
1713#if 0
1714 g_debug ("%s (%p) geometry %d %d %d", output->name, output,
1715 w, h, output->rate);
1716#endif
1717
1718 viewport.height -= 2 * MARGIN15;
1719 viewport.width -= 2 * MARGIN15;
1720
1721 cafe_rr_output_info_get_geometry (output, &output_x, &output_y, NULL((void*)0), NULL((void*)0));
1722 x = output_x * scale + MARGIN15 + (viewport.width - total_w * scale) / 2.0;
1723 y = output_y * scale + MARGIN15 + (viewport.height - total_h * scale) / 2.0;
1724
1725#if 0
1726 g_debug ("scaled: %f %f", x, y);
1727
1728 g_debug ("scale: %f", scale);
1729
1730 g_debug ("%f %f %f %f", x, y, w * scale + 0.5, h * scale + 0.5);
1731#endif
1732
1733 cairo_translate (cr,
1734 x + (w * scale + 0.5) / 2,
1735 y + (h * scale + 0.5) / 2);
1736
1737 /* rotation is already applied in get_geometry */
1738
1739 rotation = cafe_rr_output_info_get_rotation (output);
1740 if (rotation & CAFE_RR_REFLECT_X)
1741 cairo_scale (cr, -1, 1);
1742
1743 if (rotation & CAFE_RR_REFLECT_Y)
1744 cairo_scale (cr, 1, -1);
1745
1746 cairo_translate (cr,
1747 - x - (w * scale + 0.5) / 2,
1748 - y - (h * scale + 0.5) / 2);
1749
1750
1751 cairo_rectangle (cr, x, y, w * scale + 0.5, h * scale + 0.5);
1752 cairo_clip_preserve (cr);
1753
1754 cafe_rr_labeler_get_rgba_for_output (app->labeler, output, &output_color);
1755 r = output_color.red;
1756 g = output_color.green;
1757 b = output_color.blue;
1758
1759 if (!cafe_rr_output_info_is_active (output))
1760 {
1761 /* If the output is turned off, just darken the selected color */
1762 r *= 0.2;
1763 g *= 0.2;
1764 b *= 0.2;
1765 }
1766
1767 cairo_set_source_rgba (cr, r, g, b, 1.0);
1768
1769 foo_scroll_area_add_input_from_fill (FOO_SCROLL_AREA (app->area)((((FooScrollArea*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->area)), ((foo_scroll_area_get_type ()))))))
,
1770 cr, on_output_event, output);
1771 cairo_fill (cr);
1772
1773 if (output == app->current_output)
1774 {
1775 cairo_rectangle (cr, x + 2, y + 2, w * scale + 0.5 - 4, h * scale + 0.5 - 4);
1776
1777 cairo_set_line_width (cr, 4);
1778 cairo_set_source_rgba (cr, 0.33, 0.43, 0.57, 1.0);
1779 cairo_stroke (cr);
1780 }
1781
1782 cairo_rectangle (cr, x + 0.5, y + 0.5, w * scale + 0.5 - 1, h * scale + 0.5 - 1);
1783
1784 cairo_set_line_width (cr, 1);
1785 cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
1786
1787 cairo_stroke (cr);
1788 cairo_set_line_width (cr, 2);
1789
1790 layout_set_font (layout, "Sans 12");
1791 pango_layout_get_pixel_extents (layout, &ink_extent, &log_extent);
1792
1793 available_w = w * scale + 0.5 - 6; /* Same as the inner rectangle's width, minus 1 pixel of padding on each side */
1794 if (available_w < ink_extent.width)
1795 factor = available_w / ink_extent.width;
1796 else
1797 factor = 1.0;
1798
1799 cairo_move_to (cr,
1800 x + ((w * scale + 0.5) - factor * log_extent.width) / 2,
1801 y + ((h * scale + 0.5) - factor * log_extent.height) / 2);
1802
1803 cairo_scale (cr, factor, factor);
1804
1805 if (cafe_rr_output_info_is_active (output))
1806 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
1807 else
1808 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
1809
1810 pango_cairo_show_layout (cr, layout);
1811
1812 cairo_restore (cr);
1813
1814 g_object_unref (layout);
1815}
1816
1817static void
1818on_area_paint (FooScrollArea *area,
1819 cairo_t *cr,
1820 gpointer data)
1821{
1822 App *app = data;
1823 GList *connected_outputs = NULL((void*)0);
1824 GList *list;
1825
1826 paint_background (area, cr);
1827
1828 if (!app->current_configuration)
1829 return;
1830
1831 connected_outputs = list_connected_outputs (app, NULL((void*)0), NULL((void*)0));
1832
1833#if 0
1834 double scale;
1835 scale = compute_scale (app);
1836 g_debug ("scale: %f", scale);
1837#endif
1838
1839 for (list = connected_outputs; list != NULL((void*)0); list = list->next)
1840 {
1841 paint_output (app, cr, g_list_position (connected_outputs, list));
1842
1843 if (cafe_rr_config_get_clone (app->current_configuration))
1844 break;
1845 }
1846}
1847
1848static void
1849make_text_combo (CtkWidget *widget, int sort_column)
1850{
1851 CtkComboBox *box = CTK_COMBO_BOX (widget)((((CtkComboBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_combo_box_get_type ()))))))
;
1852 CtkListStore *store = ctk_list_store_new (
1853 6,
1854 G_TYPE_STRING((GType) ((16) << (2))), /* Text */
1855 G_TYPE_INT((GType) ((6) << (2))), /* Width */
1856 G_TYPE_INT((GType) ((6) << (2))), /* Height */
1857 G_TYPE_INT((GType) ((6) << (2))), /* Frequency */
1858 G_TYPE_INT((GType) ((6) << (2))), /* Width * Height */
1859 G_TYPE_INT((GType) ((6) << (2)))); /* Rotation */
1860
1861 CtkCellRenderer *cell;
1862
1863 ctk_cell_layout_clear (CTK_CELL_LAYOUT (widget)((((CtkCellLayout*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_cell_layout_get_type ()))))))
);
1864
1865 ctk_combo_box_set_model (box, CTK_TREE_MODEL (store)((((CtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((store)), ((ctk_tree_model_get_type ()))))))
);
1866
1867 cell = ctk_cell_renderer_text_new ();
1868 ctk_cell_layout_pack_start (CTK_CELL_LAYOUT (box)((((CtkCellLayout*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_cell_layout_get_type ()))))))
, cell, TRUE(!(0)));
1869 ctk_cell_layout_set_attributes (CTK_CELL_LAYOUT (box)((((CtkCellLayout*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_cell_layout_get_type ()))))))
, cell,
1870 "text", 0,
1871 NULL((void*)0));
1872
1873 if (sort_column != -1)
1874 {
1875 ctk_tree_sortable_set_sort_column_id (CTK_TREE_SORTABLE (store)((((CtkTreeSortable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((store)), ((ctk_tree_sortable_get_type ()))))))
,
1876 sort_column,
1877 CTK_SORT_DESCENDING);
1878 }
1879}
1880
1881static void
1882compute_virtual_size_for_configuration (CafeRRConfig *config, int *ret_width, int *ret_height)
1883{
1884 int i;
1885 int width, height;
1886 int output_x, output_y, output_width, output_height;
1887 CafeRROutputInfo **outputs;
1888
1889 width = height = 0;
1890
1891 outputs = cafe_rr_config_get_outputs (config);
1892 for (i = 0; outputs[i] != NULL((void*)0); i++)
1893 {
1894 if (cafe_rr_output_info_is_active (outputs[i]))
1895 {
1896 cafe_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height);
1897 width = MAX (width, output_x + output_width)(((width) > (output_x + output_width)) ? (width) : (output_x
+ output_width))
;
1898 height = MAX (height, output_y + output_height)(((height) > (output_y + output_height)) ? (height) : (output_y
+ output_height))
;
1899 }
1900 }
1901
1902 *ret_width = width;
1903 *ret_height = height;
1904}
1905
1906static void
1907check_required_virtual_size (App *app)
1908{
1909 int req_width, req_height;
1910 int min_width, max_width;
1911 int min_height, max_height;
1912
1913 compute_virtual_size_for_configuration (app->current_configuration, &req_width, &req_height);
1914
1915 cafe_rr_screen_get_ranges (app->screen, &min_width, &max_width, &min_height, &max_height);
1916
1917#if 0
1918 g_debug ("X Server supports:");
1919 g_debug ("min_width = %d, max_width = %d", min_width, max_width);
1920 g_debug ("min_height = %d, max_height = %d", min_height, max_height);
1921
1922 g_debug ("Requesting size of %dx%d", req_width, req_height);
1923#endif
1924
1925 if (!(min_width <= req_width && req_width <= max_width
1926 && min_height <= req_height && req_height <= max_height))
1927 {
1928 /* FIXME: present a useful dialog, maybe even before the user tries to Apply */
1929#if 0
1930 g_debug ("Your X server needs a larger Virtual size!");
1931#endif
1932 }
1933}
1934
1935static void
1936begin_version2_apply_configuration (App *app, CdkWindow *parent_window, guint32 timestamp)
1937{
1938 XID parent_window_xid;
1939 GError *error = NULL((void*)0);
1940
1941 parent_window_xid = CDK_WINDOW_XID (parent_window)(cdk_x11_window_get_xid (parent_window));
1942
1943 app->proxy = g_dbus_proxy_new_sync (app->connection,
1944 G_DBUS_PROXY_FLAGS_NONE,
1945 NULL((void*)0),
1946 "org.cafe.SettingsDaemon",
1947 "/org/cafe/SettingsDaemon/XRANDR",
1948 "org.cafe.SettingsDaemon.XRANDR_2",
1949 NULL((void*)0),
1950 &error);
1951 if (app->proxy == NULL((void*)0)) {
1952 g_warning ("Failed to get dbus connection: %s", error->message);
1953 g_error_free (error);
1954 } else {
1955 app->apply_configuration_state = APPLYING_VERSION_2;
1956 g_dbus_proxy_call (app->proxy,
1957 "ApplyConfiguration",
1958 g_variant_new ("(xx)", parent_window_xid, timestamp),
1959 G_DBUS_CALL_FLAGS_NONE,
1960 -1,
1961 NULL((void*)0),
1962 (GAsyncReadyCallback) apply_configuration_returned_cb,
1963 app);
1964 }
1965}
1966
1967static void
1968begin_version1_apply_configuration (App *app)
1969{
1970 GError *error = NULL((void*)0);
1971
1972 app->proxy = g_dbus_proxy_new_sync (app->connection,
1973 G_DBUS_PROXY_FLAGS_NONE,
1974 NULL((void*)0),
1975 "org.cafe.SettingsDaemon",
1976 "/org/cafe/SettingsDaemon/XRANDR",
1977 "org.cafe.SettingsDaemon.XRANDR",
1978 NULL((void*)0),
1979 &error);
1980 if (app->proxy == NULL((void*)0)) {
1981 g_warning ("Failed to get dbus connection: %s", error->message);
1982 g_error_free (error);
1983 } else {
1984 app->apply_configuration_state = APPLYING_VERSION_1;
1985 g_dbus_proxy_call (app->proxy,
1986 "ApplyConfiguration",
1987 g_variant_new ("()"),
1988 G_DBUS_CALL_FLAGS_NONE,
1989 -1,
1990 NULL((void*)0),
1991 (GAsyncReadyCallback) apply_configuration_returned_cb,
1992 app);
1993 }
1994}
1995
1996static void
1997ensure_current_configuration_is_saved (void)
1998{
1999 CafeRRScreen *rr_screen;
2000 CafeRRConfig *rr_config;
2001
2002 /* Normally, cafe_rr_config_save() creates a backup file based on the
2003 * old monitors.xml. However, if *that* file didn't exist, there is
2004 * nothing from which to create a backup. So, here we'll save the
2005 * current/unchanged configuration and then let our caller call
2006 * cafe_rr_config_save() again with the new/changed configuration, so
2007 * that there *will* be a backup file in the end.
2008 */
2009
2010 rr_screen = cafe_rr_screen_new (cdk_screen_get_default (), NULL((void*)0)); /* NULL-GError */
2011 if (!rr_screen)
2012 return;
2013
2014 rr_config = cafe_rr_config_new_current (rr_screen, NULL((void*)0));
2015 cafe_rr_config_save (rr_config, NULL((void*)0)); /* NULL-GError */
2016
2017 g_object_unref (rr_config);
2018 g_object_unref (rr_screen);
2019}
2020
2021/* Callback for g_dbus_proxy_call() */
2022static void
2023apply_configuration_returned_cb (GObject *source_object,
2024 GAsyncResult *res,
2025 gpointer data)
2026{
2027 GVariant *variant;
2028 GError *error;
2029 App *app = data;
2030
2031 error = NULL((void*)0);
2032
2033 if (app->proxy == NULL((void*)0))
2034 return;
2035
2036 variant = g_dbus_proxy_call_finish (app->proxy, res, &error);
2037 if (variant == NULL((void*)0)) {
2038 if (app->apply_configuration_state == APPLYING_VERSION_2
2039 && g_error_matches (error, G_DBUS_ERRORg_dbus_error_quark(), G_DBUS_ERROR_UNKNOWN_METHOD)) {
2040 g_error_free (error);
2041
2042 g_object_unref (app->proxy);
2043 app->proxy = NULL((void*)0);
2044
2045 begin_version1_apply_configuration (app);
2046 return;
2047 } else {
2048 /* We don't pop up an error message; cafe-settings-daemon already does that
2049 * in case the selected RANDR configuration could not be applied.
2050 */
2051 g_error_free (error);
2052 }
2053 }
2054
2055 g_object_unref (app->proxy);
2056 app->proxy = NULL((void*)0);
2057
2058 g_object_unref (app->connection);
2059 app->connection = NULL((void*)0);
2060
2061 ctk_widget_set_sensitive (app->dialog, TRUE(!(0)));
2062}
2063
2064static gboolean
2065sanitize_and_save_configuration (App *app)
2066{
2067 GError *error;
2068
2069 cafe_rr_config_sanitize (app->current_configuration);
2070
2071 check_required_virtual_size (app);
2072
2073 foo_scroll_area_invalidate (FOO_SCROLL_AREA (app->area)((((FooScrollArea*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->area)), ((foo_scroll_area_get_type ()))))))
);
2074
2075 ensure_current_configuration_is_saved ();
2076
2077 error = NULL((void*)0);
2078 if (!cafe_rr_config_save (app->current_configuration, &error))
2079 {
2080 error_message (app, _("Could not save the monitor configuration")gettext ("Could not save the monitor configuration"), error->message);
2081 g_error_free (error);
2082 return FALSE(0);
2083 }
2084
2085 return TRUE(!(0));
2086}
2087
2088static void
2089apply (App *app)
2090{
2091 GError *error = NULL((void*)0);
2092
2093 if (!sanitize_and_save_configuration (app))
2094 return;
2095
2096 g_assert (app->connection == NULL)do { if (app->connection == ((void*)0)) ; else g_assertion_message_expr
("display-properties", "xrandr-capplet.c", 2096, ((const char
*) (__func__)), "app->connection == NULL"); } while (0)
;
2097 g_assert (app->proxy == NULL)do { if (app->proxy == ((void*)0)) ; else g_assertion_message_expr
("display-properties", "xrandr-capplet.c", 2097, ((const char
*) (__func__)), "app->proxy == NULL"); } while (0)
;
2098
2099 app->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL((void*)0), &error);
2100 if (app->connection == NULL((void*)0)) {
2101 error_message (app, _("Could not get session bus while applying display configuration")gettext ("Could not get session bus while applying display configuration"
)
, error->message);
2102 g_error_free (error);
2103 return;
2104 }
2105
2106 ctk_widget_set_sensitive (app->dialog, FALSE(0));
2107
2108 begin_version2_apply_configuration (app, ctk_widget_get_window (app->dialog), app->apply_button_clicked_timestamp);
2109}
2110
2111static void
2112on_detect_displays (CtkWidget *widget, gpointer data)
2113{
2114 App *app = data;
2115 GError *error;
2116
2117 error = NULL((void*)0);
2118 if (!cafe_rr_screen_refresh (app->screen, &error)) {
2119 if (error) {
2120 error_message (app, _("Could not detect displays")gettext ("Could not detect displays"), error->message);
2121 g_error_free (error);
2122 }
2123 }
2124}
2125
2126static void
2127set_primary (CtkWidget *widget, gpointer data)
2128{
2129 App *app = data;
2130 int i;
2131 CafeRROutputInfo **outputs;
2132
2133 if (!app->current_output)
2134 return;
2135
2136 outputs = cafe_rr_config_get_outputs (app->current_configuration);
2137 for (i=0; outputs[i]!=NULL((void*)0); i++) {
2138 cafe_rr_output_info_set_primary (outputs[i], outputs[i] == app->current_output);
2139 }
2140
2141 ctk_widget_set_sensitive (app->primary_button, !cafe_rr_output_info_get_primary(app->current_output));
2142}
2143
2144#define CSD_XRANDR_SCHEMA"org.cafe.SettingsDaemon.plugins.xrandr" "org.cafe.SettingsDaemon.plugins.xrandr"
2145#define SHOW_ICON_KEY"show-notification-icon" "show-notification-icon"
2146#define DEFAULT_CONFIGURATION_FILE_KEY"default-configuration-file" "default-configuration-file"
2147
2148static void
2149on_show_icon_toggled (CtkWidget *widget, gpointer data)
2150{
2151 CtkToggleButton *tb = CTK_TOGGLE_BUTTON (widget)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_toggle_button_get_type ()))))))
;
2152 App *app = data;
2153
2154 g_settings_set_boolean (app->settings, SHOW_ICON_KEY"show-notification-icon",
2155 ctk_toggle_button_get_active (tb));
2156}
2157
2158static CafeRROutputInfo *
2159get_nearest_output (CafeRRConfig *configuration, int x, int y)
2160{
2161 int i;
2162 int nearest_index;
2163 int nearest_dist;
2164 CafeRROutputInfo **outputs;
2165
2166 nearest_index = -1;
2167 nearest_dist = G_MAXINT2147483647;
2168
2169 outputs = cafe_rr_config_get_outputs (configuration);
2170 for (i = 0; outputs[i] != NULL((void*)0); i++)
2171 {
2172 int dist_x, dist_y;
2173 int output_x, output_y, output_width, output_height;
2174
2175 if (!(cafe_rr_output_info_is_connected(outputs[i]) && cafe_rr_output_info_is_active (outputs[i])))
2176 continue;
2177
2178 cafe_rr_output_info_get_geometry (outputs[i], &output_x, &output_y, &output_width, &output_height);
2179 if (x < output_x)
2180 dist_x = output_x - x;
2181 else if (x >= output_x + output_width)
2182 dist_x = x - (output_x + output_width) + 1;
2183 else
2184 dist_x = 0;
2185
2186 if (y < output_y)
2187 dist_y = output_y - y;
2188 else if (y >= output_y + output_height)
2189 dist_y = y - (output_y + output_height) + 1;
2190 else
2191 dist_y = 0;
2192
2193 if (MIN (dist_x, dist_y)(((dist_x) < (dist_y)) ? (dist_x) : (dist_y)) < nearest_dist)
2194 {
2195 nearest_dist = MIN (dist_x, dist_y)(((dist_x) < (dist_y)) ? (dist_x) : (dist_y));
2196 nearest_index = i;
2197 }
2198 }
2199
2200 if (nearest_index != -1)
2201 return outputs[nearest_index];
2202 else
2203 return NULL((void*)0);
2204
2205}
2206
2207/* Gets the output that contains the largest intersection with the window.
2208 * Logic stolen from cdk_screen_get_monitor_at_window().
2209 */
2210static CafeRROutputInfo *
2211get_output_for_window (CafeRRConfig *configuration, CdkWindow *window)
2212{
2213 CdkRectangle win_rect;
2214 int i;
2215 int largest_area;
2216 int largest_index;
2217 CafeRROutputInfo **outputs;
2218
2219 cdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width, &win_rect.height);
2220 cdk_window_get_origin (window, &win_rect.x, &win_rect.y);
2221
2222 largest_area = 0;
2223 largest_index = -1;
2224
2225 outputs = cafe_rr_config_get_outputs (configuration);
2226 for (i = 0; outputs[i] != NULL((void*)0); i++)
2227 {
2228 CdkRectangle output_rect, intersection;
2229
2230 cafe_rr_output_info_get_geometry (outputs[i], &output_rect.x, &output_rect.y, &output_rect.width, &output_rect.height);
2231
2232 if (cafe_rr_output_info_is_connected (outputs[i]) && cdk_rectangle_intersect (&win_rect, &output_rect, &intersection))
2233 {
2234 int area;
2235
2236 area = intersection.width * intersection.height;
2237 if (area > largest_area)
2238 {
2239 largest_area = area;
2240 largest_index = i;
2241 }
2242 }
2243 }
2244
2245 if (largest_index != -1)
2246 return outputs[largest_index];
2247 else
2248 return get_nearest_output (configuration,
2249 win_rect.x + win_rect.width / 2,
2250 win_rect.y + win_rect.height / 2);
2251}
2252
2253/* We select the current output, i.e. select the one being edited, based on
2254 * which output is showing the configuration dialog.
2255 */
2256static void
2257select_current_output_from_dialog_position (App *app)
2258{
2259 if (ctk_widget_get_realized (app->dialog))
2260 app->current_output = get_output_for_window (app->current_configuration, ctk_widget_get_window (app->dialog));
2261 else
2262 app->current_output = NULL((void*)0);
2263
2264 rebuild_gui (app);
2265}
2266
2267/* This is a CtkWidget::map-event handler. We wait for the display-properties
2268 * dialog to be mapped, and then we select the output which corresponds to the
2269 * monitor on which the dialog is being shown.
2270 */
2271static gboolean
2272dialog_map_event_cb (CtkWidget *widget, CdkEventAny *event, gpointer data)
2273{
2274 App *app = data;
2275
2276 select_current_output_from_dialog_position (app);
2277 return FALSE(0);
2278}
2279
2280static void
2281apply_button_clicked_cb (CtkButton *button, gpointer data)
2282{
2283 App *app = data;
2284
2285 /* We simply store the timestamp at which the Apply button was clicked.
2286 * We'll just wait for the dialog to return from ctk_dialog_run(), and
2287 * *then* use the timestamp when applying the RANDR configuration.
2288 */
2289
2290 app->apply_button_clicked_timestamp = ctk_get_current_event_time ();
2291}
2292
2293static void
2294success_dialog_for_make_default (App *app)
2295{
2296 CtkWidget *dialog;
2297
2298 dialog = ctk_message_dialog_new (CTK_WINDOW (app->dialog)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->dialog)), ((ctk_window_get_type ()))))))
,
2299 CTK_DIALOG_MODAL,
2300 CTK_MESSAGE_INFO,
2301 CTK_BUTTONS_OK,
2302 _("The monitor configuration has been saved")gettext ("The monitor configuration has been saved"));
2303 ctk_message_dialog_format_secondary_text (CTK_MESSAGE_DIALOG (dialog)((((CtkMessageDialog*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((dialog)), ((ctk_message_dialog_get_type ())
)))))
,
2304 _("This configuration will be used the next time someone logs in.")gettext ("This configuration will be used the next time someone logs in."
)
);
2305
2306 ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
);
2307 ctk_widget_destroy (dialog);
2308}
2309
2310static void
2311error_dialog_for_make_default (App *app, const char *error_text)
2312{
2313 error_message (app, _("Could not set the default configuration for monitors")gettext ("Could not set the default configuration for monitors"
)
, error_text);
2314}
2315
2316static void
2317make_default (App *app)
2318{
2319 char *command_line;
2320 char *source_filename;
2321 char *dest_filename;
2322 char *dest_basename;
2323 char *std_error;
2324 gint exit_status;
2325 GError *error;
2326
2327 if (!sanitize_and_save_configuration (app))
2328 return;
2329
2330 dest_filename = g_settings_get_string (app->settings, DEFAULT_CONFIGURATION_FILE_KEY"default-configuration-file");
2331 if (!dest_filename)
2332 return; /* FIXME: present an error? */
2333
2334 dest_basename = g_path_get_basename (dest_filename);
2335
2336 source_filename = cafe_rr_config_get_intended_filename ();
2337
2338 command_line = g_strdup_printf ("pkexec %s/cafe-display-properties-install-systemwide %s %s",
2339 SBINDIR"/usr/sbin",
2340 source_filename,
2341 dest_basename);
2342
2343 error = NULL((void*)0);
2344 if (!g_spawn_command_line_sync (command_line, NULL((void*)0), &std_error, &exit_status, &error))
2345 {
2346 error_dialog_for_make_default (app, error->message);
2347 g_error_free (error);
2348 }
2349 else if (!WIFEXITED (exit_status)(((exit_status) & 0x7f) == 0) || WEXITSTATUS (exit_status)(((exit_status) & 0xff00) >> 8) != 0)
2350 {
2351 error_dialog_for_make_default (app, std_error);
2352 }
2353 else
2354 {
2355 success_dialog_for_make_default (app);
2356 }
2357
2358 g_free (std_error);
2359 g_free (dest_filename);
2360 g_free (dest_basename);
2361 g_free (source_filename);
2362 g_free (command_line);
2363}
2364
2365static CtkWidget*
2366_ctk_builder_get_widget (CtkBuilder *builder, const gchar *name)
2367{
2368 return CTK_WIDGET (ctk_builder_get_object (builder, name))((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((ctk_builder_get_object (builder, name))), ((ctk_widget_get_type
()))))))
;
2369}
2370
2371static void
2372run_application (App *app)
2373{
2374 CtkBuilder *builder;
2375 CtkWidget *align;
2376 GError *error = NULL((void*)0);
2377
2378 builder = ctk_builder_new ();
2379
2380 if (ctk_builder_add_from_resource (builder, "/org/cafe/ccc/display/display-capplet.ui", &error) == 0)
2381 {
2382 g_warning ("Could not parse UI definition: %s", error->message);
2383 g_error_free (error);
2384 g_object_unref (builder);
2385 return;
2386 }
2387
2388 app->screen = cafe_rr_screen_new (cdk_screen_get_default (), &error);
2389 g_signal_connect (app->screen, "changed", G_CALLBACK (on_screen_changed), app)g_signal_connect_data ((app->screen), ("changed"), (((GCallback
) (on_screen_changed))), (app), ((void*)0), (GConnectFlags) 0
)
;
2390 if (!app->screen)
2391 {
2392 error_message (NULL((void*)0), _("Could not get screen information")gettext ("Could not get screen information"), error->message);
2393 g_error_free (error);
2394 g_object_unref (builder);
2395 return;
2396 }
2397
2398 app->settings = g_settings_new (CSD_XRANDR_SCHEMA"org.cafe.SettingsDaemon.plugins.xrandr");
2399
2400 app->dialog = _ctk_builder_get_widget (builder, "dialog");
2401 g_signal_connect_after (app->dialog, "map-event",g_signal_connect_data ((app->dialog), ("map-event"), (((GCallback
) (dialog_map_event_cb))), (app), ((void*)0), G_CONNECT_AFTER
)
2402 G_CALLBACK (dialog_map_event_cb), app)g_signal_connect_data ((app->dialog), ("map-event"), (((GCallback
) (dialog_map_event_cb))), (app), ((void*)0), G_CONNECT_AFTER
)
;
2403
2404 ctk_window_set_default_icon_name ("preferences-desktop-display");
2405 ctk_window_set_icon_name (CTK_WINDOW (app->dialog)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->dialog)), ((ctk_window_get_type ()))))))
,
2406 "preferences-desktop-display");
2407
2408 app->current_monitor_event_box = _ctk_builder_get_widget (builder,
2409 "current_monitor_event_box");
2410 app->current_monitor_label = _ctk_builder_get_widget (builder,
2411 "current_monitor_label");
2412
2413 app->monitor_on_radio = _ctk_builder_get_widget (builder,
2414 "monitor_on_radio");
2415 app->monitor_off_radio = _ctk_builder_get_widget (builder,
2416 "monitor_off_radio");
2417 g_signal_connect (app->monitor_on_radio, "toggled",g_signal_connect_data ((app->monitor_on_radio), ("toggled"
), (((GCallback) (monitor_on_off_toggled_cb))), (app), ((void
*)0), (GConnectFlags) 0)
2418 G_CALLBACK (monitor_on_off_toggled_cb), app)g_signal_connect_data ((app->monitor_on_radio), ("toggled"
), (((GCallback) (monitor_on_off_toggled_cb))), (app), ((void
*)0), (GConnectFlags) 0)
;
2419 g_signal_connect (app->monitor_off_radio, "toggled",g_signal_connect_data ((app->monitor_off_radio), ("toggled"
), (((GCallback) (monitor_on_off_toggled_cb))), (app), ((void
*)0), (GConnectFlags) 0)
2420 G_CALLBACK (monitor_on_off_toggled_cb), app)g_signal_connect_data ((app->monitor_off_radio), ("toggled"
), (((GCallback) (monitor_on_off_toggled_cb))), (app), ((void
*)0), (GConnectFlags) 0)
;
2421
2422 app->resolution_combo = _ctk_builder_get_widget (builder,
2423 "resolution_combo");
2424 g_signal_connect (app->resolution_combo, "changed",g_signal_connect_data ((app->resolution_combo), ("changed"
), (((GCallback) (on_resolution_changed))), (app), ((void*)0)
, (GConnectFlags) 0)
2425 G_CALLBACK (on_resolution_changed), app)g_signal_connect_data ((app->resolution_combo), ("changed"
), (((GCallback) (on_resolution_changed))), (app), ((void*)0)
, (GConnectFlags) 0)
;
2426
2427 app->refresh_combo = _ctk_builder_get_widget (builder, "refresh_combo");
2428 g_signal_connect (app->refresh_combo, "changed",g_signal_connect_data ((app->refresh_combo), ("changed"), (
((GCallback) (on_rate_changed))), (app), ((void*)0), (GConnectFlags
) 0)
2429 G_CALLBACK (on_rate_changed), app)g_signal_connect_data ((app->refresh_combo), ("changed"), (
((GCallback) (on_rate_changed))), (app), ((void*)0), (GConnectFlags
) 0)
;
2430
2431 app->rotation_combo = _ctk_builder_get_widget (builder, "rotation_combo");
2432 g_signal_connect (app->rotation_combo, "changed",g_signal_connect_data ((app->rotation_combo), ("changed"),
(((GCallback) (on_rotation_changed))), (app), ((void*)0), (GConnectFlags
) 0)
2433 G_CALLBACK (on_rotation_changed), app)g_signal_connect_data ((app->rotation_combo), ("changed"),
(((GCallback) (on_rotation_changed))), (app), ((void*)0), (GConnectFlags
) 0)
;
2434
2435 app->clone_checkbox = _ctk_builder_get_widget (builder, "clone_checkbox");
2436 g_signal_connect (app->clone_checkbox, "toggled",g_signal_connect_data ((app->clone_checkbox), ("toggled"),
(((GCallback) (on_clone_changed))), (app), ((void*)0), (GConnectFlags
) 0)
2437 G_CALLBACK (on_clone_changed), app)g_signal_connect_data ((app->clone_checkbox), ("toggled"),
(((GCallback) (on_clone_changed))), (app), ((void*)0), (GConnectFlags
) 0)
;
2438
2439 g_signal_connect (_ctk_builder_get_widget (builder, "detect_displays_button"),g_signal_connect_data ((_ctk_builder_get_widget (builder, "detect_displays_button"
)), ("clicked"), (((GCallback) (on_detect_displays))), (app),
((void*)0), (GConnectFlags) 0)
2440 "clicked", G_CALLBACK (on_detect_displays), app)g_signal_connect_data ((_ctk_builder_get_widget (builder, "detect_displays_button"
)), ("clicked"), (((GCallback) (on_detect_displays))), (app),
((void*)0), (GConnectFlags) 0)
;
2441
2442 app->primary_button = _ctk_builder_get_widget (builder, "primary_button");
2443
2444 g_signal_connect (app->primary_button, "clicked", G_CALLBACK (set_primary), app)g_signal_connect_data ((app->primary_button), ("clicked"),
(((GCallback) (set_primary))), (app), ((void*)0), (GConnectFlags
) 0)
;
2445
2446 app->show_icon_checkbox = _ctk_builder_get_widget (builder,
2447 "show_notification_icon");
2448
2449 ctk_toggle_button_set_active (CTK_TOGGLE_BUTTON (app->show_icon_checkbox)((((CtkToggleButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->show_icon_checkbox)), ((ctk_toggle_button_get_type
()))))))
,
2450 g_settings_get_boolean (app->settings, SHOW_ICON_KEY"show-notification-icon"));
2451
2452 g_signal_connect (app->show_icon_checkbox, "toggled", G_CALLBACK (on_show_icon_toggled), app)g_signal_connect_data ((app->show_icon_checkbox), ("toggled"
), (((GCallback) (on_show_icon_toggled))), (app), ((void*)0),
(GConnectFlags) 0)
;
2453
2454 app->panel_checkbox = _ctk_builder_get_widget (builder, "panel_checkbox");
2455
2456 make_text_combo (app->resolution_combo, 4);
2457 make_text_combo (app->refresh_combo, 3);
2458 make_text_combo (app->rotation_combo, -1);
2459
2460 g_assert (app->panel_checkbox)do { if (app->panel_checkbox) ; else g_assertion_message_expr
("display-properties", "xrandr-capplet.c", 2460, ((const char
*) (__func__)), "app->panel_checkbox"); } while (0)
;
2461
2462 /* Scroll Area */
2463 app->area = (CtkWidget *)foo_scroll_area_new ();
2464
2465 g_object_set_data (G_OBJECT (app->area)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->area)), (((GType) ((20) << (2))))))))
, "app", app);
2466
2467 set_monitors_tooltip (app, FALSE(0));
2468
2469 /* FIXME: this should be computed dynamically */
2470 foo_scroll_area_set_min_size (FOO_SCROLL_AREA (app->area)((((FooScrollArea*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->area)), ((foo_scroll_area_get_type ()))))))
, -1, 200);
2471 ctk_widget_show (app->area);
2472 g_signal_connect (app->area, "paint",g_signal_connect_data ((app->area), ("paint"), (((GCallback
) (on_area_paint))), (app), ((void*)0), (GConnectFlags) 0)
2473 G_CALLBACK (on_area_paint), app)g_signal_connect_data ((app->area), ("paint"), (((GCallback
) (on_area_paint))), (app), ((void*)0), (GConnectFlags) 0)
;
2474 g_signal_connect (app->area, "viewport_changed",g_signal_connect_data ((app->area), ("viewport_changed"), (
((GCallback) (on_viewport_changed))), (app), ((void*)0), (GConnectFlags
) 0)
2475 G_CALLBACK (on_viewport_changed), app)g_signal_connect_data ((app->area), ("viewport_changed"), (
((GCallback) (on_viewport_changed))), (app), ((void*)0), (GConnectFlags
) 0)
;
2476
2477 align = _ctk_builder_get_widget (builder, "align");
2478
2479 ctk_container_add (CTK_CONTAINER (align)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((align)), ((ctk_container_get_type ()))))))
, app->area);
2480
2481 app->apply_button = _ctk_builder_get_widget (builder, "apply_button");
2482 g_signal_connect (app->apply_button, "clicked",g_signal_connect_data ((app->apply_button), ("clicked"), (
((GCallback) (apply_button_clicked_cb))), (app), ((void*)0), (
GConnectFlags) 0)
2483 G_CALLBACK (apply_button_clicked_cb), app)g_signal_connect_data ((app->apply_button), ("clicked"), (
((GCallback) (apply_button_clicked_cb))), (app), ((void*)0), (
GConnectFlags) 0)
;
2484
2485 on_screen_changed (app->screen, app);
2486
2487 g_object_unref (builder);
2488
2489restart:
2490 switch (ctk_dialog_run (CTK_DIALOG (app->dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->dialog)), ((ctk_dialog_get_type ()))))))
))
2491 {
2492 default:
2493 /* Fall Through */
2494 case CTK_RESPONSE_DELETE_EVENT:
2495 case CTK_RESPONSE_CLOSE:
2496#if 0
2497 g_debug ("Close");
2498#endif
2499 break;
2500
2501 case CTK_RESPONSE_HELP:
2502 ctk_show_uri_on_window (CTK_DIALOG (app->dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((app->dialog)), ((ctk_dialog_get_type ()))))))
,
2503 "help:cafe-user-guide/goscustdesk-70",
2504 ctk_get_current_event_time (),
2505 &error);
2506 if (error)
2507 {
2508 error_message (app, _("Could not open help content")gettext ("Could not open help content"), error->message);
2509 g_error_free (error);
2510 }
2511 goto restart;
2512 break;
2513
2514 case CTK_RESPONSE_APPLY:
2515 apply (app);
2516 goto restart;
2517 break;
2518
2519 case RESPONSE_MAKE_DEFAULT:
2520 make_default (app);
2521 goto restart;
2522 break;
2523 }
2524
2525 ctk_widget_destroy (app->dialog);
2526 g_object_unref (app->screen);
2527 g_object_unref (app->settings);
2528}
2529
2530int
2531main (int argc, char **argv)
2532{
2533 App *app;
2534
2535 capplet_init (NULL((void*)0), &argc, &argv);
2536
2537 app = g_new0 (App, 1)((App *) g_malloc0_n ((1), sizeof (App)));
2538
2539 g_object_set (ctk_settings_get_default (), "ctk-button-images", TRUE(!(0)), NULL((void*)0));
2540
2541 run_application (app);
2542
2543 g_free (app);
2544
2545 return 0;
2546}