Bug Summary

File:plugins/xrandr/csd_xrandr-manager.c
Warning:line 802, column 21
Although the value stored to 'best_width' is used in the enclosing expression, the value is never actually read from 'best_width'

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