Bug Summary

File:plugins/xrandr/csd_xrandr-manager.c
Warning:line 820, column 25
Value stored to 'best_height' is never read

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 csd_xrandr-manager.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 -fhalf-no-semantic-interposition -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 -fdebug-compilation-dir=/rootdir/plugins/xrandr -fcoverage-compilation-dir=/rootdir/plugins/xrandr -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I ../.. -I ../../cafe-settings-daemon -D BINDIR="/usr/bin" -D CAFE_SETTINGS_LOCALEDIR="/usr/share/locale" -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/sysprof-6 -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/gdk-pixbuf-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libpng16 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/cafe-desktop-2.0 -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/sysprof-6 -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/startup-notification-1.0 -I /usr/include/dconf -D PIC -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/15/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -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.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/2025-10-12-101237-64225-1 -x c csd_xrandr-manager.c
1/*
2 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
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 */
20
21#include "config.h"
22
23#include <sys/types.h>
24#include <sys/wait.h>
25#include <sys/stat.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <unistd.h>
29#include <string.h>
30#include <errno(*__errno_location ()).h>
31
32#include <locale.h>
33
34#include <glib.h>
35#include <glib/gi18n.h>
36#include <cdk/cdk.h>
37#include <cdk/cdkx.h>
38#include <ctk/ctk.h>
39#include <gio/gio.h>
40#include <dbus/dbus-glib.h>
41
42#define CAFE_DESKTOP_USE_UNSTABLE_API
43#include <libcafe-desktop/cafe-rr-config.h>
44#include <libcafe-desktop/cafe-rr.h>
45#include <libcafe-desktop/cafe-rr-labeler.h>
46#include <libcafe-desktop/cafe-desktop-utils.h>
47
48#ifdef HAVE_LIBNOTIFY1
49#include <libnotify/notify.h>
50#endif
51
52#ifdef HAVE_RDA
53#include <rda/rda.h>
54#endif
55
56#include "cafe-settings-profile.h"
57#include "csd_xrandr-manager.h"
58
59#define CONF_SCHEMA"org.cafe.SettingsDaemon.plugins.xrandr" "org.cafe.SettingsDaemon.plugins.xrandr"
60#define CONF_KEY_SHOW_NOTIFICATION_ICON"show-notification-icon" "show-notification-icon"
61#define CONF_KEY_USE_XORG_MONITOR_SETTINGS"use-xorg-monitor-settings" "use-xorg-monitor-settings"
62#define CONF_KEY_TURN_ON_EXTERNAL_MONITORS_AT_STARTUP"turn-on-external-monitors-at-startup" "turn-on-external-monitors-at-startup"
63#define CONF_KEY_TURN_ON_LAPTOP_MONITOR_AT_STARTUP"turn-on-laptop-monitor-at-startup" "turn-on-laptop-monitor-at-startup"
64#define CONF_KEY_DEFAULT_CONFIGURATION_FILE"default-configuration-file" "default-configuration-file"
65
66#define VIDEO_KEYSYM"XF86Display" "XF86Display"
67#define ROTATE_KEYSYM"XF86RotateWindows" "XF86RotateWindows"
68
69/* Number of seconds that the confirmation dialog will last before it resets the
70 * RANDR configuration to its old state.
71 */
72#define CONFIRMATION_DIALOG_SECONDS30 30
73
74/* name of the icon files (csd_xrandr.svg, etc.) */
75#define CSD_XRANDR_ICON_NAME"csd_xrandr" "csd_xrandr"
76
77/* executable of the control center's display configuration capplet */
78#define CSD_XRANDR_DISPLAY_CAPPLET"cafe-display-properties" "cafe-display-properties"
79
80#define CSD_DBUS_PATH"/org/cafe/SettingsDaemon" "/org/cafe/SettingsDaemon"
81#define CSD_DBUS_NAME"org.cafe.SettingsDaemon" "org.cafe.SettingsDaemon"
82#define CSD_XRANDR_DBUS_PATH"/org/cafe/SettingsDaemon" "/XRANDR" CSD_DBUS_PATH"/org/cafe/SettingsDaemon" "/XRANDR"
83#define CSD_XRANDR_DBUS_NAME"org.cafe.SettingsDaemon" ".XRANDR" CSD_DBUS_NAME"org.cafe.SettingsDaemon" ".XRANDR"
84
85struct CsdXrandrManagerPrivate
86{
87 DBusGConnection *dbus_connection;
88
89 /* Key code of the XF86Display key (Fn-F7 on Thinkpads, Fn-F4 on HP machines, etc.) */
90 guint switch_video_mode_keycode;
91
92 /* Key code of the XF86RotateWindows key (present on some tablets) */
93 guint rotate_windows_keycode;
94
95 CafeRRScreen *rw_screen;
96 gboolean running;
97
98 CtkStatusIcon *status_icon;
99 CtkWidget *popup_menu;
100 CafeRRConfig *configuration;
101 CafeRRLabeler *labeler;
102 GSettings *settings;
103
104 /* fn-F7 status */
105 int current_fn_f7_config; /* -1 if no configs */
106 CafeRRConfig **fn_f7_configs; /* NULL terminated, NULL if there are no configs */
107
108 /* Last time at which we got a "screen got reconfigured" event; see on_randr_event() */
109 guint32 last_config_timestamp;
110};
111
112static const CafeRRRotation possible_rotations[] = {
113 CAFE_RR_ROTATION_0,
114 CAFE_RR_ROTATION_90,
115 CAFE_RR_ROTATION_180,
116 CAFE_RR_ROTATION_270
117 /* We don't allow REFLECT_X or REFLECT_Y for now, as cafe-display-properties doesn't allow them, either */
118};
119
120static void csd_xrandr_manager_finalize (GObject *object);
121
122static void error_message (CsdXrandrManager *mgr, const char *primary_text, GError *error_to_display, const char *secondary_text);
123
124static void status_icon_popup_menu (CsdXrandrManager *manager, guint button, guint32 timestamp);
125static void run_display_capplet (CtkWidget *widget);
126static void get_allowed_rotations_for_output (CafeRRConfig *config,
127 CafeRRScreen *rr_screen,
128 CafeRROutputInfo *output,
129 int *out_num_rotations,
130 CafeRRRotation *out_rotations);
131
132G_DEFINE_TYPE_WITH_PRIVATE (CsdXrandrManager, csd_xrandr_manager, G_TYPE_OBJECT)static void csd_xrandr_manager_init (CsdXrandrManager *self);
static void csd_xrandr_manager_class_init (CsdXrandrManagerClass
*klass); static GType csd_xrandr_manager_get_type_once (void
); static gpointer csd_xrandr_manager_parent_class = ((void*)
0); static gint CsdXrandrManager_private_offset; static void csd_xrandr_manager_class_intern_init
(gpointer klass) { csd_xrandr_manager_parent_class = g_type_class_peek_parent
(klass); if (CsdXrandrManager_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CsdXrandrManager_private_offset); csd_xrandr_manager_class_init
((CsdXrandrManagerClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer csd_xrandr_manager_get_instance_private
(CsdXrandrManager *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CsdXrandrManager_private_offset)))); } GType csd_xrandr_manager_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= csd_xrandr_manager_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType csd_xrandr_manager_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("CsdXrandrManager"
), sizeof (CsdXrandrManagerClass), (GClassInitFunc)(void (*)(
void)) csd_xrandr_manager_class_intern_init, sizeof (CsdXrandrManager
), (GInstanceInitFunc)(void (*)(void)) csd_xrandr_manager_init
, (GTypeFlags) 0); { {{ CsdXrandrManager_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CsdXrandrManagerPrivate)); };} } return
g_define_type_id; }
133
134static gpointer manager_object = NULL((void*)0);
135
136static FILE *log_file;
137
138static void
139log_open (void)
140{
141 char *toggle_filename;
142 char *log_filename;
143 struct stat st;
144
145 if (log_file)
146 return;
147
148 toggle_filename = g_build_filename (g_get_home_dir (), "csd_debug-randr", NULL((void*)0));
149 log_filename = g_build_filename (g_get_home_dir (), "csd_debug-randr.log", NULL((void*)0));
150
151 if (stat (toggle_filename, &st) != 0)
152 goto out;
153
154 log_file = fopen (log_filename, "a");
155
156 if (log_file && ftell (log_file) == 0)
157 fprintf (log_file, "To keep this log from being created, please rm ~/csd_debug-randr\n");
158
159out:
160 g_free (toggle_filename);
161 g_free (log_filename);
162}
163
164static void
165log_close (void)
166{
167 if (log_file) {
168 fclose (log_file);
169 log_file = NULL((void*)0);
170 }
171}
172
173static void
174log_msg (const char *format, ...)
175{
176 if (log_file) {
177 va_list args;
178
179 va_start (args, format)__builtin_va_start(args, format);
180 vfprintf (log_file, format, args);
181 va_end (args)__builtin_va_end(args);
182 }
183}
184
185static void
186log_output (CafeRROutputInfo *output)
187{
188 gchar *name = cafe_rr_output_info_get_name (output);
189 gchar *display_name = cafe_rr_output_info_get_display_name (output);
190
191 log_msg (" %s: ", name ? name : "unknown");
192
193 if (cafe_rr_output_info_is_connected (output)) {
194 if (cafe_rr_output_info_is_active (output)) {
195 int x, y, width, height;
196 cafe_rr_output_info_get_geometry (output, &x, &y, &width, &height);
197 log_msg ("%dx%d@%d +%d+%d",
198 width,
199 height,
200 cafe_rr_output_info_get_refresh_rate (output),
201 x,
202 y);
203 } else
204 log_msg ("off");
205 } else
206 log_msg ("disconnected");
207
208 if (display_name)
209 log_msg (" (%s)", display_name);
210
211 if (cafe_rr_output_info_get_primary (output))
212 log_msg (" (primary output)");
213
214 log_msg ("\n");
215}
216
217static void
218log_configuration (CafeRRConfig *config)
219{
220 int i;
221 CafeRROutputInfo **outputs = cafe_rr_config_get_outputs (config);
222
223 log_msg (" cloned: %s\n", cafe_rr_config_get_clone (config) ? "yes" : "no");
224
225 for (i = 0; outputs[i] != NULL((void*)0); i++)
226 log_output (outputs[i]);
227
228 if (i == 0)
229 log_msg (" no outputs!\n");
230}
231
232static char
233timestamp_relationship (guint32 a, guint32 b)
234{
235 if (a < b)
236 return '<';
237 else if (a > b)
238 return '>';
239 else
240 return '=';
241}
242
243static void
244log_screen (CafeRRScreen *screen)
245{
246 CafeRRConfig *config;
247 int min_w, min_h, max_w, max_h;
248 guint32 change_timestamp, config_timestamp;
249
250 if (!log_file)
251 return;
252
253 config = cafe_rr_config_new_current (screen, NULL((void*)0));
254
255 cafe_rr_screen_get_ranges (screen, &min_w, &max_w, &min_h, &max_h);
256 cafe_rr_screen_get_timestamps (screen, &change_timestamp, &config_timestamp);
257
258 log_msg (" Screen min(%d, %d), max(%d, %d), change=%u %c config=%u\n",
259 min_w, min_h,
260 max_w, max_h,
261 change_timestamp,
262 timestamp_relationship (change_timestamp, config_timestamp),
263 config_timestamp);
264
265 log_configuration (config);
266 g_object_unref (config);
267}
268
269static void
270log_configurations (CafeRRConfig **configs)
271{
272 int i;
273
274 if (!configs) {
275 log_msg (" No configurations\n");
276 return;
277 }
278
279 for (i = 0; configs[i]; i++) {
280 log_msg (" Configuration %d\n", i);
281 log_configuration (configs[i]);
282 }
283}
284
285static void
286show_timestamps_dialog (CsdXrandrManager *manager G_GNUC_UNUSED__attribute__ ((__unused__)),
287 const char *msg G_GNUC_UNUSED__attribute__ ((__unused__)))
288{
289#if 1
290 return;
291#else
292 struct CsdXrandrManagerPrivate *priv = manager->priv;
293 CtkWidget *dialog;
294 guint32 change_timestamp, config_timestamp;
295 static int serial;
296
297 cafe_rr_screen_get_timestamps (priv->rw_screen, &change_timestamp, &config_timestamp);
298
299 dialog = ctk_message_dialog_new (NULL((void*)0),
300 0,
301 CTK_MESSAGE_INFO,
302 CTK_BUTTONS_CLOSE,
303 "RANDR timestamps (%d):\n%s\nchange: %u\nconfig: %u",
304 serial++,
305 msg,
306 change_timestamp,
307 config_timestamp);
308 g_signal_connect (dialog, "response",g_signal_connect_data ((dialog), ("response"), (((GCallback) (
ctk_widget_destroy))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
309 G_CALLBACK (ctk_widget_destroy), NULL)g_signal_connect_data ((dialog), ("response"), (((GCallback) (
ctk_widget_destroy))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
310 ctk_widget_show (dialog);
311#endif
312}
313
314/* This function centralizes the use of cafe_rr_config_apply_from_filename_with_time().
315 *
316 * Optionally filters out CAFE_RR_ERROR_NO_MATCHING_CONFIG from
317 * cafe_rr_config_apply_from_filename_with_time(), since that is not usually an error.
318 */
319static gboolean
320apply_configuration_from_filename (CsdXrandrManager *manager,
321 const char *filename,
322 gboolean no_matching_config_is_an_error,
323 guint32 timestamp,
324 GError **error)
325{
326 struct CsdXrandrManagerPrivate *priv = manager->priv;
327 GError *my_error;
328 gboolean success;
329 char *str;
330
331 str = g_strdup_printf ("Applying %s with timestamp %d", filename, timestamp);
332 show_timestamps_dialog (manager, str);
333 g_free (str);
334
335 my_error = NULL((void*)0);
336 success = cafe_rr_config_apply_from_filename_with_time (priv->rw_screen, filename, timestamp, &my_error);
337 if (success)
338 return TRUE(!(0));
339
340 if (g_error_matches (my_error, CAFE_RR_ERROR(cafe_rr_error_quark ()), CAFE_RR_ERROR_NO_MATCHING_CONFIG)) {
341 if (no_matching_config_is_an_error)
342 goto fail;
343
344 /* This is not an error; the user probably changed his monitors
345 * and so they don't match any of the stored configurations.
346 */
347 g_error_free (my_error);
348 return TRUE(!(0));
349 }
350
351fail:
352 g_propagate_error (error, my_error);
353 return FALSE(0);
354}
355
356/* This function centralizes the use of cafe_rr_config_apply_with_time().
357 *
358 * Applies a configuration and displays an error message if an error happens.
359 * We just return whether setting the configuration succeeded.
360 */
361static gboolean
362apply_configuration_and_display_error (CsdXrandrManager *manager, CafeRRConfig *config, guint32 timestamp)
363{
364 CsdXrandrManagerPrivate *priv = manager->priv;
365 GError *error;
366 gboolean success;
367
368 error = NULL((void*)0);
369 success = cafe_rr_config_apply_with_time (config, priv->rw_screen, timestamp, &error);
370 if (!success) {
371 log_msg ("Could not switch to the following configuration (timestamp %u): %s\n", timestamp, error->message);
372 log_configuration (config);
373 error_message (manager, _("Could not switch the monitor configuration")gettext ("Could not switch the monitor configuration"), error, NULL((void*)0));
374 g_error_free (error);
375 }
376
377 return success;
378}
379
380static void
381restore_backup_configuration_without_messages (const char *backup_filename, const char *intended_filename)
382{
383 backup_filename = cafe_rr_config_get_backup_filename ();
384 rename (backup_filename, intended_filename);
385}
386
387static void
388restore_backup_configuration (CsdXrandrManager *manager, const char *backup_filename, const char *intended_filename, guint32 timestamp)
389{
390 int saved_errno;
391
392 if (rename (backup_filename, intended_filename) == 0) {
393 GError *error;
394
395 error = NULL((void*)0);
396 if (!apply_configuration_from_filename (manager, intended_filename, FALSE(0), timestamp, &error)) {
397 error_message (manager, _("Could not restore the display's configuration")gettext ("Could not restore the display's configuration"), error, NULL((void*)0));
398
399 if (error)
400 g_error_free (error);
401 }
402
403 return;
404 }
405
406 saved_errno = errno(*__errno_location ());
407
408 /* ENOENT means the original file didn't exist. That is *not* an error;
409 * the backup was not created because there wasn't even an original
410 * monitors.xml (such as on a first-time login). Note that *here* there
411 * is a "didn't work" monitors.xml, so we must delete that one.
412 */
413 if (saved_errno == ENOENT2)
414 unlink (intended_filename);
415 else {
416 char *msg;
417
418 msg = g_strdup_printf ("Could not rename %s to %s: %s",
419 backup_filename, intended_filename,
420 g_strerror (saved_errno));
421 error_message (manager,
422 _("Could not restore the display's configuration from a backup")gettext ("Could not restore the display's configuration from a backup"
)
,
423 NULL((void*)0),
424 msg);
425 g_free (msg);
426 }
427
428 unlink (backup_filename);
429}
430
431typedef struct {
432 CsdXrandrManager *manager;
433 CtkWidget *dialog;
434
435 int countdown;
436 int response_id;
437} TimeoutDialog;
438
439static void
440print_countdown_text (TimeoutDialog *timeout)
441{
442 ctk_message_dialog_format_secondary_text (CTK_MESSAGE_DIALOG (timeout->dialog)((((CtkMessageDialog*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((timeout->dialog)), ((ctk_message_dialog_get_type
()))))))
,
443 ngettext ("The display will be reset to its previous configuration in %d second",
444 "The display will be reset to its previous configuration in %d seconds",
445 timeout->countdown),
446 timeout->countdown);
447}
448
449static gboolean
450timeout_cb (gpointer data)
451{
452 TimeoutDialog *timeout = data;
453
454 timeout->countdown--;
455
456 if (timeout->countdown == 0) {
457 timeout->response_id = CTK_RESPONSE_CANCEL;
458 ctk_main_quit ();
459 } else {
460 print_countdown_text (timeout);
461 }
462
463 return TRUE(!(0));
464}
465
466static void
467timeout_response_cb (CtkDialog *dialog G_GNUC_UNUSED__attribute__ ((__unused__)),
468 int response_id,
469 gpointer data)
470{
471 TimeoutDialog *timeout = data;
472
473 if (response_id == CTK_RESPONSE_DELETE_EVENT) {
474 /* The user closed the dialog or pressed ESC, revert */
475 timeout->response_id = CTK_RESPONSE_CANCEL;
476 } else
477 timeout->response_id = response_id;
478
479 ctk_main_quit ();
480}
481
482static gboolean
483user_says_things_are_ok (CsdXrandrManager *manager, CdkWindow *parent_window)
484{
485 TimeoutDialog timeout;
486 guint timeout_id;
487
488 timeout.manager = manager;
489
490 timeout.dialog = ctk_message_dialog_new (NULL((void*)0),
491 CTK_DIALOG_MODAL,
492 CTK_MESSAGE_QUESTION,
493 CTK_BUTTONS_NONE,
494 _("Does the display look OK?")gettext ("Does the display look OK?"));
495
496 timeout.countdown = CONFIRMATION_DIALOG_SECONDS30;
497
498 print_countdown_text (&timeout);
499
500 ctk_window_set_icon_name (CTK_WINDOW (timeout.dialog)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((timeout.dialog)), ((ctk_window_get_type ()))))))
, "preferences-desktop-display");
501 ctk_dialog_add_button (CTK_DIALOG (timeout.dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((timeout.dialog)), ((ctk_dialog_get_type ()))))))
, _("_Restore Previous Configuration")gettext ("_Restore Previous Configuration"), CTK_RESPONSE_CANCEL);
502 ctk_dialog_add_button (CTK_DIALOG (timeout.dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((timeout.dialog)), ((ctk_dialog_get_type ()))))))
, _("_Keep This Configuration")gettext ("_Keep This Configuration"), CTK_RESPONSE_ACCEPT);
503 ctk_dialog_set_default_response (CTK_DIALOG (timeout.dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((timeout.dialog)), ((ctk_dialog_get_type ()))))))
, CTK_RESPONSE_ACCEPT); /* ah, the optimism */
504
505 g_signal_connect (timeout.dialog, "response",g_signal_connect_data ((timeout.dialog), ("response"), (((GCallback
) (timeout_response_cb))), (&timeout), ((void*)0), (GConnectFlags
) 0)
506 G_CALLBACK (timeout_response_cb),g_signal_connect_data ((timeout.dialog), ("response"), (((GCallback
) (timeout_response_cb))), (&timeout), ((void*)0), (GConnectFlags
) 0)
507 &timeout)g_signal_connect_data ((timeout.dialog), ("response"), (((GCallback
) (timeout_response_cb))), (&timeout), ((void*)0), (GConnectFlags
) 0)
;
508
509 ctk_widget_realize (timeout.dialog);
510
511 if (parent_window)
512 cdk_window_set_transient_for (ctk_widget_get_window (timeout.dialog), parent_window);
513
514 ctk_widget_show_all (timeout.dialog);
515 /* We don't use g_timeout_add_seconds() since we actually care that the user sees "real" second ticks in the dialog */
516 timeout_id = g_timeout_add (1000,
517 timeout_cb,
518 &timeout);
519 ctk_main ();
520
521 ctk_widget_destroy (timeout.dialog);
522 g_source_remove (timeout_id);
523
524 if (timeout.response_id == CTK_RESPONSE_ACCEPT)
525 return TRUE(!(0));
526 else
527 return FALSE(0);
528}
529
530struct confirmation {
531 CsdXrandrManager *manager;
532 CdkWindow *parent_window;
533 guint32 timestamp;
534};
535
536static gboolean
537confirm_with_user_idle_cb (gpointer data)
538{
539 struct confirmation *confirmation = data;
540 char *backup_filename;
541 char *intended_filename;
542
543 backup_filename = cafe_rr_config_get_backup_filename ();
544 intended_filename = cafe_rr_config_get_intended_filename ();
545
546 if (user_says_things_are_ok (confirmation->manager, confirmation->parent_window))
547 unlink (backup_filename);
548 else
549 restore_backup_configuration (confirmation->manager, backup_filename, intended_filename, confirmation->timestamp);
550
551 g_free (confirmation);
552
553 return FALSE(0);
554}
555
556static void
557queue_confirmation_by_user (CsdXrandrManager *manager, CdkWindow *parent_window, guint32 timestamp)
558{
559 struct confirmation *confirmation;
560
561 confirmation = g_new (struct confirmation, 1)((struct confirmation *) g_malloc_n ((1), sizeof (struct confirmation
)))
;
562 confirmation->manager = manager;
563 confirmation->parent_window = parent_window;
564 confirmation->timestamp = timestamp;
565
566 g_idle_add (confirm_with_user_idle_cb, confirmation);
567}
568
569static gboolean
570try_to_apply_intended_configuration (CsdXrandrManager *manager, CdkWindow *parent_window, guint32 timestamp, GError **error)
571{
572 char *backup_filename;
573 char *intended_filename;
574 gboolean result;
575
576 /* Try to apply the intended configuration */
577
578 backup_filename = cafe_rr_config_get_backup_filename ();
579 intended_filename = cafe_rr_config_get_intended_filename ();
580
581 result = apply_configuration_from_filename (manager, intended_filename, FALSE(0), timestamp, error);
582 if (!result) {
583 error_message (manager, _("The selected configuration for displays could not be applied")gettext ("The selected configuration for displays could not be applied"
)
, error ? *error : NULL((void*)0), NULL((void*)0));
584 restore_backup_configuration_without_messages (backup_filename, intended_filename);
585 goto out;
586 } else {
587 /* We need to return as quickly as possible, so instead of
588 * confirming with the user right here, we do it in an idle
589 * handler. The caller only expects a status for "could you
590 * change the RANDR configuration?", not "is the user OK with it
591 * as well?".
592 */
593 queue_confirmation_by_user (manager, parent_window, timestamp);
594 }
595
596out:
597 g_free (backup_filename);
598 g_free (intended_filename);
599
600 return result;
601}
602
603/* DBus method for org.cafe.SettingsDaemon.XRANDR ApplyConfiguration; see csd_xrandr-manager.xml for the interface definition */
604static gboolean
605csd_xrandr_manager_apply_configuration (CsdXrandrManager *manager,
606 GError **error)
607{
608 return try_to_apply_intended_configuration (manager, NULL((void*)0), CDK_CURRENT_TIME0L, error);
609}
610
611/* DBus method for org.cafe.SettingsDaemon.XRANDR_2 ApplyConfiguration; see csd_xrandr-manager.xml for the interface definition */
612static gboolean
613csd_xrandr_manager_2_apply_configuration (CsdXrandrManager *manager,
614 gint64 parent_window_id,
615 gint64 timestamp,
616 GError **error)
617{
618 CdkWindow *parent_window;
619 gboolean result;
620
621 if (parent_window_id != 0)
622 parent_window = cdk_x11_window_foreign_new_for_display (cdk_display_get_default (), (Window) parent_window_id);
623 else
624 parent_window = NULL((void*)0);
625
626 result = try_to_apply_intended_configuration (manager, parent_window, (guint32) timestamp, error);
627
628 if (parent_window)
629 g_object_unref (parent_window);
630
631 return result;
632}
633
634/* We include this after the definition of csd_xrandr_manager_apply_configuration() so the prototype will already exist */
635#include "csd_xrandr-manager-glue.h"
636
637static gboolean
638is_laptop (CafeRRScreen *screen, CafeRROutputInfo *output)
639{
640 CafeRROutput *rr_output;
641
642 rr_output = cafe_rr_screen_get_output_by_name (screen, cafe_rr_output_info_get_name (output));
643 return cafe_rr_output_is_laptop (rr_output);
644}
645
646static gboolean
647get_clone_size (CafeRRScreen *screen, int *width, int *height)
648{
649 CafeRRMode **modes = cafe_rr_screen_list_clone_modes (screen);
650 int best_w, best_h;
651 int i;
652
653 best_w = 0;
654 best_h = 0;
655
656 for (i = 0; modes[i] != NULL((void*)0); ++i) {
657 CafeRRMode *mode = modes[i];
658 int w, h;
659
660 w = cafe_rr_mode_get_width (mode);
661 h = cafe_rr_mode_get_height (mode);
662
663 if (w * h > best_w * best_h) {
664 best_w = w;
665 best_h = h;
666 }
667 }
668
669 if (best_w > 0 && best_h > 0) {
670 if (width)
671 *width = best_w;
672 if (height)
673 *height = best_h;
674
675 return TRUE(!(0));
676 }
677
678 return FALSE(0);
679}
680
681static void
682print_output (CafeRROutputInfo *info)
683{
684 int x, y, width, height;
685
686 g_print (" Output: %s attached to %s\n", cafe_rr_output_info_get_display_name (info), cafe_rr_output_info_get_name (info));
687 g_print (" status: %s\n", cafe_rr_output_info_is_active (info) ? "on" : "off");
688
689 cafe_rr_output_info_get_geometry (info, &x, &y, &width, &height);
690 g_print (" width: %d\n", width);
691 g_print (" height: %d\n", height);
692 g_print (" rate: %d\n", cafe_rr_output_info_get_refresh_rate (info));
693 g_print (" position: %d %d\n", x, y);
694}
695
696static void
697print_configuration (CafeRRConfig *config, const char *header)
698{
699 int i;
700 CafeRROutputInfo **outputs;
701
702 g_print ("=== %s Configuration ===\n", header);
703 if (!config) {
704 g_print (" none\n");
705 return;
706 }
707
708 outputs = cafe_rr_config_get_outputs (config);
709 for (i = 0; outputs[i] != NULL((void*)0); ++i)
710 print_output (outputs[i]);
711}
712
713static gboolean
714config_is_all_off (CafeRRConfig *config)
715{
716 int j;
717 CafeRROutputInfo **outputs;
718
719 outputs = cafe_rr_config_get_outputs (config);
720
721 for (j = 0; outputs[j] != NULL((void*)0); ++j) {
722 if (cafe_rr_output_info_is_active (outputs[j])) {
723 return FALSE(0);
724 }
725 }
726
727 return TRUE(!(0));
728}
729
730static CafeRRConfig *
731make_clone_setup (CafeRRScreen *screen)
732{
733 CafeRRConfig *result;
734 CafeRROutputInfo **outputs;
735 int width, height;
736 int i;
737
738 if (!get_clone_size (screen, &width, &height))
739 return NULL((void*)0);
740
741 result = cafe_rr_config_new_current (screen, NULL((void*)0));
742 outputs = cafe_rr_config_get_outputs (result);
743
744 for (i = 0; outputs[i] != NULL((void*)0); ++i) {
745 CafeRROutputInfo *info = outputs[i];
746
747 cafe_rr_output_info_set_active (info, FALSE(0));
748 if (cafe_rr_output_info_is_connected (info)) {
749 CafeRROutput *output =
750 cafe_rr_screen_get_output_by_name (screen, cafe_rr_output_info_get_name (info));
751 CafeRRMode **modes = cafe_rr_output_list_modes (output);
752 int j;
753 int best_rate = 0;
754
755 for (j = 0; modes[j] != NULL((void*)0); ++j) {
756 CafeRRMode *mode = modes[j];
757 int w, h;
758
759 w = cafe_rr_mode_get_width (mode);
760 h = cafe_rr_mode_get_height (mode);
761
762 if (w == width && h == height) {
763 best_rate = cafe_rr_mode_get_freq (mode);
764 }
765 }
766
767 if (best_rate > 0) {
768 cafe_rr_output_info_set_active (info, TRUE(!(0)));
769 cafe_rr_output_info_set_rotation (info, CAFE_RR_ROTATION_0);
770 cafe_rr_output_info_set_refresh_rate (info, best_rate);
771 cafe_rr_output_info_set_geometry (info, 0, 0, width, height);
772 }
773 }
774 }
775
776 if (config_is_all_off (result)) {
777 g_object_unref (result);
778 result = NULL((void*)0);
779 }
780
781 print_configuration (result, "clone setup");
782
783 return result;
784}
785
786static CafeRRMode *
787find_best_mode (CafeRROutput *output)
788{
789 CafeRRMode *preferred;
790 CafeRRMode **modes;
791 int best_size;
792 int best_width, best_height, best_rate;
793 int i;
794 CafeRRMode *best_mode;
795
796 preferred = cafe_rr_output_get_preferred_mode (output);
797 if (preferred)
798 return preferred;
799
800 modes = cafe_rr_output_list_modes (output);
801 if (!modes)
802 return NULL((void*)0);
803
804 best_size = best_width = best_height = best_rate = 0;
805 best_mode = NULL((void*)0);
806
807 for (i = 0; modes[i] != NULL((void*)0); i++) {
808 int w, h, r;
809 int size;
810
811 w = cafe_rr_mode_get_width (modes[i]);
812 h = cafe_rr_mode_get_height (modes[i]);
813 r = cafe_rr_mode_get_freq (modes[i]);
814
815 size = w * h;
816
817 if (size > best_size) {
818 best_size = size;
819 best_width = w;
820 best_height = h;
Value stored to 'best_height' is never read
821 best_rate = r;
822 best_mode = modes[i];
823 } else if (size == best_size) {
824 if (r > best_rate) {
825 best_rate = r;
826 best_mode = modes[i];
827 }
828 }
829 }
830
831 return best_mode;
832}
833
834static gboolean
835turn_on (CafeRRScreen *screen,
836 CafeRROutputInfo *info,
837 int x, int y)
838{
839 CafeRROutput *output = cafe_rr_screen_get_output_by_name (screen, cafe_rr_output_info_get_name (info));
840 CafeRRMode *mode = find_best_mode (output);
841
842 if (mode) {
843 cafe_rr_output_info_set_active (info, TRUE(!(0)));
844 cafe_rr_output_info_set_geometry (info, x, y, cafe_rr_mode_get_width (mode), cafe_rr_mode_get_height (mode));
845 cafe_rr_output_info_set_rotation (info, CAFE_RR_ROTATION_0);
846 cafe_rr_output_info_set_refresh_rate (info, cafe_rr_mode_get_freq (mode));
847
848 return TRUE(!(0));
849 }
850
851 return FALSE(0);
852}
853
854static CafeRRConfig *
855make_primary_only_setup (CafeRRScreen *screen)
856{
857 /*Leave all of the monitors turned on, just change from mirror to xinerama layout*/
858 CafeRRConfig *result = cafe_rr_config_new_current (screen, NULL((void*)0));
859 CafeRROutputInfo **outputs = cafe_rr_config_get_outputs (result);
860 int i, x, width,height;
861 x = 0;
862
863 for (i = 0; outputs[i] != NULL((void*)0); ++i) {
864 CafeRROutputInfo *info = outputs[i];
865 width = cafe_rr_output_info_get_preferred_width (info);
866 height = cafe_rr_output_info_get_preferred_height (info);
867 cafe_rr_output_info_set_geometry (info, x, 0, width, height);
868 cafe_rr_output_info_set_active (info, TRUE(!(0)));
869 x = x + width;
870 }
871
872 if (result && config_is_all_off (result)) {
873 g_object_unref (G_OBJECT (result)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((result)), (((GType) ((20) << (2))))))))
);
874 result = NULL((void*)0);
875 }
876
877 cafe_rr_config_set_clone (result, FALSE(0));
878 print_configuration (result, "Primary only setup");
879
880 return result;
881}
882
883static CafeRRConfig *
884make_laptop_setup (CafeRRScreen *screen)
885{
886 /* Turn on the laptop, disable everything else */
887 CafeRRConfig *result = cafe_rr_config_new_current (screen, NULL((void*)0));
888 CafeRROutputInfo **outputs = cafe_rr_config_get_outputs (result);
889 int i;
890
891 for (i = 0; outputs[i] != NULL((void*)0); ++i) {
892 CafeRROutputInfo *info = outputs[i];
893
894 if (is_laptop (screen, info)) {
895 if (!turn_on (screen, info, 0, 0)) {
896 g_object_unref (G_OBJECT (result)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((result)), (((GType) ((20) << (2))))))))
);
897 result = NULL((void*)0);
898 break;
899 }
900 }
901 else {
902 cafe_rr_output_info_set_active (info, FALSE(0));
903 }
904 }
905
906 if (result && config_is_all_off (result)) {
907 g_object_unref (G_OBJECT (result)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((result)), (((GType) ((20) << (2))))))))
);
908 result = NULL((void*)0);
909 }
910
911 print_configuration (result, "Laptop setup");
912
913 /* FIXME - Maybe we should return NULL if there is more than
914 * one connected "laptop" screen?
915 */
916 return result;
917}
918
919static int
920turn_on_and_get_rightmost_offset (CafeRRScreen *screen, CafeRROutputInfo *info, int x)
921{
922 if (turn_on (screen, info, x, 0)) {
923 int width;
924 cafe_rr_output_info_get_geometry (info, NULL((void*)0), NULL((void*)0), &width, NULL((void*)0));
925 x += width;
926 }
927
928 return x;
929}
930
931static CafeRRConfig *
932make_xinerama_setup (CafeRRScreen *screen)
933{
934 /* Turn on everything that has a preferred mode, and
935 * position it from left to right
936 */
937 CafeRRConfig *result = cafe_rr_config_new_current (screen, NULL((void*)0));
938 CafeRROutputInfo **outputs = cafe_rr_config_get_outputs (result);
939 int i;
940 int x;
941
942 x = 0;
943 for (i = 0; outputs[i] != NULL((void*)0); ++i) {
944 CafeRROutputInfo *info = outputs[i];
945
946 if (is_laptop (screen, info))
947 x = turn_on_and_get_rightmost_offset (screen, info, x);
948 }
949
950 for (i = 0; outputs[i] != NULL((void*)0); ++i) {
951 CafeRROutputInfo *info = outputs[i];
952
953 if (cafe_rr_output_info_is_connected (info) && !is_laptop (screen, info))
954 x = turn_on_and_get_rightmost_offset (screen, info, x);
955 }
956
957 if (config_is_all_off (result)) {
958 g_object_unref (G_OBJECT (result)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((result)), (((GType) ((20) << (2))))))))
);
959 result = NULL((void*)0);
960 }
961
962 print_configuration (result, "xinerama setup");
963
964 return result;
965}
966
967static CafeRRConfig *
968make_other_setup (CafeRRScreen *screen)
969{
970 /* Turn off all laptops, and make all external monitors clone
971 * from (0, 0)
972 */
973
974 CafeRRConfig *result = cafe_rr_config_new_current (screen, NULL((void*)0));
975 CafeRROutputInfo **outputs = cafe_rr_config_get_outputs (result);
976 int i;
977
978 for (i = 0; outputs[i] != NULL((void*)0); ++i) {
979 CafeRROutputInfo *info = outputs[i];
980
981 if (is_laptop (screen, info)) {
982 cafe_rr_output_info_set_active (info, FALSE(0));
983 }
984 else {
985 if (cafe_rr_output_info_is_connected (info))
986 turn_on (screen, info, 0, 0);
987 }
988 }
989
990 if (config_is_all_off (result)) {
991 g_object_unref (G_OBJECT (result)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((result)), (((GType) ((20) << (2))))))))
);
992 result = NULL((void*)0);
993 }
994
995 print_configuration (result, "other setup");
996
997 return result;
998}
999
1000static GPtrArray *
1001sanitize (CsdXrandrManager *manager, GPtrArray *array)
1002{
1003 int i;
1004 GPtrArray *new;
1005
1006 g_debug ("before sanitizing");
1007
1008 for (i = 0; i < array->len; ++i) {
1009 if (array->pdata[i]) {
1010 print_configuration (array->pdata[i], "before");
1011 }
1012 }
1013
1014
1015 /* Remove configurations that are duplicates of
1016 * configurations earlier in the cycle
1017 */
1018 for (i = 0; i < array->len; i++) {
1019 int j;
1020
1021 for (j = i + 1; j < array->len; j++) {
1022 CafeRRConfig *this = array->pdata[j];
1023 CafeRRConfig *other = array->pdata[i];
1024
1025 if (this && other && cafe_rr_config_equal (this, other)) {
1026 g_debug ("removing duplicate configuration");
1027 g_object_unref (this);
1028 array->pdata[j] = NULL((void*)0);
1029 break;
1030 }
1031 }
1032 }
1033
1034 for (i = 0; i < array->len; ++i) {
1035 CafeRRConfig *config = array->pdata[i];
1036
1037 if (config && config_is_all_off (config)) {
1038 g_debug ("removing configuration as all outputs are off");
1039 g_object_unref (array->pdata[i]);
1040 array->pdata[i] = NULL((void*)0);
1041 }
1042 }
1043
1044 /* Do a final sanitization pass. This will remove configurations that
1045 * don't fit in the framebuffer's Virtual size.
1046 */
1047
1048 for (i = 0; i < array->len; i++) {
1049 CafeRRConfig *config = array->pdata[i];
1050
1051 if (config) {
1052 GError *error;
1053
1054 error = NULL((void*)0);
1055 if (!cafe_rr_config_applicable (config, manager->priv->rw_screen, &error)) { /* NULL-GError */
1056 g_debug ("removing configuration which is not applicable because %s", error->message);
1057 g_error_free (error);
1058
1059 g_object_unref (config);
1060 array->pdata[i] = NULL((void*)0);
1061 }
1062 }
1063 }
1064
1065 /* Remove NULL configurations */
1066 new = g_ptr_array_new ();
1067
1068 for (i = 0; i < array->len; ++i) {
1069 if (array->pdata[i]) {
1070 g_ptr_array_add (new, array->pdata[i]);
1071 print_configuration (array->pdata[i], "Final");
1072 }
1073 }
1074
1075 if (new->len > 0) {
1076 g_ptr_array_add (new, NULL((void*)0));
1077 } else {
1078 g_ptr_array_free (new, TRUE(!(0)));
1079 new = NULL((void*)0);
1080 }
1081
1082 g_ptr_array_free (array, TRUE(!(0)));
1083
1084 return new;
1085}
1086
1087static void
1088generate_fn_f7_configs (CsdXrandrManager *mgr)
1089{
1090 GPtrArray *array = g_ptr_array_new ();
1091 CafeRRScreen *screen = mgr->priv->rw_screen;
1092
1093 g_debug ("Generating configurations");
1094
1095 /* Free any existing list of configurations */
1096 if (mgr->priv->fn_f7_configs) {
1097 int i;
1098
1099 for (i = 0; mgr->priv->fn_f7_configs[i] != NULL((void*)0); ++i)
1100 g_object_unref (mgr->priv->fn_f7_configs[i]);
1101 g_free (mgr->priv->fn_f7_configs);
1102
1103 mgr->priv->fn_f7_configs = NULL((void*)0);
1104 mgr->priv->current_fn_f7_config = -1;
1105 }
1106
1107 g_ptr_array_add (array, cafe_rr_config_new_current (screen, NULL((void*)0)));
1108 g_ptr_array_add (array, make_clone_setup (screen));
1109 g_ptr_array_add (array, make_xinerama_setup (screen));
1110 g_ptr_array_add (array, make_laptop_setup (screen));
1111 g_ptr_array_add (array, make_other_setup (screen));
1112
1113 array = sanitize (mgr, array);
1114
1115 if (array) {
1116 mgr->priv->fn_f7_configs = (CafeRRConfig **)g_ptr_array_free (array, FALSE(0));
1117 mgr->priv->current_fn_f7_config = 0;
1118 }
1119}
1120
1121static void
1122error_message (CsdXrandrManager *mgr, const char *primary_text, GError *error_to_display, const char *secondary_text)
1123{
1124#ifdef HAVE_LIBNOTIFY1
1125 CsdXrandrManagerPrivate *priv = mgr->priv;
1126 NotifyNotification *notification;
1127
1128 g_assert (error_to_display == NULL || secondary_text == NULL)do { if (error_to_display == ((void*)0) || secondary_text == (
(void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "csd_xrandr-manager.c"
, 1128, ((const char*) (__func__)), "error_to_display == NULL || secondary_text == NULL"
); } while (0)
;
1129
1130 if (priv->status_icon)
1131 notification = notify_notification_new (primary_text,
1132 error_to_display ? error_to_display->message : secondary_text,
1133 ctk_status_icon_get_icon_name(priv->status_icon));
1134 else
1135 notification = notify_notification_new (primary_text,
1136 error_to_display ? error_to_display->message : secondary_text,
1137 CSD_XRANDR_ICON_NAME"csd_xrandr");
1138
1139 notify_notification_show (notification, NULL((void*)0)); /* NULL-GError */
1140#else
1141 CtkWidget *dialog;
1142
1143 dialog = ctk_message_dialog_new (NULL((void*)0), CTK_DIALOG_MODAL, CTK_MESSAGE_ERROR, CTK_BUTTONS_CLOSE,
1144 "%s", primary_text);
1145 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",
1146 error_to_display ? error_to_display->message : secondary_text);
1147
1148 ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
);
1149 ctk_widget_destroy (dialog);
1150#endif /* HAVE_LIBNOTIFY */
1151}
1152
1153static void
1154handle_fn_f7 (CsdXrandrManager *mgr, guint32 timestamp)
1155{
1156 CsdXrandrManagerPrivate *priv = mgr->priv;
1157 CafeRRScreen *screen = priv->rw_screen;
1158 CafeRRConfig *current;
1159 GError *error;
1160
1161 /* Theory of fn-F7 operation
1162 *
1163 * We maintain a datastructure "fn_f7_status", that contains
1164 * a list of CafeRRConfig's. Each of the CafeRRConfigs has a
1165 * mode (or "off") for each connected output.
1166 *
1167 * When the user hits fn-F7, we cycle to the next CafeRRConfig
1168 * in the data structure. If the data structure does not exist, it
1169 * is generated. If the configs in the data structure do not match
1170 * the current hardware reality, it is regenerated.
1171 *
1172 */
1173 g_debug ("Handling fn-f7");
1174
1175 log_open ();
1176 log_msg ("Handling XF86Display hotkey - timestamp %u\n", timestamp);
1177
1178 error = NULL((void*)0);
1179 if (!cafe_rr_screen_refresh (screen, &error) && error) {
1180 char *str;
1181
1182 str = g_strdup_printf (_("Could not refresh the screen information: %s")gettext ("Could not refresh the screen information: %s"), error->message);
1183 g_error_free (error);
1184
1185 log_msg ("%s\n", str);
1186 error_message (mgr, str, NULL((void*)0), _("Trying to switch the monitor configuration anyway.")gettext ("Trying to switch the monitor configuration anyway."
)
);
1187 g_free (str);
1188 }
1189
1190 if (!priv->fn_f7_configs) {
1191 log_msg ("Generating stock configurations:\n");
1192 generate_fn_f7_configs (mgr);
1193 log_configurations (priv->fn_f7_configs);
1194 }
1195
1196 current = cafe_rr_config_new_current (screen, NULL((void*)0));
1197
1198 if (priv->fn_f7_configs &&
1199 (!cafe_rr_config_match (current, priv->fn_f7_configs[0]) ||
1200 !cafe_rr_config_equal (current, priv->fn_f7_configs[mgr->priv->current_fn_f7_config]))) {
1201 /* Our view of the world is incorrect, so regenerate the
1202 * configurations
1203 */
1204 generate_fn_f7_configs (mgr);
1205 log_msg ("Regenerated stock configurations:\n");
1206 log_configurations (priv->fn_f7_configs);
1207 }
1208
1209 g_object_unref (current);
1210
1211 if (priv->fn_f7_configs) {
1212 guint32 server_timestamp;
1213 gboolean success;
1214
1215 mgr->priv->current_fn_f7_config++;
1216
1217 if (priv->fn_f7_configs[mgr->priv->current_fn_f7_config] == NULL((void*)0))
1218 mgr->priv->current_fn_f7_config = 0;
1219
1220 g_debug ("cycling to next configuration (%d)", mgr->priv->current_fn_f7_config);
1221
1222 print_configuration (priv->fn_f7_configs[mgr->priv->current_fn_f7_config], "new config");
1223
1224 g_debug ("applying");
1225
1226 /* See https://bugzilla.gnome.org/show_bug.cgi?id=610482
1227 *
1228 * Sometimes we'll get two rapid XF86Display keypress events,
1229 * but their timestamps will be out of order with respect to the
1230 * RANDR timestamps. This *may* be due to stupid BIOSes sending
1231 * out display-switch keystrokes "to make Windows work".
1232 *
1233 * The X server will error out if the timestamp provided is
1234 * older than a previous change configuration timestamp. We
1235 * assume here that we do want this event to go through still,
1236 * since kernel timestamps may be skewed wrt the X server.
1237 */
1238 cafe_rr_screen_get_timestamps (screen, NULL((void*)0), &server_timestamp);
1239 if (timestamp < server_timestamp)
1240 timestamp = server_timestamp;
1241
1242 success = apply_configuration_and_display_error (mgr, priv->fn_f7_configs[mgr->priv->current_fn_f7_config], timestamp);
1243
1244 if (success) {
1245 log_msg ("Successfully switched to configuration (timestamp %u):\n", timestamp);
1246 log_configuration (priv->fn_f7_configs[mgr->priv->current_fn_f7_config]);
1247 }
1248 }
1249 else {
1250 g_debug ("no configurations generated");
1251 }
1252
1253 log_close ();
1254
1255 g_debug ("done handling fn-f7");
1256}
1257
1258static CafeRROutputInfo *
1259get_laptop_output_info (CafeRRScreen *screen, CafeRRConfig *config)
1260{
1261 int i;
1262 CafeRROutputInfo **outputs = cafe_rr_config_get_outputs (config);
1263
1264 for (i = 0; outputs[i] != NULL((void*)0); i++) {
1265 if (is_laptop (screen, outputs[i]))
1266 return outputs[i];
1267 }
1268
1269 return NULL((void*)0);
1270
1271}
1272
1273static CafeRRRotation
1274get_next_rotation (CafeRRRotation allowed_rotations, CafeRRRotation current_rotation)
1275{
1276 int i;
1277 int current_index;
1278
1279 /* First, find the index of the current rotation */
1280
1281 current_index = -1;
1282
1283 for (i = 0; i < G_N_ELEMENTS (possible_rotations)(sizeof (possible_rotations) / sizeof ((possible_rotations)[0
]))
; i++) {
1284 CafeRRRotation r;
1285
1286 r = possible_rotations[i];
1287 if (r == current_rotation) {
1288 current_index = i;
1289 break;
1290 }
1291 }
1292
1293 if (current_index == -1) {
1294 /* Huh, the current_rotation was not one of the supported rotations. Bail out. */
1295 return current_rotation;
1296 }
1297
1298 /* Then, find the next rotation that is allowed */
1299
1300 i = (current_index + 1) % G_N_ELEMENTS (possible_rotations)(sizeof (possible_rotations) / sizeof ((possible_rotations)[0
]))
;
1301
1302 while (1) {
1303 CafeRRRotation r;
1304
1305 r = possible_rotations[i];
1306 if (r == current_rotation) {
1307 /* We wrapped around and no other rotation is suported. Bummer. */
1308 return current_rotation;
1309 } else if (r & allowed_rotations)
1310 return r;
1311
1312 i = (i + 1) % G_N_ELEMENTS (possible_rotations)(sizeof (possible_rotations) / sizeof ((possible_rotations)[0
]))
;
1313 }
1314}
1315
1316/* We use this when the XF86RotateWindows key is pressed. That key is present
1317 * on some tablet PCs; they use it so that the user can rotate the tablet
1318 * easily.
1319 */
1320static void
1321handle_rotate_windows (CsdXrandrManager *mgr, guint32 timestamp)
1322{
1323 CsdXrandrManagerPrivate *priv = mgr->priv;
1324 CafeRRScreen *screen = priv->rw_screen;
1325 CafeRRConfig *current;
1326 CafeRROutputInfo *rotatable_output_info;
1327 int num_allowed_rotations;
1328 CafeRRRotation allowed_rotations;
1329 CafeRRRotation next_rotation;
1330
1331 g_debug ("Handling XF86RotateWindows");
1332
1333 /* Which output? */
1334
1335 current = cafe_rr_config_new_current (screen, NULL((void*)0));
1336
1337 rotatable_output_info = get_laptop_output_info (screen, current);
1338 if (rotatable_output_info == NULL((void*)0)) {
1339 g_debug ("No laptop outputs found to rotate; XF86RotateWindows key will do nothing");
1340 goto out;
1341 }
1342
1343 /* Which rotation? */
1344
1345 get_allowed_rotations_for_output (current, priv->rw_screen, rotatable_output_info, &num_allowed_rotations, &allowed_rotations);
1346 next_rotation = get_next_rotation (allowed_rotations, cafe_rr_output_info_get_rotation (rotatable_output_info));
1347
1348 if (next_rotation == cafe_rr_output_info_get_rotation (rotatable_output_info)) {
1349 g_debug ("No rotations are supported other than the current one; XF86RotateWindows key will do nothing");
1350 goto out;
1351 }
1352
1353 /* Rotate */
1354
1355 cafe_rr_output_info_set_rotation (rotatable_output_info, next_rotation);
1356
1357 apply_configuration_and_display_error (mgr, current, timestamp);
1358
1359out:
1360 g_object_unref (current);
1361}
1362
1363static CdkFilterReturn
1364event_filter (CdkXEvent *xevent,
1365 CdkEvent *event G_GNUC_UNUSED__attribute__ ((__unused__)),
1366 gpointer data)
1367{
1368 CsdXrandrManager *manager = data;
1369 XEvent *xev = (XEvent *) xevent;
1370
1371 if (!manager->priv->running)
1372 return CDK_FILTER_CONTINUE;
1373
1374 /* verify we have a key event */
1375 if (xev->xany.type != KeyPress2 && xev->xany.type != KeyRelease3)
1376 return CDK_FILTER_CONTINUE;
1377
1378 if (xev->xany.type == KeyPress2) {
1379 if (xev->xkey.keycode == manager->priv->switch_video_mode_keycode)
1380 handle_fn_f7 (manager, xev->xkey.time);
1381 else if (xev->xkey.keycode == manager->priv->rotate_windows_keycode)
1382 handle_rotate_windows (manager, xev->xkey.time);
1383
1384 return CDK_FILTER_CONTINUE;
1385 }
1386
1387 return CDK_FILTER_CONTINUE;
1388}
1389
1390static void
1391refresh_tray_icon_menu_if_active (CsdXrandrManager *manager, guint32 timestamp)
1392{
1393 CsdXrandrManagerPrivate *priv = manager->priv;
1394
1395 if (priv->popup_menu) {
1396 ctk_menu_shell_cancel (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
); /* status_icon_popup_menu_selection_done_cb() will free everything */
1397 status_icon_popup_menu (manager, 0, timestamp);
1398 }
1399}
1400
1401static void
1402auto_configure_outputs (CsdXrandrManager *manager, guint32 timestamp)
1403{
1404 CsdXrandrManagerPrivate *priv = manager->priv;
1405 CafeRRConfig *config;
1406 CafeRROutputInfo **outputs;
1407 int i;
1408 GList *just_turned_on;
1409 GList *l;
1410 int x;
1411 GError *error;
1412 gboolean applicable;
1413
1414 config = cafe_rr_config_new_current (priv->rw_screen, NULL((void*)0));
1415
1416 /* For outputs that are connected and on (i.e. they have a CRTC assigned
1417 * to them, so they are getting a signal), we leave them as they are
1418 * with their current modes.
1419 *
1420 * For other outputs, we will turn on connected-but-off outputs and turn
1421 * off disconnected-but-on outputs.
1422 *
1423 * FIXME: If an output remained connected+on, it would be nice to ensure
1424 * that the output's CRTCs still has a reasonable mode (think of
1425 * changing one monitor for another with different capabilities).
1426 */
1427
1428 just_turned_on = NULL((void*)0);
1429 outputs = cafe_rr_config_get_outputs (config);
1430
1431 for (i = 0; outputs[i] != NULL((void*)0); i++) {
1432 CafeRROutputInfo *output = outputs[i];
1433
1434 if (cafe_rr_output_info_is_connected (output) && !cafe_rr_output_info_is_active (output)) {
1435 cafe_rr_output_info_set_active (output, TRUE(!(0)));
1436 cafe_rr_output_info_set_rotation (output, CAFE_RR_ROTATION_0);
1437 just_turned_on = g_list_prepend (just_turned_on, GINT_TO_POINTER (i)((gpointer) (glong) (i)));
1438 } else if (!cafe_rr_output_info_is_connected (output) && cafe_rr_output_info_is_active (output))
1439 cafe_rr_output_info_set_active (output, FALSE(0));
1440 }
1441
1442 /* Now, lay out the outputs from left to right. Put first the outputs
1443 * which remained on; put last the outputs that were newly turned on.
1444 */
1445
1446 x = 0;
1447
1448 /* First, outputs that remained on */
1449
1450 for (i = 0; outputs[i] != NULL((void*)0); i++) {
1451 CafeRROutputInfo *output = outputs[i];
1452
1453 if (g_list_find (just_turned_on, GINT_TO_POINTER (i)((gpointer) (glong) (i))))
1454 continue;
1455
1456 if (cafe_rr_output_info_is_active (output)) {
1457 int width, height;
1458 g_assert (cafe_rr_output_info_is_connected (output))do { if (cafe_rr_output_info_is_connected (output)) ; else g_assertion_message_expr
(((gchar*) 0), "csd_xrandr-manager.c", 1458, ((const char*) (
__func__)), "cafe_rr_output_info_is_connected (output)"); } while
(0)
;
1459
1460 cafe_rr_output_info_get_geometry (output, NULL((void*)0), NULL((void*)0), &width, &height);
1461 cafe_rr_output_info_set_geometry (output, x, 0, width, height);
1462
1463 x += width;
1464 }
1465 }
1466
1467 /* Second, outputs that were newly-turned on */
1468
1469 for (l = just_turned_on; l; l = l->next) {
1470 CafeRROutputInfo *output;
1471 int width;
1472
1473 i = GPOINTER_TO_INT (l->data)((gint) (glong) (l->data));
1474 output = outputs[i];
1475
1476 g_assert (cafe_rr_output_info_is_active (output) && cafe_rr_output_info_is_connected (output))do { if (cafe_rr_output_info_is_active (output) && cafe_rr_output_info_is_connected
(output)) ; else g_assertion_message_expr (((gchar*) 0), "csd_xrandr-manager.c"
, 1476, ((const char*) (__func__)), "cafe_rr_output_info_is_active (output) && cafe_rr_output_info_is_connected (output)"
); } while (0)
;
1477
1478 /* since the output was off, use its preferred width/height (it doesn't have a real width/height yet) */
1479 width = cafe_rr_output_info_get_preferred_width (output);
1480 cafe_rr_output_info_set_geometry (output, x, 0, width, cafe_rr_output_info_get_preferred_height (output));
1481
1482 x += width;
1483 }
1484
1485 /* Check if we have a large enough framebuffer size. If not, turn off
1486 * outputs from right to left until we reach a usable size.
1487 */
1488
1489 just_turned_on = g_list_reverse (just_turned_on); /* now the outputs here are from right to left */
1490
1491 l = just_turned_on;
1492 while (1) {
1493 CafeRROutputInfo *output;
1494 gboolean is_bounds_error;
1495
1496 error = NULL((void*)0);
1497 applicable = cafe_rr_config_applicable (config, priv->rw_screen, &error);
1498
1499 if (applicable)
1500 break;
1501
1502 is_bounds_error = g_error_matches (error, CAFE_RR_ERROR(cafe_rr_error_quark ()), CAFE_RR_ERROR_BOUNDS_ERROR);
1503 g_error_free (error);
1504
1505 if (!is_bounds_error)
1506 break;
1507
1508 if (l) {
1509 i = GPOINTER_TO_INT (l->data)((gint) (glong) (l->data));
1510 l = l->next;
1511
1512 output = outputs[i];
1513 cafe_rr_output_info_set_active (output, FALSE(0));
1514 } else
1515 break;
1516 }
1517
1518 /* Apply the configuration! */
1519
1520 if (applicable)
1521 apply_configuration_and_display_error (manager, config, timestamp);
1522
1523 g_list_free (just_turned_on);
1524 g_object_unref (config);
1525
1526 /* Finally, even though we did a best-effort job in sanitizing the
1527 * outputs, we don't know the physical layout of the monitors. We'll
1528 * start the display capplet so that the user can tweak things to his
1529 * liking.
1530 */
1531
1532#if 0
1533 /* FIXME: This is disabled for now. The capplet is not a single-instance application.
1534 * If you do this:
1535 *
1536 * 1. Start the display capplet
1537 *
1538 * 2. Plug an extra monitor
1539 *
1540 * 3. Hit the "Detect displays" button
1541 *
1542 * Then we will get a RANDR event because X re-probes the outputs. We don't want to
1543 * start up a second display capplet right there!
1544 */
1545
1546 run_display_capplet (NULL((void*)0));
1547#endif
1548}
1549
1550static void
1551apply_color_profiles (void)
1552{
1553 gboolean ret;
1554 GError *error = NULL((void*)0);
1555
1556 /* run the cafe-color-manager apply program */
1557 ret = g_spawn_command_line_async (BINDIR"/usr/bin" "/gcm-apply", &error);
1558 if (!ret) {
1559 /* only print the warning if the binary is installed */
1560 if (error->code != G_SPAWN_ERROR_NOENT) {
1561 g_warning ("failed to apply color profiles: %s", error->message);
1562 }
1563 g_error_free (error);
1564 }
1565}
1566
1567static void
1568on_randr_event (CafeRRScreen *screen, gpointer data)
1569{
1570 CsdXrandrManager *manager = CSD_XRANDR_MANAGER (data)((((CsdXrandrManager*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((data)), ((csd_xrandr_manager_get_type ())))
)))
;
1571 CsdXrandrManagerPrivate *priv = manager->priv;
1572 guint32 change_timestamp, config_timestamp;
1573
1574 if (!priv->running)
1575 return;
1576
1577 cafe_rr_screen_get_timestamps (screen, &change_timestamp, &config_timestamp);
1578
1579 log_open ();
1580 log_msg ("Got RANDR event with timestamps change=%u %c config=%u\n",
1581 change_timestamp,
1582 timestamp_relationship (change_timestamp, config_timestamp),
1583 config_timestamp);
1584
1585 if (change_timestamp >= config_timestamp) {
1586 /* The event is due to an explicit configuration change.
1587 *
1588 * If the change was performed by us, then we need to do nothing.
1589 *
1590 * If the change was done by some other X client, we don't need
1591 * to do anything, either; the screen is already configured.
1592 */
1593 show_timestamps_dialog (manager, "ignoring since change > config");
1594 log_msg (" Ignoring event since change >= config\n");
1595 } else {
1596 /* Here, config_timestamp > change_timestamp. This means that
1597 * the screen got reconfigured because of hotplug/unplug; the X
1598 * server is just notifying us, and we need to configure the
1599 * outputs in a sane way.
1600 */
1601
1602 char *intended_filename;
1603 GError *error;
1604 gboolean success;
1605
1606 show_timestamps_dialog (manager, "need to deal with reconfiguration, as config > change");
1607
1608 intended_filename = cafe_rr_config_get_intended_filename ();
1609
1610 error = NULL((void*)0);
1611 success = apply_configuration_from_filename (manager, intended_filename, TRUE(!(0)), config_timestamp, &error);
1612 g_free (intended_filename);
1613
1614 if (!success) {
1615 /* We don't bother checking the error type.
1616 *
1617 * Both G_FILE_ERROR_NOENT and
1618 * CAFE_RR_ERROR_NO_MATCHING_CONFIG would mean, "there
1619 * was no configuration to apply, or none that matched
1620 * the current outputs", and in that case we need to run
1621 * our fallback.
1622 *
1623 * Any other error means "we couldn't do the smart thing
1624 * of using a previously- saved configuration, anyway,
1625 * for some other reason. In that case, we also need to
1626 * run our fallback to avoid leaving the user with a
1627 * bogus configuration.
1628 */
1629
1630 if (error)
1631 g_error_free (error);
1632
1633 if (config_timestamp != priv->last_config_timestamp) {
1634 priv->last_config_timestamp = config_timestamp;
1635 auto_configure_outputs (manager, config_timestamp);
1636 log_msg (" Automatically configured outputs to deal with event\n");
1637 } else
1638 log_msg (" Ignored event as old and new config timestamps are the same\n");
1639 } else
1640 log_msg ("Applied stored configuration to deal with event\n");
1641 }
1642
1643 /* poke cafe-color-manager */
1644 apply_color_profiles ();
1645
1646 refresh_tray_icon_menu_if_active (manager, MAX (change_timestamp, config_timestamp)(((change_timestamp) > (config_timestamp)) ? (change_timestamp
) : (config_timestamp))
);
1647
1648 log_close ();
1649}
1650
1651static void
1652run_display_capplet (CtkWidget *widget)
1653{
1654 CdkScreen *screen;
1655 GError *error;
1656
1657 if (widget)
1658 screen = ctk_widget_get_screen (widget);
1659 else
1660 screen = cdk_screen_get_default ();
1661
1662 error = NULL((void*)0);
1663 if (!cafe_cdk_spawn_command_line_on_screen (screen, CSD_XRANDR_DISPLAY_CAPPLET"cafe-display-properties", &error)) {
1664 CtkWidget *dialog;
1665
1666 dialog = ctk_message_dialog_new_with_markup (NULL((void*)0), 0, CTK_MESSAGE_ERROR, CTK_BUTTONS_OK,
1667 "<span weight=\"bold\" size=\"larger\">"
1668 "Display configuration could not be run"
1669 "</span>\n\n"
1670 "%s", error->message);
1671 ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
);
1672 ctk_widget_destroy (dialog);
1673
1674 g_error_free (error);
1675 }
1676}
1677
1678static void
1679popup_menu_configure_display_cb (CtkMenuItem *item,
1680 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
1681{
1682 run_display_capplet (CTK_WIDGET (item)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((ctk_widget_get_type ()))))))
);
1683}
1684
1685static void
1686status_icon_popup_menu_selection_done_cb (CtkMenuShell *menu_shell G_GNUC_UNUSED__attribute__ ((__unused__)),
1687 gpointer data)
1688{
1689 CsdXrandrManager *manager = CSD_XRANDR_MANAGER (data)((((CsdXrandrManager*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((data)), ((csd_xrandr_manager_get_type ())))
)))
;
1690 struct CsdXrandrManagerPrivate *priv = manager->priv;
1691
1692 ctk_widget_destroy (priv->popup_menu);
1693 priv->popup_menu = NULL((void*)0);
1694
1695 cafe_rr_labeler_hide (priv->labeler);
1696 g_object_unref (priv->labeler);
1697 priv->labeler = NULL((void*)0);
1698
1699 g_object_unref (priv->configuration);
1700 priv->configuration = NULL((void*)0);
1701}
1702
1703#define OUTPUT_TITLE_ITEM_BORDER2 2
1704#define OUTPUT_TITLE_ITEM_PADDING4 4
1705
1706static void
1707title_item_size_allocate_cb (CtkWidget *widget,
1708 CtkAllocation *allocation,
1709 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
1710{
1711 /* When CtkMenu does size_request on its items, it asks them for their "toggle size",
1712 * which will be non-zero when there are check/radio items. CtkMenu remembers
1713 * the largest of those sizes. During the size_allocate pass, CtkMenu calls
1714 * ctk_menu_item_toggle_size_allocate() with that value, to tell the menu item
1715 * that it should later paint its child a bit to the right of its edge.
1716 *
1717 * However, we want the "title" menu items for each RANDR output to span the *whole*
1718 * allocation of the menu item, not just the "allocation minus toggle" area.
1719 *
1720 * So, we let the menu item size_allocate itself as usual, but this
1721 * callback gets run afterward. Here we hack a toggle size of 0 into
1722 * the menu item, and size_allocate it by hand *again*. We also need to
1723 * avoid recursing into this function.
1724 */
1725
1726 g_assert (CTK_IS_MENU_ITEM (widget))do { if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((widget)); GType __t = ((ctk_menu_item_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))) ; else
g_assertion_message_expr (((gchar*) 0), "csd_xrandr-manager.c"
, 1726, ((const char*) (__func__)), "CTK_IS_MENU_ITEM (widget)"
); } while (0)
;
1727
1728 ctk_menu_item_toggle_size_allocate (CTK_MENU_ITEM (widget)((((CtkMenuItem*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_menu_item_get_type ()))))))
, 0);
1729
1730 g_signal_handlers_block_by_func (widget, title_item_size_allocate_cb, NULL)g_signal_handlers_block_matched ((widget), (GSignalMatchType)
(G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)0
), (title_item_size_allocate_cb), (((void*)0)))
;
1731
1732 /* Sigh. There is no way to turn on CTK_ALLOC_NEEDED outside of CTK+
1733 * itself; also, since calling size_allocate on a widget with the same
1734 * allcation is a no-op, we need to allocate with a "different" size
1735 * first.
1736 */
1737
1738 allocation->width++;
1739 ctk_widget_size_allocate (widget, allocation);
1740
1741 allocation->width--;
1742 ctk_widget_size_allocate (widget, allocation);
1743
1744 g_signal_handlers_unblock_by_func (widget, title_item_size_allocate_cb, NULL)g_signal_handlers_unblock_matched ((widget), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (title_item_size_allocate_cb), (((void*)0)))
;
1745}
1746
1747static CtkWidget *
1748make_menu_item_for_output_title (CsdXrandrManager *manager, CafeRROutputInfo *output)
1749{
1750 CtkWidget *item;
1751 CtkStyleContext *context;
1752 CtkCssProvider *provider, *provider2;
1753 CtkWidget *label;
1754 CtkWidget *image;
1755 CtkWidget *box;
1756 char *str;
1757 GString *string;
1758 CdkRGBA color;
1759 gchar *css, *color_string, *theme_name;
1760 CtkSettings *settings;
1761 GSettings *icon_settings;
1762
1763 struct CsdXrandrManagerPrivate *priv = manager->priv;
1764
1765 item = ctk_menu_item_new ();
1766 box = ctk_box_new (CTK_ORIENTATION_HORIZONTAL, 6);
1767 image = ctk_image_new_from_icon_name ("computer", CTK_ICON_SIZE_MENU);
1768 context = ctk_widget_get_style_context (item);
1769 ctk_style_context_add_class (context, "xrandr-applet");
1770
1771 g_signal_connect (item, "size-allocate",g_signal_connect_data ((item), ("size-allocate"), (((GCallback
) (title_item_size_allocate_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
1772 G_CALLBACK (title_item_size_allocate_cb), NULL)g_signal_connect_data ((item), ("size-allocate"), (((GCallback
) (title_item_size_allocate_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
;
1773
1774 str = g_markup_printf_escaped ("<b>%s</b>", cafe_rr_output_info_get_display_name (output));
1775 label = ctk_label_new (NULL((void*)0));
1776 ctk_label_set_markup (CTK_LABEL (label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((ctk_label_get_type ()))))))
, str);
1777 g_free (str);
1778
1779 /* Add padding around the label to fit the box that we'll draw for color-coding */
1780 ctk_label_set_xalign (CTK_LABEL (label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((ctk_label_get_type ()))))))
, 0.0);
1781 ctk_label_set_yalign (CTK_LABEL (label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((ctk_label_get_type ()))))))
, 0.5);
1782 ctk_widget_set_margin_start (label, OUTPUT_TITLE_ITEM_BORDER2 + OUTPUT_TITLE_ITEM_PADDING4);
1783 ctk_widget_set_margin_end (label, OUTPUT_TITLE_ITEM_BORDER2 + OUTPUT_TITLE_ITEM_PADDING4);
1784 ctk_widget_set_margin_top (label, OUTPUT_TITLE_ITEM_BORDER2 + OUTPUT_TITLE_ITEM_PADDING4);
1785 ctk_widget_set_margin_bottom (label, OUTPUT_TITLE_ITEM_BORDER2 + OUTPUT_TITLE_ITEM_PADDING4);
1786
1787 /*Load the icon unless the user has icons in menus turned off*/
1788 icon_settings = g_settings_new ("org.cafe.interface");
1789 if (g_settings_get_boolean (icon_settings, "menus-have-icons")){
1790 ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, image);
1791 }
1792 ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, label);
1793 ctk_container_add (CTK_CONTAINER (item)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((ctk_container_get_type ()))))))
, box);
1794
1795 cafe_rr_labeler_get_rgba_for_output (priv->labeler, output, &color);
1796
1797 color_string = cdk_rgba_to_string (&color);
1798
1799 /*This can be overriden by themes, check all label:insensitive entries if it does not show up*/
1800 string = g_string_new(NULL((void*)0));
1801 g_string_append (string, ".cafe-panel-menu-bar menuitem.xrandr-applet:disabled>box>label{\n")(__builtin_constant_p (".cafe-panel-menu-bar menuitem.xrandr-applet:disabled>box>label{\n"
) ? __extension__ ({ const char * const __val = (".cafe-panel-menu-bar menuitem.xrandr-applet:disabled>box>label{\n"
); g_string_append_len_inline (string, __val, (__val != ((void
*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1)
; }) : g_string_append_len_inline (string, ".cafe-panel-menu-bar menuitem.xrandr-applet:disabled>box>label{\n"
, (gssize) -1))
;
1802 /*g_string_append (string, "color: black;"); Does not work-overridden in all themes*/
1803 g_string_append (string, "padding-left: 4px; padding-right: 4px;")(__builtin_constant_p ("padding-left: 4px; padding-right: 4px;"
) ? __extension__ ({ const char * const __val = ("padding-left: 4px; padding-right: 4px;"
); g_string_append_len_inline (string, __val, (__val != ((void
*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1)
; }) : g_string_append_len_inline (string, "padding-left: 4px; padding-right: 4px;"
, (gssize) -1))
;
1804 g_string_append (string, "border-color: gray;")(__builtin_constant_p ("border-color: gray;") ? __extension__
({ const char * const __val = ("border-color: gray;"); g_string_append_len_inline
(string, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(string, "border-color: gray;", (gssize) -1))
;
1805 g_string_append (string, "border-width: 1px;")(__builtin_constant_p ("border-width: 1px;") ? __extension__ (
{ const char * const __val = ("border-width: 1px;"); g_string_append_len_inline
(string, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(string, "border-width: 1px;", (gssize) -1))
;
1806 g_string_append (string, "border-style: inset;")(__builtin_constant_p ("border-style: inset;") ? __extension__
({ const char * const __val = ("border-style: inset;"); g_string_append_len_inline
(string, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(string, "border-style: inset;", (gssize) -1))
;
1807 g_string_append (string, "background-image: none;")(__builtin_constant_p ("background-image: none;") ? __extension__
({ const char * const __val = ("background-image: none;"); g_string_append_len_inline
(string, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(string, "background-image: none;", (gssize) -1))
;
1808 /*Bright color for active monitor, dimmed for inactive monitor*/
1809 if (cafe_rr_output_info_is_active (output)){
1810 g_string_append (string, "background-color:")(__builtin_constant_p ("background-color:") ? __extension__ (
{ const char * const __val = ("background-color:"); g_string_append_len_inline
(string, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(string, "background-color:", (gssize) -1))
;
1811 g_string_append (string, color_string)(__builtin_constant_p (color_string) ? __extension__ ({ const
char * const __val = (color_string); g_string_append_len_inline
(string, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(string, color_string, (gssize) -1))
;
1812 g_string_append (string, ";")(__builtin_constant_p (";") ? __extension__ ({ const char * const
__val = (";"); g_string_append_len_inline (string, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (string, ";", (gssize)
-1))
;
1813 g_string_append (string," }")(__builtin_constant_p (" }") ? __extension__ ({ const char * const
__val = (" }"); g_string_append_len_inline (string, __val, (
__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val)))
: (gssize) -1); }) : g_string_append_len_inline (string, " }"
, (gssize) -1))
;
1814 }
1815 else{
1816 g_string_append (string, "background-color: alpha(")(__builtin_constant_p ("background-color: alpha(") ? __extension__
({ const char * const __val = ("background-color: alpha("); g_string_append_len_inline
(string, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(string, "background-color: alpha(", (gssize) -1))
;
1817 g_string_append (string, color_string)(__builtin_constant_p (color_string) ? __extension__ ({ const
char * const __val = (color_string); g_string_append_len_inline
(string, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(string, color_string, (gssize) -1))
;
1818 g_string_append (string, ", 0.4);")(__builtin_constant_p (", 0.4);") ? __extension__ ({ const char
* const __val = (", 0.4);"); g_string_append_len_inline (string
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (string
, ", 0.4);", (gssize) -1))
;
1819 g_string_append (string," }")(__builtin_constant_p (" }") ? __extension__ ({ const char * const
__val = (" }"); g_string_append_len_inline (string, __val, (
__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val)))
: (gssize) -1); }) : g_string_append_len_inline (string, " }"
, (gssize) -1))
;
1820 ctk_style_context_add_class (context, "monitor-off");
1821 }
1822
1823 css = g_string_free (string, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((string
), ((0))) : g_string_free_and_steal (string)) : (g_string_free
) ((string), ((0))))
;
1824
1825 context = ctk_widget_get_style_context (label);
1826 provider = ctk_css_provider_new ();
1827 ctk_css_provider_load_from_data (provider,css, -1, NULL((void*)0));
1828
1829 ctk_style_context_add_provider (context,
1830 CTK_STYLE_PROVIDER (provider)((((CtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider)), ((ctk_style_provider_get_type (
)))))))
,
1831 CTK_STYLE_PROVIDER_PRIORITY_FALLBACK1);
1832
1833 g_object_unref (provider);
1834 g_free (color_string);
1835 g_free (css);
1836
1837 /*This is NOT overrridden by themes as FALLBACK won't work here
1838 *Disable dim/opacity effects applied to icons in an insensitive menu item
1839 */
1840
1841 context = ctk_widget_get_style_context (image);
1842 provider = ctk_css_provider_new ();
1843
1844 ctk_css_provider_load_from_data (provider,
1845 ".cafe-panel-menu-bar menuitem.xrandr-applet:disabled>box>image{\n"
1846 "opacity: 1.0; \n"
1847 "-ctk-icon-style:regular; \n" /* symbolic icons would get the disabled color*/
1848 "-ctk-icon-effect: none; \n"
1849 "}",
1850 -1, NULL((void*)0));
1851 ctk_style_context_add_provider (context,
1852 CTK_STYLE_PROVIDER (provider)((((CtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider)), ((ctk_style_provider_get_type (
)))))))
,
1853 CTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
1854
1855 /*Deal with the GNOME and *bird themes, match display capplet theme */
1856 provider2 = ctk_css_provider_new ();
1857 settings = ctk_settings_get_default();
1858 context = ctk_widget_get_style_context (label);
1859 g_object_get (settings, "ctk-theme-name", &theme_name, NULL((void*)0));
1860 if (g_strcmp0 (theme_name, "Adwaita") == 0 ||
1861 g_strcmp0 (theme_name, "Adwaita-dark") == 0 ||
1862 g_strcmp0 (theme_name, "Raleigh") == 0 ||
1863 g_strcmp0 (theme_name, "win32") == 0 ||
1864 g_strcmp0 (theme_name, "HighContrast") == 0 ||
1865 g_strcmp0 (theme_name, "HighContrastInverse") == 0 ||
1866 g_strcmp0 (theme_name, "Blackbird") == 0 ||
1867 g_strcmp0 (theme_name, "Bluebird") == 0 ||
1868 g_strcmp0 (theme_name, "Greybird") == 0){
1869 ctk_css_provider_load_from_data (provider2,
1870 ".cafe-panel-menu-bar menuitem.xrandr-applet:disabled>box>label{\n"
1871 "color: black;\n"
1872 "}"
1873 ".cafe-panel-menu-bar menuitem.xrandr-applet.monitor-off:disabled>box>label{\n"
1874 "color: alpha (black, 0.6);\n"
1875 "}",
1876 -1, NULL((void*)0));
1877 ctk_style_context_add_provider(context,
1878 CTK_STYLE_PROVIDER (provider2)((((CtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider2)), ((ctk_style_provider_get_type (
)))))))
,
1879 CTK_STYLE_PROVIDER_PRIORITY_APPLICATION600);
1880 }
1881 /*Keep or take this off all other themes as soon as the theme changes*/
1882 else{
1883 ctk_style_context_remove_provider(context, CTK_STYLE_PROVIDER (provider2)((((CtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider2)), ((ctk_style_provider_get_type (
)))))))
);
1884 }
1885
1886 g_object_unref (provider);
1887 g_object_unref (provider2);
1888
1889 ctk_widget_set_sensitive (item, FALSE(0)); /* the title is not selectable */
1890
1891 ctk_widget_show_all (item);
1892
1893 return item;
1894}
1895
1896static void
1897get_allowed_rotations_for_output (CafeRRConfig *config,
1898 CafeRRScreen *rr_screen,
1899 CafeRROutputInfo *output,
1900 int *out_num_rotations,
1901 CafeRRRotation *out_rotations)
1902{
1903 CafeRRRotation current_rotation;
1904 int i;
1905
1906 *out_num_rotations = 0;
1907 *out_rotations = 0;
1908
1909 current_rotation = cafe_rr_output_info_get_rotation (output);
1910
1911 /* Yay for brute force */
1912
1913 for (i = 0; i < G_N_ELEMENTS (possible_rotations)(sizeof (possible_rotations) / sizeof ((possible_rotations)[0
]))
; i++) {
1914 CafeRRRotation rotation_to_test;
1915
1916 rotation_to_test = possible_rotations[i];
1917
1918 cafe_rr_output_info_set_rotation (output, rotation_to_test);
1919
1920 if (cafe_rr_config_applicable (config, rr_screen, NULL((void*)0))) { /* NULL-GError */
1921 (*out_num_rotations)++;
1922 (*out_rotations) |= rotation_to_test;
1923 }
1924 }
1925
1926 cafe_rr_output_info_set_rotation (output, current_rotation);
1927
1928 if (*out_num_rotations == 0 || *out_rotations == 0) {
1929 g_warning ("Huh, output %p says it doesn't support any rotations, and yet it has a current rotation?", output);
1930 *out_num_rotations = 1;
1931 *out_rotations = cafe_rr_output_info_get_rotation (output);
1932 }
1933}
1934
1935static void
1936add_unsupported_rotation_item (CsdXrandrManager *manager)
1937{
1938 struct CsdXrandrManagerPrivate *priv = manager->priv;
1939 CtkWidget *item;
1940 CtkWidget *label;
1941 gchar *markup;
1942
1943 item = ctk_menu_item_new ();
1944
1945 label = ctk_label_new (NULL((void*)0));
1946 markup = g_strdup_printf ("<i>%s</i>", _("Rotation not supported")gettext ("Rotation not supported"));
1947 ctk_label_set_markup (CTK_LABEL (label)((((CtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((ctk_label_get_type ()))))))
, markup);
1948 g_free (markup);
1949 ctk_container_add (CTK_CONTAINER (item)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((ctk_container_get_type ()))))))
, label);
1950
1951 ctk_widget_show_all (item);
1952 ctk_menu_shell_append (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, item);
1953}
1954
1955static void
1956ensure_current_configuration_is_saved (void)
1957{
1958 CafeRRScreen *rr_screen;
1959 CafeRRConfig *rr_config;
1960
1961 /* Normally, cafe_rr_config_save() creates a backup file based on the
1962 * old monitors.xml. However, if *that* file didn't exist, there is
1963 * nothing from which to create a backup. So, here we'll save the
1964 * current/unchanged configuration and then let our caller call
1965 * cafe_rr_config_save() again with the new/changed configuration, so
1966 * that there *will* be a backup file in the end.
1967 */
1968
1969 rr_screen = cafe_rr_screen_new (cdk_screen_get_default (), NULL((void*)0)); /* NULL-GError */
1970 if (!rr_screen)
1971 return;
1972
1973 rr_config = cafe_rr_config_new_current (rr_screen, NULL((void*)0));
1974 cafe_rr_config_save (rr_config, NULL((void*)0)); /* NULL-GError */
1975
1976 g_object_unref (rr_config);
1977 g_object_unref (rr_screen);
1978}
1979
1980static void
1981monitor_activate_cb (CtkCheckMenuItem *item, gpointer data)
1982{
1983 CsdXrandrManager *manager = CSD_XRANDR_MANAGER (data)((((CsdXrandrManager*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((data)), ((csd_xrandr_manager_get_type ())))
)))
;
1984 struct CsdXrandrManagerPrivate *priv = manager->priv;
1985 CafeRROutputInfo *output;
1986 GError *error;
1987
1988 ensure_current_configuration_is_saved ();
1989
1990 output = g_object_get_data (G_OBJECT (item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), (((GType) ((20) << (2))))))))
, "output");
1991
1992 /*This is borrowed from the capplet in cafe-control-center
1993 *And shares the same limitations concerning monitors
1994 *which have been turned off and back on without being reconfigured
1995 */
1996 if (ctk_check_menu_item_get_active (item)){
1997 int x, y, width, height;
1998 cafe_rr_output_info_get_geometry (output, &x, &y, NULL((void*)0), NULL((void*)0));
1999 width = cafe_rr_output_info_get_preferred_width (output);
2000 height = cafe_rr_output_info_get_preferred_height (output);
2001 cafe_rr_output_info_set_geometry (output, x, y, width, height);
2002 cafe_rr_output_info_set_active (output, TRUE(!(0)));
2003
2004 }
2005 else{
2006 cafe_rr_output_info_set_active (output, FALSE(0));
2007 }
2008
2009 error = NULL((void*)0);
2010 if (!cafe_rr_config_save (priv->configuration, &error)) {
2011 error_message (manager, _("Could not save monitor configuration")gettext ("Could not save monitor configuration"), error, NULL((void*)0));
2012 if (error)
2013 g_error_free (error);
2014
2015 return;
2016 }
2017
2018 try_to_apply_intended_configuration (manager, NULL((void*)0), ctk_get_current_event_time (), NULL((void*)0));
2019}
2020
2021static void
2022output_rotation_item_activate_cb (CtkCheckMenuItem *item, gpointer data)
2023{
2024 CsdXrandrManager *manager = CSD_XRANDR_MANAGER (data)((((CsdXrandrManager*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((data)), ((csd_xrandr_manager_get_type ())))
)))
;
2025 struct CsdXrandrManagerPrivate *priv = manager->priv;
2026 CafeRROutputInfo *output;
2027 CafeRRRotation rotation;
2028 GError *error;
2029
2030 /* Not interested in deselected items */
2031 if (!ctk_check_menu_item_get_active (item))
2032 return;
2033
2034 ensure_current_configuration_is_saved ();
2035
2036 output = g_object_get_data (G_OBJECT (item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), (((GType) ((20) << (2))))))))
, "output");
2037 rotation = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "rotation"))((gint) (glong) (g_object_get_data (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((item)), (((GType) ((20) << (2)))))
))), "rotation")))
;
2038
2039 cafe_rr_output_info_set_rotation (output, rotation);
2040
2041 error = NULL((void*)0);
2042 if (!cafe_rr_config_save (priv->configuration, &error)) {
2043 error_message (manager, _("Could not save monitor configuration")gettext ("Could not save monitor configuration"), error, NULL((void*)0));
2044 if (error)
2045 g_error_free (error);
2046
2047 return;
2048 }
2049
2050 try_to_apply_intended_configuration (manager, NULL((void*)0), ctk_get_current_event_time (), NULL((void*)0)); /* NULL-GError */
2051}
2052
2053static void
2054mirror_outputs_cb(CtkCheckMenuItem *item, gpointer data)
2055{
2056 CsdXrandrManager *manager = CSD_XRANDR_MANAGER (data)((((CsdXrandrManager*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((data)), ((csd_xrandr_manager_get_type ())))
)))
;
2057 struct CsdXrandrManagerPrivate *priv = manager->priv;
2058 CafeRRScreen *screen = priv->rw_screen;
2059
2060 if (ctk_check_menu_item_get_active(item)){
2061
2062 CafeRRConfig *config;
2063 config = make_clone_setup (screen);
2064 if (!config || config == NULL((void*)0)){
2065 error_message (manager, _("Mirroring outputs not supported")gettext ("Mirroring outputs not supported"), NULL((void*)0), NULL((void*)0));
2066 }
2067
2068 cafe_rr_config_save (config, NULL((void*)0));
2069 try_to_apply_intended_configuration (manager, NULL((void*)0), ctk_get_current_event_time (), NULL((void*)0));
2070
2071 g_object_unref (config);
2072
2073 }
2074 else{
2075
2076 CafeRRConfig *config;
2077 config = make_primary_only_setup (screen);
2078 /*If nothing worked, bring up the display capplet so the user can reconfigure*/
2079 if (config == NULL((void*)0))
2080 run_display_capplet(CTK_WIDGET(item)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((ctk_widget_get_type ()))))))
);
2081 cafe_rr_config_save (config, NULL((void*)0));
2082 try_to_apply_intended_configuration (manager, NULL((void*)0), ctk_get_current_event_time (), NULL((void*)0));
2083
2084 g_object_unref (config);
2085
2086 }
2087}
2088static void
2089add_items_for_rotations (CsdXrandrManager *manager, CafeRROutputInfo *output, CafeRRRotation allowed_rotations)
2090{
2091 typedef struct {
2092 CafeRRRotation rotation;
2093 const char * name;
2094 } RotationInfo;
2095 static const RotationInfo rotations[] = {
2096 { CAFE_RR_ROTATION_0, N_("Normal")("Normal") },
2097 { CAFE_RR_ROTATION_90, N_("Left")("Left") },
2098 { CAFE_RR_ROTATION_270, N_("Right")("Right") },
2099 { CAFE_RR_ROTATION_180, N_("Upside Down")("Upside Down") },
2100 /* We don't allow REFLECT_X or REFLECT_Y for now, as cafe-display-properties doesn't allow them, either */
2101 };
2102
2103 struct CsdXrandrManagerPrivate *priv = manager->priv;
2104 int i;
2105 GSList *group;
2106 CtkWidget *active_item;
2107 gulong active_item_activate_id;
2108
2109 group = NULL((void*)0);
2110 active_item = NULL((void*)0);
2111 active_item_activate_id = 0;
2112
2113 for (i = 0; i < G_N_ELEMENTS (rotations)(sizeof (rotations) / sizeof ((rotations)[0])); i++) {
2114 CafeRRRotation rot;
2115 CtkWidget *item;
2116 gulong activate_id;
2117
2118 rot = rotations[i].rotation;
2119
2120 if ((allowed_rotations & rot) == 0) {
2121 /* don't display items for rotations which are
2122 * unavailable. Their availability is not under the
2123 * user's control, anyway.
2124 */
2125 continue;
2126 }
2127
2128 item = ctk_radio_menu_item_new_with_label (group, _(rotations[i].name)gettext (rotations[i].name));
2129 /*HERE*/
2130 if (!(cafe_rr_output_info_is_active (output))){
2131 ctk_widget_set_sensitive (item, FALSE(0)); /*Rotation can't be set from the OFF state*/
2132 }
2133 ctk_widget_show_all (item);
2134 ctk_menu_shell_append (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, item);
2135
2136 g_object_set_data (G_OBJECT (item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), (((GType) ((20) << (2))))))))
, "output", output);
2137 g_object_set_data (G_OBJECT (item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), (((GType) ((20) << (2))))))))
, "rotation", GINT_TO_POINTER (rot)((gpointer) (glong) (rot)));
2138
2139 activate_id = g_signal_connect (item, "activate",g_signal_connect_data ((item), ("activate"), (((GCallback) (output_rotation_item_activate_cb
))), (manager), ((void*)0), (GConnectFlags) 0)
2140 G_CALLBACK (output_rotation_item_activate_cb), manager)g_signal_connect_data ((item), ("activate"), (((GCallback) (output_rotation_item_activate_cb
))), (manager), ((void*)0), (GConnectFlags) 0)
;
2141
2142 group = ctk_radio_menu_item_get_group (CTK_RADIO_MENU_ITEM (item)((((CtkRadioMenuItem*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((item)), ((ctk_radio_menu_item_get_type ()))
))))
);
2143
2144 if (rot == cafe_rr_output_info_get_rotation (output)) {
2145 active_item = item;
2146 active_item_activate_id = activate_id;
2147 }
2148 }
2149
2150 if (active_item) {
2151 /* Block the signal temporarily so our callback won't be called;
2152 * we are just setting up the UI.
2153 */
2154 g_signal_handler_block (active_item, active_item_activate_id);
2155
2156 ctk_check_menu_item_set_active (CTK_CHECK_MENU_ITEM (active_item)((((CtkCheckMenuItem*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((active_item)), ((ctk_check_menu_item_get_type
()))))))
, TRUE(!(0)));
2157
2158 g_signal_handler_unblock (active_item, active_item_activate_id);
2159 }
2160
2161}
2162
2163static void
2164add_rotation_items_for_output (CsdXrandrManager *manager, CafeRROutputInfo *output)
2165{
2166 struct CsdXrandrManagerPrivate *priv = manager->priv;
2167 int num_rotations;
2168 CafeRRRotation rotations;
2169
2170 get_allowed_rotations_for_output (priv->configuration, priv->rw_screen, output, &num_rotations, &rotations);
2171
2172 if (num_rotations == 1)
2173 add_unsupported_rotation_item (manager);
2174 else
2175 add_items_for_rotations (manager, output, rotations);
2176}
2177
2178static void
2179add_enable_option_for_output (CsdXrandrManager *manager, CafeRROutputInfo *output)
2180{
2181 struct CsdXrandrManagerPrivate *priv = manager->priv;
2182 CtkWidget *item;
2183 gulong activate_id;
2184
2185 item = ctk_check_menu_item_new();
2186
2187 if (cafe_rr_output_info_is_active (output)){
2188 ctk_menu_item_set_label (CTK_MENU_ITEM(item)((((CtkMenuItem*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((ctk_menu_item_get_type ()))))))
, _("ON")gettext ("ON"));
2189 ctk_widget_set_tooltip_text(item, _("Turn this monitor off")gettext ("Turn this monitor off"));
2190 }
2191 else {
2192 ctk_menu_item_set_label (CTK_MENU_ITEM(item)((((CtkMenuItem*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((ctk_menu_item_get_type ()))))))
, _("OFF")gettext ("OFF"));
2193 ctk_widget_set_tooltip_text(item, _("Turn this monitor on")gettext ("Turn this monitor on"));
2194 }
2195
2196 ctk_widget_show_all (item);
2197 ctk_menu_shell_append (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, item);
2198
2199 g_object_set_data (G_OBJECT (item)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), (((GType) ((20) << (2))))))))
, "output", output);
2200
2201 activate_id = g_signal_connect (item, "activate",g_signal_connect_data ((item), ("activate"), (((GCallback) (monitor_activate_cb
))), (manager), ((void*)0), (GConnectFlags) 0)
2202 G_CALLBACK (monitor_activate_cb), manager)g_signal_connect_data ((item), ("activate"), (((GCallback) (monitor_activate_cb
))), (manager), ((void*)0), (GConnectFlags) 0)
;
2203
2204 /* Block the signal temporarily so our callback won't be called;
2205 * we are just setting up the UI.
2206 */
2207 g_signal_handler_block (item, activate_id);
2208
2209 if (cafe_rr_output_info_is_active (output)){
2210 ctk_check_menu_item_set_active(CTK_CHECK_MENU_ITEM(item)((((CtkCheckMenuItem*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((item)), ((ctk_check_menu_item_get_type ()))
))))
, TRUE(!(0)));
2211 }
2212 else{
2213 ctk_check_menu_item_set_active(CTK_CHECK_MENU_ITEM(item)((((CtkCheckMenuItem*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((item)), ((ctk_check_menu_item_get_type ()))
))))
, FALSE(0));
2214 }
2215
2216 g_signal_handler_unblock (item, activate_id);
2217}
2218
2219static void
2220add_menu_items_for_output (CsdXrandrManager *manager, CafeRROutputInfo *output)
2221{
2222 struct CsdXrandrManagerPrivate *priv = manager->priv;
2223 CtkWidget *item;
2224
2225 item = make_menu_item_for_output_title (manager, output);
2226 ctk_menu_shell_append (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, item);
2227
2228 add_enable_option_for_output (manager, output);
2229 add_rotation_items_for_output (manager, output);
2230}
2231
2232static void
2233add_menu_items_for_outputs (CsdXrandrManager *manager)
2234{
2235 struct CsdXrandrManagerPrivate *priv = manager->priv;
2236 int i;
2237 CafeRROutputInfo **outputs;
2238
2239 outputs = cafe_rr_config_get_outputs (priv->configuration);
2240 for (i = 0; outputs[i] != NULL((void*)0); i++) {
2241 if (cafe_rr_output_info_is_connected (outputs[i]))
2242 add_menu_items_for_output (manager, outputs[i]);
2243 }
2244}
2245
2246static void
2247add_menu_items_for_clone (CsdXrandrManager *manager)
2248{
2249 struct CsdXrandrManagerPrivate *priv = manager->priv;
2250 CtkWidget *item;
2251 gulong activate_id;
2252
2253 item = ctk_check_menu_item_new_with_label(_("Same output all monitors")gettext ("Same output all monitors"));
2254 ctk_widget_set_tooltip_text(item, _("Mirror same output to all monitors and turn them on")gettext ("Mirror same output to all monitors and turn them on"
)
);
2255 ctk_widget_show_all (item);
2256 ctk_menu_shell_append (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, item);
2257 activate_id = g_signal_connect (item, "activate",g_signal_connect_data ((item), ("activate"), (((GCallback) (mirror_outputs_cb
))), (manager), ((void*)0), (GConnectFlags) 0)
2258 G_CALLBACK (mirror_outputs_cb), manager)g_signal_connect_data ((item), ("activate"), (((GCallback) (mirror_outputs_cb
))), (manager), ((void*)0), (GConnectFlags) 0)
;
2259 /*Block the handler until the GUI is set up no matter what the monitor state*/
2260 g_signal_handler_block (item, activate_id);
2261
2262 if (cafe_rr_config_get_clone(priv->configuration)){
2263 ctk_check_menu_item_set_active(CTK_CHECK_MENU_ITEM(item)((((CtkCheckMenuItem*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((item)), ((ctk_check_menu_item_get_type ()))
))))
, TRUE(!(0)));
2264 }
2265 else{
2266 ctk_check_menu_item_set_active(CTK_CHECK_MENU_ITEM(item)((((CtkCheckMenuItem*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((item)), ((ctk_check_menu_item_get_type ()))
))))
, FALSE(0));
2267 }
2268 g_signal_handler_unblock (item, activate_id);
2269}
2270
2271static void
2272status_icon_popup_menu (CsdXrandrManager *manager, guint button, guint32 timestamp)
2273{
2274 struct CsdXrandrManagerPrivate *priv = manager->priv;
2275 CtkWidget *item;
2276 CtkWidget *image;
2277 CtkWidget *label;
2278 CtkWidget *box;
2279 GSettings *icon_settings;
2280
2281 g_assert (priv->configuration == NULL)do { if (priv->configuration == ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "csd_xrandr-manager.c", 2281, ((const char*) (
__func__)), "priv->configuration == NULL"); } while (0)
;
2282 priv->configuration = cafe_rr_config_new_current (priv->rw_screen, NULL((void*)0));
2283
2284 g_assert (priv->labeler == NULL)do { if (priv->labeler == ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "csd_xrandr-manager.c", 2284, ((const char*) (
__func__)), "priv->labeler == NULL"); } while (0)
;
2285 priv->labeler = cafe_rr_labeler_new (priv->configuration);
2286
2287 g_assert (priv->popup_menu == NULL)do { if (priv->popup_menu == ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "csd_xrandr-manager.c", 2287, ((const char*) (
__func__)), "priv->popup_menu == NULL"); } while (0)
;
2288 priv->popup_menu = ctk_menu_new ();
2289
2290 add_menu_items_for_outputs (manager);
2291
2292 item = ctk_separator_menu_item_new ();
2293 ctk_widget_show (item);
2294 ctk_menu_shell_append (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, item);
2295
2296 add_menu_items_for_clone (manager);
2297
2298 item = ctk_menu_item_new();
2299 box = ctk_box_new (CTK_ORIENTATION_HORIZONTAL, 10);
2300 image = ctk_image_new_from_icon_name ("preferences-system", CTK_ICON_SIZE_MENU);
2301 label = ctk_label_new_with_mnemonic(_("_Configure Display Settings…")gettext ("_Configure Display Settings…"));
2302 /*Load the icon unless the user has icons in menus turned off*/
2303 icon_settings = g_settings_new ("org.cafe.interface");
2304 if (g_settings_get_boolean (icon_settings, "menus-have-icons")){
2305 ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, image);
2306 g_signal_connect (item, "size-allocate",g_signal_connect_data ((item), ("size-allocate"), (((GCallback
) (title_item_size_allocate_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
2307 G_CALLBACK (title_item_size_allocate_cb), NULL)g_signal_connect_data ((item), ("size-allocate"), (((GCallback
) (title_item_size_allocate_cb))), (((void*)0)), ((void*)0), (
GConnectFlags) 0)
;
2308 }
2309 ctk_container_add (CTK_CONTAINER (box)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((box)), ((ctk_container_get_type ()))))))
, label);
2310 ctk_container_add (CTK_CONTAINER (item)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((item)), ((ctk_container_get_type ()))))))
, box);
2311 ctk_widget_set_tooltip_text(item, _("Open the display configuration dialog (all settings)")gettext ("Open the display configuration dialog (all settings)"
)
);
2312 g_signal_connect (item, "activate",g_signal_connect_data ((item), ("activate"), (((GCallback) (popup_menu_configure_display_cb
))), (manager), ((void*)0), (GConnectFlags) 0)
2313 G_CALLBACK (popup_menu_configure_display_cb), manager)g_signal_connect_data ((item), ("activate"), (((GCallback) (popup_menu_configure_display_cb
))), (manager), ((void*)0), (GConnectFlags) 0)
;
2314 ctk_widget_show_all (item);
2315 ctk_menu_shell_append (CTK_MENU_SHELL (priv->popup_menu)((((CtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_shell_get_type ())))))
)
, item);
2316
2317 g_signal_connect (priv->popup_menu, "selection-done",g_signal_connect_data ((priv->popup_menu), ("selection-done"
), (((GCallback) (status_icon_popup_menu_selection_done_cb)))
, (manager), ((void*)0), (GConnectFlags) 0)
2318 G_CALLBACK (status_icon_popup_menu_selection_done_cb), manager)g_signal_connect_data ((priv->popup_menu), ("selection-done"
), (((GCallback) (status_icon_popup_menu_selection_done_cb)))
, (manager), ((void*)0), (GConnectFlags) 0)
;
2319
2320 /*Set up custom theming and forced transparency support*/
2321 CtkWidget *toplevel = ctk_widget_get_toplevel (priv->popup_menu);
2322 /*Fix any failures of compiz/other wm's to communicate with ctk for transparency */
2323 CdkScreen *screen = ctk_widget_get_screen(CTK_WIDGET(toplevel)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((ctk_widget_get_type ()))))))
);
2324 CdkVisual *visual = cdk_screen_get_rgba_visual(screen);
2325 ctk_widget_set_visual(CTK_WIDGET(toplevel)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((ctk_widget_get_type ()))))))
, visual);
2326 /*Set up the ctk theme class from cafe-panel*/
2327 CtkStyleContext *context;
2328 context = ctk_widget_get_style_context (CTK_WIDGET(toplevel)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((ctk_widget_get_type ()))))))
);
2329 ctk_style_context_add_class(context,"gnome-panel-menu-bar");
2330 ctk_style_context_add_class(context,"cafe-panel-menu-bar");
2331
2332 ctk_menu_popup (CTK_MENU (priv->popup_menu)((((CtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->popup_menu)), ((ctk_menu_get_type ()))))))
, NULL((void*)0), NULL((void*)0),
2333 ctk_status_icon_position_menu,
2334 priv->status_icon, button, timestamp);
2335}
2336
2337static void
2338status_icon_activate_cb (CtkStatusIcon *status_icon G_GNUC_UNUSED__attribute__ ((__unused__)),
2339 gpointer data)
2340{
2341 CsdXrandrManager *manager = CSD_XRANDR_MANAGER (data)((((CsdXrandrManager*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((data)), ((csd_xrandr_manager_get_type ())))
)))
;
2342
2343 /* Suck; we don't get a proper button/timestamp */
2344 status_icon_popup_menu (manager, 0, ctk_get_current_event_time ());
2345}
2346
2347static void
2348status_icon_popup_menu_cb (CtkStatusIcon *status_icon G_GNUC_UNUSED__attribute__ ((__unused__)),
2349 guint button,
2350 guint32 timestamp,
2351 gpointer data)
2352{
2353 CsdXrandrManager *manager = CSD_XRANDR_MANAGER (data)((((CsdXrandrManager*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((data)), ((csd_xrandr_manager_get_type ())))
)))
;
2354
2355 status_icon_popup_menu (manager, button, timestamp);
2356}
2357
2358static void
2359status_icon_start (CsdXrandrManager *manager)
2360{
2361 struct CsdXrandrManagerPrivate *priv = manager->priv;
2362
2363 /* Ideally, we should detect if we are on a tablet and only display
2364 * the icon in that case.
2365 */
2366 if (!priv->status_icon) {
2367 priv->status_icon = ctk_status_icon_new_from_icon_name (CSD_XRANDR_ICON_NAME"csd_xrandr");
2368 ctk_status_icon_set_tooltip_text (priv->status_icon, _("Configure display settings")gettext ("Configure display settings"));
2369
2370 g_signal_connect (priv->status_icon, "activate",g_signal_connect_data ((priv->status_icon), ("activate"), (
((GCallback) (status_icon_activate_cb))), (manager), ((void*)
0), (GConnectFlags) 0)
2371 G_CALLBACK (status_icon_activate_cb), manager)g_signal_connect_data ((priv->status_icon), ("activate"), (
((GCallback) (status_icon_activate_cb))), (manager), ((void*)
0), (GConnectFlags) 0)
;
2372 g_signal_connect (priv->status_icon, "popup-menu",g_signal_connect_data ((priv->status_icon), ("popup-menu")
, (((GCallback) (status_icon_popup_menu_cb))), (manager), ((void
*)0), (GConnectFlags) 0)
2373 G_CALLBACK (status_icon_popup_menu_cb), manager)g_signal_connect_data ((priv->status_icon), ("popup-menu")
, (((GCallback) (status_icon_popup_menu_cb))), (manager), ((void
*)0), (GConnectFlags) 0)
;
2374 }
2375}
2376
2377static void
2378status_icon_stop (CsdXrandrManager *manager)
2379{
2380 struct CsdXrandrManagerPrivate *priv = manager->priv;
2381
2382 if (priv->status_icon) {
2383 g_signal_handlers_disconnect_by_func (g_signal_handlers_disconnect_matched ((priv->status_icon),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (status_icon_activate_cb))
), (manager))
2384 priv->status_icon, G_CALLBACK (status_icon_activate_cb), manager)g_signal_handlers_disconnect_matched ((priv->status_icon),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (status_icon_activate_cb))
), (manager))
;
2385 g_signal_handlers_disconnect_by_func (g_signal_handlers_disconnect_matched ((priv->status_icon),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (status_icon_popup_menu_cb
))), (manager))
2386 priv->status_icon, G_CALLBACK (status_icon_popup_menu_cb), manager)g_signal_handlers_disconnect_matched ((priv->status_icon),
(GSignalMatchType) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA
), 0, 0, ((void*)0), (((GCallback) (status_icon_popup_menu_cb
))), (manager))
;
2387
2388 /* hide the icon before unreffing it; otherwise we will leak
2389 whitespace in the notification area due to a bug in there */
2390 ctk_status_icon_set_visible (priv->status_icon, FALSE(0));
2391 g_object_unref (priv->status_icon);
2392 priv->status_icon = NULL((void*)0);
2393 }
2394}
2395
2396static void
2397start_or_stop_icon (CsdXrandrManager *manager)
2398{
2399 if (g_settings_get_boolean (manager->priv->settings, CONF_KEY_SHOW_NOTIFICATION_ICON"show-notification-icon")) {
2400 status_icon_start (manager);
2401 }
2402 else {
2403 status_icon_stop (manager);
2404 }
2405}
2406
2407static void
2408on_config_changed (GSettings *settings G_GNUC_UNUSED__attribute__ ((__unused__)),
2409 gchar *key,
2410 CsdXrandrManager *manager)
2411{
2412 if (g_strcmp0 (key, CONF_KEY_SHOW_NOTIFICATION_ICON"show-notification-icon") == 0)
2413 start_or_stop_icon (manager);
2414}
2415
2416static gboolean
2417apply_intended_configuration (CsdXrandrManager *manager, const char *intended_filename, guint32 timestamp)
2418{
2419 GError *my_error;
2420 gboolean result;
2421
2422#ifdef HAVE_RDA
2423 if (rda_session_is_remote()) {
2424 return FALSE(0);
2425 }
2426#endif
2427
2428 my_error = NULL((void*)0);
2429 result = apply_configuration_from_filename (manager, intended_filename, TRUE(!(0)), timestamp, &my_error);
2430 if (!result) {
2431 if (my_error) {
2432 if (!g_error_matches (my_error, G_FILE_ERRORg_file_error_quark (), G_FILE_ERROR_NOENT) &&
2433 !g_error_matches (my_error, CAFE_RR_ERROR(cafe_rr_error_quark ()), CAFE_RR_ERROR_NO_MATCHING_CONFIG))
2434 error_message (manager, _("Could not apply the stored configuration for monitors")gettext ("Could not apply the stored configuration for monitors"
)
, my_error, NULL((void*)0));
2435
2436 g_error_free (my_error);
2437 }
2438 }
2439
2440 return result;
2441}
2442
2443static void
2444apply_default_boot_configuration (CsdXrandrManager *mgr, guint32 timestamp)
2445{
2446 CsdXrandrManagerPrivate *priv = mgr->priv;
2447 CafeRRScreen *screen = priv->rw_screen;
2448 CafeRRConfig *config;
2449 gboolean turn_on_external, turn_on_laptop;
2450
2451 turn_on_external =
2452 g_settings_get_boolean (mgr->priv->settings, CONF_KEY_TURN_ON_EXTERNAL_MONITORS_AT_STARTUP"turn-on-external-monitors-at-startup");
2453 turn_on_laptop =
2454 g_settings_get_boolean (mgr->priv->settings, CONF_KEY_TURN_ON_LAPTOP_MONITOR_AT_STARTUP"turn-on-laptop-monitor-at-startup");
2455
2456 if (turn_on_external && turn_on_laptop)
2457 config = make_clone_setup (screen);
2458 else if (!turn_on_external && turn_on_laptop)
2459 config = make_laptop_setup (screen);
2460 else if (turn_on_external && !turn_on_laptop)
2461 config = make_other_setup (screen);
2462 else
2463 config = make_laptop_setup (screen);
2464
2465 if (config) {
2466 apply_configuration_and_display_error (mgr, config, timestamp);
2467 g_object_unref (config);
2468 }
2469}
2470
2471static gboolean
2472apply_stored_configuration_at_startup (CsdXrandrManager *manager, guint32 timestamp)
2473{
2474 GError *my_error;
2475 gboolean success;
2476 char *backup_filename;
2477 char *intended_filename;
2478
2479 backup_filename = cafe_rr_config_get_backup_filename ();
2480 intended_filename = cafe_rr_config_get_intended_filename ();
2481
2482 /* 1. See if there was a "saved" configuration. If there is one, it means
2483 * that the user had selected to change the display configuration, but the
2484 * machine crashed. In that case, we'll apply *that* configuration and save it on top of the
2485 * "intended" one.
2486 */
2487
2488 my_error = NULL((void*)0);
2489
2490 success = apply_configuration_from_filename (manager, backup_filename, FALSE(0), timestamp, &my_error);
2491 if (success) {
2492 /* The backup configuration existed, and could be applied
2493 * successfully, so we must restore it on top of the
2494 * failed/intended one.
2495 */
2496 restore_backup_configuration (manager, backup_filename, intended_filename, timestamp);
2497 goto out;
2498 }
2499
2500 if (!g_error_matches (my_error, G_FILE_ERRORg_file_error_quark (), G_FILE_ERROR_NOENT)) {
2501 /* Epic fail: there (probably) was a backup configuration, but
2502 * we could not apply it. The only thing we can do is delete
2503 * the backup configuration. Let's hope that the user doesn't
2504 * get left with an unusable display...
2505 */
2506
2507 unlink (backup_filename);
2508 goto out;
2509 }
2510
2511 /* 2. There was no backup configuration! This means we are
2512 * good. Apply the intended configuration instead.
2513 */
2514
2515 success = apply_intended_configuration (manager, intended_filename, timestamp);
2516
2517out:
2518 if (my_error)
2519 g_error_free (my_error);
2520
2521 g_free (backup_filename);
2522 g_free (intended_filename);
2523
2524 return success;
2525}
2526
2527static gboolean
2528apply_default_configuration_from_file (CsdXrandrManager *manager, guint32 timestamp)
2529{
2530 CsdXrandrManagerPrivate *priv = manager->priv;
2531 char *default_config_filename;
2532 gboolean result;
2533
2534 default_config_filename = g_settings_get_string (priv->settings, CONF_KEY_DEFAULT_CONFIGURATION_FILE"default-configuration-file");
2535 if (!default_config_filename)
2536 return FALSE(0);
2537
2538 result = apply_configuration_from_filename (manager, default_config_filename, TRUE(!(0)), timestamp, NULL((void*)0));
2539
2540 g_free (default_config_filename);
2541 return result;
2542}
2543
2544gboolean
2545csd_xrandr_manager_start (CsdXrandrManager *manager,
2546 GError **error)
2547{
2548 CdkDisplay *display;
2549
2550 g_debug ("Starting xrandr manager");
2551 cafe_settings_profile_start (NULL);
2552
2553 log_open ();
2554 log_msg ("------------------------------------------------------------\nSTARTING XRANDR PLUGIN\n");
2555
2556 manager->priv->rw_screen = cafe_rr_screen_new (cdk_screen_get_default (), error);
2557
2558 if (manager->priv->rw_screen == NULL((void*)0)) {
2559 log_msg ("Could not initialize the RANDR plugin%s%s\n",
2560 (error && *error) ? ": " : "",
2561 (error && *error) ? (*error)->message : "");
2562 log_close ();
2563 return FALSE(0);
2564 }
2565
2566 g_signal_connect (manager->priv->rw_screen, "changed", G_CALLBACK (on_randr_event), manager)g_signal_connect_data ((manager->priv->rw_screen), ("changed"
), (((GCallback) (on_randr_event))), (manager), ((void*)0), (
GConnectFlags) 0)
;
2567
2568 log_msg ("State of screen at startup:\n");
2569 log_screen (manager->priv->rw_screen);
2570
2571 manager->priv->running = TRUE(!(0));
2572 manager->priv->settings = g_settings_new (CONF_SCHEMA"org.cafe.SettingsDaemon.plugins.xrandr");
2573
2574 g_signal_connect (manager->priv->settings,g_signal_connect_data ((manager->priv->settings), ("changed::"
"show-notification-icon"), (((GCallback) (on_config_changed)
)), (manager), ((void*)0), (GConnectFlags) 0)
2575 "changed::" CONF_KEY_SHOW_NOTIFICATION_ICON,g_signal_connect_data ((manager->priv->settings), ("changed::"
"show-notification-icon"), (((GCallback) (on_config_changed)
)), (manager), ((void*)0), (GConnectFlags) 0)
2576 G_CALLBACK (on_config_changed),g_signal_connect_data ((manager->priv->settings), ("changed::"
"show-notification-icon"), (((GCallback) (on_config_changed)
)), (manager), ((void*)0), (GConnectFlags) 0)
2577 manager)g_signal_connect_data ((manager->priv->settings), ("changed::"
"show-notification-icon"), (((GCallback) (on_config_changed)
)), (manager), ((void*)0), (GConnectFlags) 0)
;
2578
2579 display = cdk_display_get_default ();
2580
2581 if (manager->priv->switch_video_mode_keycode) {
2582 cdk_x11_display_error_trap_push (display);
2583
2584 XGrabKey (cdk_x11_get_default_xdisplay(),
2585 manager->priv->switch_video_mode_keycode, AnyModifier(1<<15),
2586 cdk_x11_get_default_root_xwindow(),
2587 True1, GrabModeAsync1, GrabModeAsync1);
2588
2589 cdk_display_flush (display);
2590 cdk_x11_display_error_trap_pop_ignored (display);
2591 }
2592
2593 if (manager->priv->rotate_windows_keycode) {
2594 cdk_x11_display_error_trap_push (display);
2595
2596 XGrabKey (cdk_x11_get_default_xdisplay(),
2597 manager->priv->rotate_windows_keycode, AnyModifier(1<<15),
2598 cdk_x11_get_default_root_xwindow(),
2599 True1, GrabModeAsync1, GrabModeAsync1);
2600
2601 cdk_display_flush (display);
2602 cdk_x11_display_error_trap_pop_ignored (display);
2603 }
2604
2605 show_timestamps_dialog (manager, "Startup");
2606 if (!apply_stored_configuration_at_startup (manager, CDK_CURRENT_TIME0L)) /* we don't have a real timestamp at startup anyway */
2607 if (!apply_default_configuration_from_file (manager, CDK_CURRENT_TIME0L))
2608 if (!g_settings_get_boolean (manager->priv->settings, CONF_KEY_USE_XORG_MONITOR_SETTINGS"use-xorg-monitor-settings"))
2609 apply_default_boot_configuration (manager, CDK_CURRENT_TIME0L);
2610
2611 log_msg ("State of screen after initial configuration:\n");
2612 log_screen (manager->priv->rw_screen);
2613
2614 cdk_window_add_filter (cdk_get_default_root_window(),
2615 (CdkFilterFunc)event_filter,
2616 manager);
2617
2618 start_or_stop_icon (manager);
2619
2620 log_close ();
2621
2622 cafe_settings_profile_end (NULL);
2623
2624 return TRUE(!(0));
2625}
2626
2627void
2628csd_xrandr_manager_stop (CsdXrandrManager *manager)
2629{
2630 CdkDisplay *display;
2631
2632 g_debug ("Stopping xrandr manager");
2633
2634 manager->priv->running = FALSE(0);
2635
2636 display = cdk_display_get_default ();
2637
2638 if (manager->priv->switch_video_mode_keycode) {
2639 cdk_x11_display_error_trap_push (display);
2640
2641 XUngrabKey (cdk_x11_get_default_xdisplay(),
2642 manager->priv->switch_video_mode_keycode, AnyModifier(1<<15),
2643 cdk_x11_get_default_root_xwindow());
2644
2645 cdk_x11_display_error_trap_pop_ignored (display);
2646 }
2647
2648 if (manager->priv->rotate_windows_keycode) {
2649 cdk_x11_display_error_trap_push (display);
2650
2651 XUngrabKey (cdk_x11_get_default_xdisplay(),
2652 manager->priv->rotate_windows_keycode, AnyModifier(1<<15),
2653 cdk_x11_get_default_root_xwindow());
2654
2655 cdk_x11_display_error_trap_pop_ignored (display);
2656 }
2657
2658 cdk_window_remove_filter (cdk_get_default_root_window (),
2659 (CdkFilterFunc) event_filter,
2660 manager);
2661
2662 if (manager->priv->settings != NULL((void*)0)) {
2663 g_object_unref (manager->priv->settings);
2664 manager->priv->settings = NULL((void*)0);
2665 }
2666
2667 if (manager->priv->rw_screen != NULL((void*)0)) {
2668 g_object_unref (manager->priv->rw_screen);
2669 manager->priv->rw_screen = NULL((void*)0);
2670 }
2671
2672 if (manager->priv->dbus_connection != NULL((void*)0)) {
2673 dbus_g_connection_unref (manager->priv->dbus_connection);
2674 manager->priv->dbus_connection = NULL((void*)0);
2675 }
2676
2677 status_icon_stop (manager);
2678
2679 log_open ();
2680 log_msg ("STOPPING XRANDR PLUGIN\n------------------------------------------------------------\n");
2681 log_close ();
2682}
2683
2684static void
2685csd_xrandr_manager_class_init (CsdXrandrManagerClass *klass)
2686{
2687 GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
2688
2689 object_class->finalize = csd_xrandr_manager_finalize;
2690
2691 dbus_g_object_type_install_info (CSD_TYPE_XRANDR_MANAGER(csd_xrandr_manager_get_type ()), &dbus_glib_csd_xrandr_manager_object_info);
2692}
2693
2694static guint
2695get_keycode_for_keysym_name (const char *name)
2696{
2697 Display *dpy;
2698 guint keyval;
2699
2700 dpy = cdk_x11_get_default_xdisplay ();
2701
2702 keyval = cdk_keyval_from_name (name);
2703 return XKeysymToKeycode (dpy, keyval);
2704}
2705
2706static void
2707csd_xrandr_manager_init (CsdXrandrManager *manager)
2708{
2709 manager->priv = csd_xrandr_manager_get_instance_private (manager);
2710
2711 manager->priv->switch_video_mode_keycode = get_keycode_for_keysym_name (VIDEO_KEYSYM"XF86Display");
2712 manager->priv->rotate_windows_keycode = get_keycode_for_keysym_name (ROTATE_KEYSYM"XF86RotateWindows");
2713
2714 manager->priv->current_fn_f7_config = -1;
2715 manager->priv->fn_f7_configs = NULL((void*)0);
2716}
2717
2718static void
2719csd_xrandr_manager_finalize (GObject *object)
2720{
2721 CsdXrandrManager *xrandr_manager;
2722
2723 g_return_if_fail (object != NULL)do { if ((object != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "object != NULL")
; return; } } while (0)
;
2724 g_return_if_fail (CSD_IS_XRANDR_MANAGER (object))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((object)); GType __t = ((csd_xrandr_manager_get_type ()))
; gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class
&& __inst->g_class->g_type == __t) __r = (!(0)
); else __r = g_type_check_instance_is_a (__inst, __t); __r; }
)))))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const
char*) (__func__)), "CSD_IS_XRANDR_MANAGER (object)"); return
; } } while (0)
;
2725
2726 xrandr_manager = CSD_XRANDR_MANAGER (object)((((CsdXrandrManager*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((object)), ((csd_xrandr_manager_get_type ())
)))))
;
2727
2728 g_return_if_fail (xrandr_manager->priv != NULL)do { if ((xrandr_manager->priv != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "xrandr_manager->priv != NULL"
); return; } } while (0)
;
2729
2730 G_OBJECT_CLASS (csd_xrandr_manager_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((csd_xrandr_manager_parent_class)), (((GType) ((20) <<
(2))))))))
->finalize (object);
2731}
2732
2733static gboolean
2734register_manager_dbus (CsdXrandrManager *manager)
2735{
2736 GError *error = NULL((void*)0);
2737
2738 manager->priv->dbus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
2739 if (manager->priv->dbus_connection == NULL((void*)0)) {
2740 if (error != NULL((void*)0)) {
2741 g_warning ("Error getting session bus: %s", error->message);
2742 g_error_free (error);
2743 }
2744 return FALSE(0);
2745 }
2746
2747 /* Hmm, should we do this in csd_xrandr_manager_start()? */
2748 dbus_g_connection_register_g_object (manager->priv->dbus_connection, CSD_XRANDR_DBUS_PATH"/org/cafe/SettingsDaemon" "/XRANDR", G_OBJECT (manager)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((manager)), (((GType) ((20) << (2))))))))
);
2749
2750 return TRUE(!(0));
2751}
2752
2753CsdXrandrManager *
2754csd_xrandr_manager_new (void)
2755{
2756 if (manager_object != NULL((void*)0)) {
2757 g_object_ref (manager_object)((__typeof__ (manager_object)) (g_object_ref) (manager_object
))
;
2758 } else {
2759 manager_object = g_object_new (CSD_TYPE_XRANDR_MANAGER(csd_xrandr_manager_get_type ()), NULL((void*)0));
2760 g_object_add_weak_pointer (manager_object,
2761 (gpointer *) &manager_object);
2762
2763 if (!register_manager_dbus (manager_object)) {
2764 g_object_unref (manager_object);
2765 return NULL((void*)0);
2766 }
2767 }
2768
2769 return CSD_XRANDR_MANAGER (manager_object)((((CsdXrandrManager*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((manager_object)), ((csd_xrandr_manager_get_type
()))))))
;
2770}