~ubuntu-branches/ubuntu/lucid/gnome-settings-daemon/lucid-updates

1 by Sebastien Bacher
Import upstream version 2.21.5.2
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>
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
4
 * Copyright (C) 2007, 2008 Red Hat, Inc
1 by Sebastien Bacher
Import upstream version 2.21.5.2
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
 *
20
 */
21
22
#include "config.h"
23
24
#include <sys/types.h>
25
#include <sys/wait.h>
26
#include <stdlib.h>
27
#include <stdio.h>
28
#include <unistd.h>
29
#include <string.h>
30
#include <errno.h>
31
32
#include <locale.h>
33
34
#include <glib.h>
35
#include <glib/gi18n.h>
36
#include <gdk/gdk.h>
37
#include <gdk/gdkx.h>
38
#include <gtk/gtk.h>
0.1.1 by Sebastian Dröge
Import upstream version 2.22.2.1
39
#include <gconf/gconf-client.h>
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
40
#include <dbus/dbus-glib.h>
0.1.1 by Sebastian Dröge
Import upstream version 2.22.2.1
41
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
42
#define GNOME_DESKTOP_USE_UNSTABLE_API
43
44
#include <libgnomeui/gnome-rr-config.h>
45
#include <libgnomeui/gnome-rr.h>
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
46
#include <libgnomeui/gnome-rr-labeler.h>
1 by Sebastien Bacher
Import upstream version 2.21.5.2
47
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
48
#ifdef HAVE_LIBNOTIFY
49
#include <libnotify/notify.h>
50
#endif
51
1.1.6 by Sebastien Bacher
Import upstream version 2.22.1
52
#include "gnome-settings-profile.h"
1 by Sebastien Bacher
Import upstream version 2.21.5.2
53
#include "gsd-xrandr-manager.h"
54
1.1.7 by Sebastien Bacher
Import upstream version 2.23.1.1
55
#ifndef HOST_NAME_MAX
56
#define HOST_NAME_MAX   255
57
#endif
58
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
59
#define GSD_XRANDR_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_XRANDR_MANAGER, GsdXrandrManagerPrivate))
60
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
61
#define CONF_DIR "/apps/gnome_settings_daemon/xrandr"
62
#define CONF_KEY "show_notification_icon"
63
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
64
#define VIDEO_KEYSYM    "XF86Display"
1.1.30 by Chris Coulson
Import upstream version 2.29.5
65
#define ROTATE_KEYSYM   "XF86RotateWindows"
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
66
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
67
/* Number of seconds that the confirmation dialog will last before it resets the
68
 * RANDR configuration to its old state.
69
 */
70
#define CONFIRMATION_DIALOG_SECONDS 30
71
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
72
/* name of the icon files (gsd-xrandr.svg, etc.) */
73
#define GSD_XRANDR_ICON_NAME "gsd-xrandr"
74
75
/* executable of the control center's display configuration capplet */
76
#define GSD_XRANDR_DISPLAY_CAPPLET "gnome-display-properties"
77
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
78
#define GSD_DBUS_PATH "/org/gnome/SettingsDaemon"
79
#define GSD_DBUS_NAME "org.gnome.SettingsDaemon"
80
#define GSD_XRANDR_DBUS_PATH GSD_DBUS_PATH "/XRANDR"
81
#define GSD_XRANDR_DBUS_NAME GSD_DBUS_NAME ".XRANDR"
82
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
83
struct GsdXrandrManagerPrivate
84
{
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
85
        DBusGConnection *dbus_connection;
86
1.1.30 by Chris Coulson
Import upstream version 2.29.5
87
        /* Key code of the XF86Display key (Fn-F7 on Thinkpads, Fn-F4 on HP machines, etc.) */
88
        guint switch_video_mode_keycode;
89
90
        /* Key code of the XF86RotateWindows key (present on some tablets) */
91
        guint rotate_windows_keycode;
92
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
93
        GnomeRRScreen *rw_screen;
94
        gboolean running;
95
96
        GtkStatusIcon *status_icon;
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
97
        GtkWidget *popup_menu;
98
        GnomeRRConfig *configuration;
99
        GnomeRRLabeler *labeler;
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
100
        GConfClient *client;
101
        int notify_id;
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
102
103
        /* fn-F7 status */
104
        int             current_fn_f7_config;             /* -1 if no configs */
105
        GnomeRRConfig **fn_f7_configs;  /* NULL terminated, NULL if there are no configs */
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
106
107
        /* Last time at which we got a "screen got reconfigured" event; see on_randr_event() */
108
        guint32 last_config_timestamp;
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
109
};
110
1.1.30 by Chris Coulson
Import upstream version 2.29.5
111
static const GnomeRRRotation possible_rotations[] = {
112
        GNOME_RR_ROTATION_0,
113
        GNOME_RR_ROTATION_90,
114
        GNOME_RR_ROTATION_180,
115
        GNOME_RR_ROTATION_270
116
        /* We don't allow REFLECT_X or REFLECT_Y for now, as gnome-display-properties doesn't allow them, either */
117
};
118
1 by Sebastien Bacher
Import upstream version 2.21.5.2
119
static void     gsd_xrandr_manager_class_init  (GsdXrandrManagerClass *klass);
120
static void     gsd_xrandr_manager_init        (GsdXrandrManager      *xrandr_manager);
121
static void     gsd_xrandr_manager_finalize    (GObject             *object);
122
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
123
static void error_message (GsdXrandrManager *mgr, const char *primary_text, GError *error_to_display, const char *secondary_text);
124
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
125
static void status_icon_popup_menu (GsdXrandrManager *manager, guint button, guint32 timestamp);
126
static void run_display_capplet (GtkWidget *widget);
1.1.30 by Chris Coulson
Import upstream version 2.29.5
127
static void get_allowed_rotations_for_output (GnomeRRConfig *config,
128
                                              GnomeRRScreen *rr_screen,
129
                                              GnomeOutputInfo *output,
130
                                              int *out_num_rotations,
131
                                              GnomeRRRotation *out_rotations);
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
132
1 by Sebastien Bacher
Import upstream version 2.21.5.2
133
G_DEFINE_TYPE (GsdXrandrManager, gsd_xrandr_manager, G_TYPE_OBJECT)
134
135
static gpointer manager_object = NULL;
136
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
137
static void
138
show_timestamps_dialog (GsdXrandrManager *manager, const char *msg)
139
{
140
#if 1
141
        return;
142
#else
143
        struct GsdXrandrManagerPrivate *priv = manager->priv;
144
        GtkWidget *dialog;
145
        guint32 change_timestamp, config_timestamp;
146
        static int serial;
147
148
        gnome_rr_screen_get_timestamps (priv->rw_screen, &change_timestamp, &config_timestamp);
149
150
        dialog = gtk_message_dialog_new (NULL,
151
                                         0,
152
                                         GTK_MESSAGE_INFO,
153
                                         GTK_BUTTONS_CLOSE,
154
                                         "RANDR timestamps (%d):\n%s\nchange: %u\nconfig: %u",
155
                                         serial++,
156
                                         msg,
157
                                         change_timestamp,
158
                                         config_timestamp);
159
        g_signal_connect (dialog, "response",
160
                          G_CALLBACK (gtk_widget_destroy), NULL);
161
        gtk_widget_show (dialog);
162
#endif
163
}
164
1.1.32 by Chris Coulson
Import upstream version 2.29.90
165
/* This function centralizes the use of gnome_rr_config_apply_from_filename_with_time().
166
 *
167
 * Optionally filters out GNOME_RR_ERROR_NO_MATCHING_CONFIG from
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
168
 * gnome_rr_config_apply_from_filename_with_time(), since that is not usually an error.
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
169
 */
170
static gboolean
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
171
apply_configuration_from_filename (GsdXrandrManager *manager,
172
                                   const char       *filename,
173
                                   gboolean          no_matching_config_is_an_error,
174
                                   guint32           timestamp,
175
                                   GError          **error)
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
176
{
177
        struct GsdXrandrManagerPrivate *priv = manager->priv;
178
        GError *my_error;
179
        gboolean success;
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
180
        char *str;
181
182
        str = g_strdup_printf ("Applying %s with timestamp %d", filename, timestamp);
183
        show_timestamps_dialog (manager, str);
184
        g_free (str);
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
185
186
        my_error = NULL;
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
187
        success = gnome_rr_config_apply_from_filename_with_time (priv->rw_screen, filename, timestamp, &my_error);
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
188
        if (success)
189
                return TRUE;
190
191
        if (g_error_matches (my_error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_MATCHING_CONFIG)) {
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
192
                if (no_matching_config_is_an_error)
193
                        goto fail;
194
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
195
                /* This is not an error; the user probably changed his monitors
196
                 * and so they don't match any of the stored configurations.
197
                 */
198
                g_error_free (my_error);
199
                return TRUE;
200
        }
201
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
202
fail:
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
203
        g_propagate_error (error, my_error);
204
        return FALSE;
205
}
206
1.1.32 by Chris Coulson
Import upstream version 2.29.90
207
/* This function centralizes the use of gnome_rr_config_apply_with_time().
208
 *
209
 * Applies a configuration and displays an error message if an error happens.
210
 * We just return whether setting the configuration succeeded.
211
 */
212
static gboolean
213
apply_configuration_and_display_error (GsdXrandrManager *manager, GnomeRRConfig *config, guint32 timestamp)
214
{
215
        GsdXrandrManagerPrivate *priv = manager->priv;
216
        GError *error;
217
        gboolean success;
218
219
        error = NULL;
220
        success = gnome_rr_config_apply_with_time (config, priv->rw_screen, timestamp, &error);
221
        if (!success) {
222
                error_message (manager, _("Could not switch the monitor configuration"), error, NULL);
223
                g_error_free (error);
224
        }
225
226
        return success;
227
}
228
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
229
static void
230
restore_backup_configuration_without_messages (const char *backup_filename, const char *intended_filename)
231
{
232
        backup_filename = gnome_rr_config_get_backup_filename ();
233
        rename (backup_filename, intended_filename);
234
}
235
236
static void
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
237
restore_backup_configuration (GsdXrandrManager *manager, const char *backup_filename, const char *intended_filename, guint32 timestamp)
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
238
{
239
        int saved_errno;
240
241
        if (rename (backup_filename, intended_filename) == 0) {
242
                GError *error;
243
244
                error = NULL;
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
245
                if (!apply_configuration_from_filename (manager, intended_filename, FALSE, timestamp, &error)) {
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
246
                        error_message (manager, _("Could not restore the display's configuration"), error, NULL);
247
248
                        if (error)
249
                                g_error_free (error);
250
                }
251
252
                return;
253
        }
254
255
        saved_errno = errno;
256
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
257
        /* ENOENT means the original file didn't exist.  That is *not* an error;
258
         * the backup was not created because there wasn't even an original
259
         * monitors.xml (such as on a first-time login).  Note that *here* there
260
         * is a "didn't work" monitors.xml, so we must delete that one.
261
         */
262
        if (saved_errno == ENOENT)
263
                unlink (intended_filename);
264
        else {
265
                char *msg;
266
267
                msg = g_strdup_printf ("Could not rename %s to %s: %s",
268
                                       backup_filename, intended_filename,
269
                                       g_strerror (saved_errno));
270
                error_message (manager,
271
                               _("Could not restore the display's configuration from a backup"),
272
                               NULL,
273
                               msg);
274
                g_free (msg);
275
        }
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
276
277
        unlink (backup_filename);
278
}
279
280
typedef struct {
281
        GsdXrandrManager *manager;
282
        GtkWidget *dialog;
283
284
        int countdown;
285
        int response_id;
286
} TimeoutDialog;
287
288
static void
289
print_countdown_text (TimeoutDialog *timeout)
290
{
291
        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (timeout->dialog),
1.1.21 by Sebastien Bacher
Import upstream version 2.27.1
292
                                                  ngettext ("The display will be reset to its previous configuration in %d second",
293
                                                            "The display will be reset to its previous configuration in %d seconds",
294
                                                            timeout->countdown),
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
295
                                                  timeout->countdown);
296
}
297
298
static gboolean
299
timeout_cb (gpointer data)
300
{
301
        TimeoutDialog *timeout = data;
302
303
        timeout->countdown--;
304
305
        if (timeout->countdown == 0) {
306
                timeout->response_id = GTK_RESPONSE_CANCEL;
307
                gtk_main_quit ();
308
        } else {
309
                print_countdown_text (timeout);
310
        }
311
312
        return TRUE;
313
}
314
315
static void
316
timeout_response_cb (GtkDialog *dialog, int response_id, gpointer data)
317
{
318
        TimeoutDialog *timeout = data;
319
320
        if (response_id == GTK_RESPONSE_DELETE_EVENT) {
1.1.18 by Sebastien Bacher
Import upstream version 2.25.92
321
                /* The user closed the dialog or pressed ESC, revert */
322
                timeout->response_id = GTK_RESPONSE_CANCEL;
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
323
        } else
324
                timeout->response_id = response_id;
325
326
        gtk_main_quit ();
327
}
328
329
static gboolean
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
330
user_says_things_are_ok (GsdXrandrManager *manager, GdkWindow *parent_window)
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
331
{
332
        TimeoutDialog timeout;
333
        guint timeout_id;
334
335
        timeout.manager = manager;
336
337
        timeout.dialog = gtk_message_dialog_new (NULL,
338
                                                 GTK_DIALOG_MODAL,
339
                                                 GTK_MESSAGE_QUESTION,
340
                                                 GTK_BUTTONS_NONE,
341
                                                 _("Does the display look OK?"));
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
342
343
        timeout.countdown = CONFIRMATION_DIALOG_SECONDS;
344
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
345
        print_countdown_text (&timeout);
346
1.1.18 by Sebastien Bacher
Import upstream version 2.25.92
347
        gtk_dialog_add_button (GTK_DIALOG (timeout.dialog), _("_Restore Previous Configuration"), GTK_RESPONSE_CANCEL);
348
        gtk_dialog_add_button (GTK_DIALOG (timeout.dialog), _("_Keep This Configuration"), GTK_RESPONSE_ACCEPT);
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
349
        gtk_dialog_set_default_response (GTK_DIALOG (timeout.dialog), GTK_RESPONSE_ACCEPT); /* ah, the optimism */
350
351
        g_signal_connect (timeout.dialog, "response",
352
                          G_CALLBACK (timeout_response_cb),
353
                          &timeout);
354
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
355
        gtk_widget_realize (timeout.dialog);
356
357
        if (parent_window)
358
                gdk_window_set_transient_for (gtk_widget_get_window (timeout.dialog), parent_window);
359
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
360
        gtk_widget_show_all (timeout.dialog);
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
361
        /* We don't use g_timeout_add_seconds() since we actually care that the user sees "real" second ticks in the dialog */
362
        timeout_id = g_timeout_add (1000,
363
                                    timeout_cb,
364
                                    &timeout);
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
365
        gtk_main ();
366
367
        gtk_widget_destroy (timeout.dialog);
368
        g_source_remove (timeout_id);
369
370
        if (timeout.response_id == GTK_RESPONSE_ACCEPT)
371
                return TRUE;
372
        else
373
                return FALSE;
374
}
375
1.1.23 by Chris Coulson
Import upstream version 2.27.4
376
struct confirmation {
377
        GsdXrandrManager *manager;
378
        GdkWindow *parent_window;
379
        guint32 timestamp;
380
};
381
382
static gboolean
383
confirm_with_user_idle_cb (gpointer data)
384
{
385
        struct confirmation *confirmation = data;
386
        char *backup_filename;
387
        char *intended_filename;
388
389
        backup_filename = gnome_rr_config_get_backup_filename ();
390
        intended_filename = gnome_rr_config_get_intended_filename ();
391
392
        if (user_says_things_are_ok (confirmation->manager, confirmation->parent_window))
393
                unlink (backup_filename);
394
        else
395
                restore_backup_configuration (confirmation->manager, backup_filename, intended_filename, confirmation->timestamp);
396
397
        g_free (confirmation);
398
399
        return FALSE;
400
}
401
402
static void
403
queue_confirmation_by_user (GsdXrandrManager *manager, GdkWindow *parent_window, guint32 timestamp)
404
{
405
        struct confirmation *confirmation;
406
407
        confirmation = g_new (struct confirmation, 1);
408
        confirmation->manager = manager;
409
        confirmation->parent_window = parent_window;
410
        confirmation->timestamp = timestamp;
411
412
        g_idle_add (confirm_with_user_idle_cb, confirmation);
413
}
414
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
415
static gboolean
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
416
try_to_apply_intended_configuration (GsdXrandrManager *manager, GdkWindow *parent_window, guint32 timestamp, GError **error)
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
417
{
418
        char *backup_filename;
419
        char *intended_filename;
420
        gboolean result;
421
422
        /* Try to apply the intended configuration */
423
424
        backup_filename = gnome_rr_config_get_backup_filename ();
425
        intended_filename = gnome_rr_config_get_intended_filename ();
426
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
427
        result = apply_configuration_from_filename (manager, intended_filename, FALSE, timestamp, error);
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
428
        if (!result) {
429
                error_message (manager, _("The selected configuration for displays could not be applied"), error ? *error : NULL, NULL);
430
                restore_backup_configuration_without_messages (backup_filename, intended_filename);
431
                goto out;
1.1.23 by Chris Coulson
Import upstream version 2.27.4
432
        } else {
433
                /* We need to return as quickly as possible, so instead of
434
                 * confirming with the user right here, we do it in an idle
435
                 * handler.  The caller only expects a status for "could you
436
                 * change the RANDR configuration?", not "is the user OK with it
437
                 * as well?".
438
                 */
439
                queue_confirmation_by_user (manager, parent_window, timestamp);
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
440
        }
441
442
out:
443
        g_free (backup_filename);
444
        g_free (intended_filename);
445
446
        return result;
447
}
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
448
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
449
/* DBus method for org.gnome.SettingsDaemon.XRANDR ApplyConfiguration; see gsd-xrandr-manager.xml for the interface definition */
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
450
static gboolean
451
gsd_xrandr_manager_apply_configuration (GsdXrandrManager *manager,
452
                                        GError          **error)
453
{
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
454
        return try_to_apply_intended_configuration (manager, NULL, GDK_CURRENT_TIME, error);
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
455
}
456
457
/* DBus method for org.gnome.SettingsDaemon.XRANDR_2 ApplyConfiguration; see gsd-xrandr-manager.xml for the interface definition */
458
static gboolean
459
gsd_xrandr_manager_2_apply_configuration (GsdXrandrManager *manager,
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
460
                                          gint64            parent_window_id,
461
                                          gint64            timestamp,
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
462
                                          GError          **error)
463
{
464
        GdkWindow *parent_window;
465
        gboolean result;
466
467
        if (parent_window_id != 0)
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
468
                parent_window = gdk_window_foreign_new_for_display (gdk_display_get_default (), (GdkNativeWindow) parent_window_id);
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
469
        else
470
                parent_window = NULL;
471
472
        result = try_to_apply_intended_configuration (manager, parent_window, (guint32) timestamp, error);
473
474
        if (parent_window)
475
                g_object_unref (parent_window);
476
477
        return result;
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
478
}
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
479
480
/* We include this after the definition of gsd_xrandr_manager_apply_configuration() so the prototype will already exist */
481
#include "gsd-xrandr-manager-glue.h"
482
483
static gboolean
1.1.34 by Sebastien Bacher
Import upstream version 2.29.92
484
is_laptop (GnomeRRScreen *screen, GnomeOutputInfo *output)
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
485
{
1.1.34 by Sebastien Bacher
Import upstream version 2.29.92
486
        GnomeRROutput *rr_output;
487
488
        rr_output = gnome_rr_screen_get_output_by_name (screen, output->name);
489
        return gnome_rr_output_is_laptop (rr_output);
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
490
}
491
492
static gboolean
493
get_clone_size (GnomeRRScreen *screen, int *width, int *height)
494
{
495
        GnomeRRMode **modes = gnome_rr_screen_list_clone_modes (screen);
496
        int best_w, best_h;
497
        int i;
498
499
        best_w = 0;
500
        best_h = 0;
501
502
        for (i = 0; modes[i] != NULL; ++i) {
503
                GnomeRRMode *mode = modes[i];
504
                int w, h;
505
506
                w = gnome_rr_mode_get_width (mode);
507
                h = gnome_rr_mode_get_height (mode);
508
509
                if (w * h > best_w * best_h) {
510
                        best_w = w;
511
                        best_h = h;
512
                }
513
        }
514
515
        if (best_w > 0 && best_h > 0) {
516
                if (width)
517
                        *width = best_w;
518
                if (height)
519
                        *height = best_h;
520
521
                return TRUE;
522
        }
523
524
        return FALSE;
525
}
526
527
static void
528
print_output (GnomeOutputInfo *info)
529
{
530
        g_print ("  Output: %s attached to %s\n", info->display_name, info->name);
531
        g_print ("     status: %s\n", info->on ? "on" : "off");
532
        g_print ("     width: %d\n", info->width);
533
        g_print ("     height: %d\n", info->height);
534
        g_print ("     rate: %d\n", info->rate);
535
        g_print ("     position: %d %d\n", info->x, info->y);
536
}
537
538
static void
539
print_configuration (GnomeRRConfig *config, const char *header)
540
{
541
        int i;
542
543
        g_print ("=== %s Configuration ===\n", header);
544
        if (!config) {
545
                g_print ("  none\n");
546
                return;
547
        }
548
549
        for (i = 0; config->outputs[i] != NULL; ++i)
550
                print_output (config->outputs[i]);
551
}
552
553
static GnomeRRConfig *
554
make_clone_setup (GnomeRRScreen *screen)
555
{
556
        GnomeRRConfig *result;
557
        int width, height;
558
        int i;
559
560
        if (!get_clone_size (screen, &width, &height))
561
                return NULL;
562
563
        result = gnome_rr_config_new_current (screen);
564
565
        for (i = 0; result->outputs[i] != NULL; ++i) {
566
                GnomeOutputInfo *info = result->outputs[i];
567
568
                info->on = FALSE;
569
                if (info->connected) {
570
                        GnomeRROutput *output =
571
                                gnome_rr_screen_get_output_by_name (screen, info->name);
572
                        GnomeRRMode **modes = gnome_rr_output_list_modes (output);
573
                        int j;
574
                        int best_rate = 0;
575
576
                        for (j = 0; modes[j] != NULL; ++j) {
577
                                GnomeRRMode *mode = modes[j];
578
                                int w, h;
579
580
                                w = gnome_rr_mode_get_width (mode);
581
                                h = gnome_rr_mode_get_height (mode);
582
583
                                if (w == width && h == height) {
584
                                        int r = gnome_rr_mode_get_freq (mode);
585
                                        if (r > best_rate)
586
                                                best_rate = r;
587
                                }
588
                        }
589
590
                        if (best_rate > 0) {
591
                                info->on = TRUE;
592
                                info->width = width;
593
                                info->height = height;
594
                                info->rate = best_rate;
595
                                info->rotation = GNOME_RR_ROTATION_0;
596
                                info->x = 0;
597
                                info->y = 0;
598
                        }
599
                }
600
        }
601
602
        print_configuration (result, "clone setup");
603
604
        return result;
605
}
606
1.1.24 by Chris Coulson
Import upstream version 2.27.5
607
static GnomeRRMode *
608
find_best_mode (GnomeRROutput *output)
609
{
610
        GnomeRRMode *preferred;
611
        GnomeRRMode **modes;
612
        int best_size;
613
        int best_width, best_height, best_rate;
614
        int i;
615
        GnomeRRMode *best_mode;
616
617
        preferred = gnome_rr_output_get_preferred_mode (output);
618
        if (preferred)
619
                return preferred;
620
621
        modes = gnome_rr_output_list_modes (output);
622
        if (!modes)
623
                return NULL;
624
625
        best_size = best_width = best_height = best_rate = 0;
626
        best_mode = NULL;
627
628
        for (i = 0; modes[i] != NULL; i++) {
629
                int w, h, r;
630
                int size;
631
632
                w = gnome_rr_mode_get_width (modes[i]);
633
                h = gnome_rr_mode_get_height (modes[i]);
634
                r = gnome_rr_mode_get_freq  (modes[i]);
635
636
                size = w * h;
637
638
                if (size > best_size) {
639
                        best_size   = size;
640
                        best_width  = w;
641
                        best_height = h;
642
                        best_rate   = r;
643
                        best_mode   = modes[i];
644
                } else if (size == best_size) {
645
                        if (r > best_rate) {
646
                                best_rate = r;
647
                                best_mode = modes[i];
648
                        }
649
                }
650
        }
651
652
        return best_mode;
653
}
654
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
655
static gboolean
656
turn_on (GnomeRRScreen *screen,
657
         GnomeOutputInfo *info,
658
         int x, int y)
659
{
1.1.24 by Chris Coulson
Import upstream version 2.27.5
660
        GnomeRROutput *output = gnome_rr_screen_get_output_by_name (screen, info->name);
661
        GnomeRRMode *mode = find_best_mode (output);
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
662
663
        if (mode) {
664
                info->on = TRUE;
665
                info->x = x;
666
                info->y = y;
667
                info->width = gnome_rr_mode_get_width (mode);
668
                info->height = gnome_rr_mode_get_height (mode);
669
                info->rotation = GNOME_RR_ROTATION_0;
670
                info->rate = gnome_rr_mode_get_freq (mode);
671
672
                return TRUE;
673
        }
674
675
        return FALSE;
676
}
677
678
static GnomeRRConfig *
679
make_laptop_setup (GnomeRRScreen *screen)
680
{
681
        /* Turn on the laptop, disable everything else */
682
        GnomeRRConfig *result = gnome_rr_config_new_current (screen);
683
        int i;
684
685
        for (i = 0; result->outputs[i] != NULL; ++i) {
686
                GnomeOutputInfo *info = result->outputs[i];
687
1.1.34 by Sebastien Bacher
Import upstream version 2.29.92
688
                if (is_laptop (screen, info)) {
1.1.33 by Chris Coulson
Import upstream version 2.29.91.1
689
                        if (!turn_on (screen, info, 0, 0)) {
690
                                gnome_rr_config_free (result);
691
                                result = NULL;
692
                                break;
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
693
                        }
694
                }
695
                else {
696
                        info->on = FALSE;
697
                }
698
        }
699
700
        print_configuration (result, "Laptop setup");
701
702
        /* FIXME - Maybe we should return NULL if there is more than
703
         * one connected "laptop" screen?
704
         */
705
        return result;
706
707
}
708
1.1.24 by Chris Coulson
Import upstream version 2.27.5
709
static int
710
turn_on_and_get_rightmost_offset (GnomeRRScreen *screen, GnomeOutputInfo *info, int x)
711
{
1.1.33 by Chris Coulson
Import upstream version 2.29.91.1
712
        if (turn_on (screen, info, x, 0))
1.1.24 by Chris Coulson
Import upstream version 2.27.5
713
                x += info->width;
714
715
        return x;
716
}
717
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
718
static GnomeRRConfig *
719
make_xinerama_setup (GnomeRRScreen *screen)
720
{
721
        /* Turn on everything that has a preferred mode, and
722
         * position it from left to right
723
         */
724
        GnomeRRConfig *result = gnome_rr_config_new_current (screen);
725
        int i;
726
        int x;
727
728
        x = 0;
729
        for (i = 0; result->outputs[i] != NULL; ++i) {
730
                GnomeOutputInfo *info = result->outputs[i];
731
1.1.34 by Sebastien Bacher
Import upstream version 2.29.92
732
                if (is_laptop (screen, info))
1.1.24 by Chris Coulson
Import upstream version 2.27.5
733
                        x = turn_on_and_get_rightmost_offset (screen, info, x);
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
734
        }
735
736
        for (i = 0; result->outputs[i] != NULL; ++i) {
737
                GnomeOutputInfo *info = result->outputs[i];
738
1.1.34 by Sebastien Bacher
Import upstream version 2.29.92
739
                if (info->connected && !is_laptop (screen, info))
1.1.24 by Chris Coulson
Import upstream version 2.27.5
740
                        x = turn_on_and_get_rightmost_offset (screen, info, x);
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
741
        }
742
743
        print_configuration (result, "xinerama setup");
744
745
        return result;
746
}
747
748
static GnomeRRConfig *
749
make_other_setup (GnomeRRScreen *screen)
750
{
751
        /* Turn off all laptops, and make all external monitors clone
752
         * from (0, 0)
753
         */
754
755
        GnomeRRConfig *result = gnome_rr_config_new_current (screen);
756
        int i;
757
758
        for (i = 0; result->outputs[i] != NULL; ++i) {
759
                GnomeOutputInfo *info = result->outputs[i];
760
1.1.34 by Sebastien Bacher
Import upstream version 2.29.92
761
                if (is_laptop (screen, info)) {
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
762
                        info->on = FALSE;
763
                }
764
                else {
1.1.33 by Chris Coulson
Import upstream version 2.29.91.1
765
                        if (info->connected)
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
766
                                turn_on (screen, info, 0, 0);
767
               }
768
        }
769
770
        print_configuration (result, "other setup");
771
772
        return result;
773
}
774
775
static GPtrArray *
1.1.24 by Chris Coulson
Import upstream version 2.27.5
776
sanitize (GsdXrandrManager *manager, GPtrArray *array)
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
777
{
778
        int i;
779
        GPtrArray *new;
780
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
781
        g_debug ("before sanitizing");
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
782
783
        for (i = 0; i < array->len; ++i) {
784
                if (array->pdata[i]) {
785
                        print_configuration (array->pdata[i], "before");
786
                }
787
        }
788
789
790
        /* Remove configurations that are duplicates of
791
         * configurations earlier in the cycle
792
         */
1.1.24 by Chris Coulson
Import upstream version 2.27.5
793
        for (i = 0; i < array->len; i++) {
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
794
                int j;
795
1.1.24 by Chris Coulson
Import upstream version 2.27.5
796
                for (j = i + 1; j < array->len; j++) {
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
797
                        GnomeRRConfig *this = array->pdata[j];
798
                        GnomeRRConfig *other = array->pdata[i];
799
800
                        if (this && other && gnome_rr_config_equal (this, other)) {
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
801
                                g_debug ("removing duplicate configuration");
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
802
                                gnome_rr_config_free (this);
803
                                array->pdata[j] = NULL;
804
                                break;
805
                        }
806
                }
807
        }
808
809
        for (i = 0; i < array->len; ++i) {
810
                GnomeRRConfig *config = array->pdata[i];
811
812
                if (config) {
813
                        gboolean all_off = TRUE;
814
                        int j;
815
816
                        for (j = 0; config->outputs[j] != NULL; ++j) {
817
                                if (config->outputs[j]->on)
818
                                        all_off = FALSE;
819
                        }
820
821
                        if (all_off) {
1.1.24 by Chris Coulson
Import upstream version 2.27.5
822
                                g_debug ("removing configuration as all outputs are off");
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
823
                                gnome_rr_config_free (array->pdata[i]);
824
                                array->pdata[i] = NULL;
825
                        }
826
                }
827
        }
828
1.1.24 by Chris Coulson
Import upstream version 2.27.5
829
        /* Do a final sanitization pass.  This will remove configurations that
830
         * don't fit in the framebuffer's Virtual size.
831
         */
832
833
        for (i = 0; i < array->len; i++) {
834
                GnomeRRConfig *config = array->pdata[i];
835
836
                if (config) {
837
                        GError *error;
838
839
                        error = NULL;
840
                        if (!gnome_rr_config_applicable (config, manager->priv->rw_screen, &error)) { /* NULL-GError */
841
                                g_debug ("removing configuration which is not applicable because %s", error->message);
842
                                g_error_free (error);
843
844
                                gnome_rr_config_free (config);
845
                                array->pdata[i] = NULL;
846
                        }
847
                }
848
        }
849
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
850
        /* Remove NULL configurations */
851
        new = g_ptr_array_new ();
852
853
        for (i = 0; i < array->len; ++i) {
854
                if (array->pdata[i]) {
855
                        g_ptr_array_add (new, array->pdata[i]);
856
                        print_configuration (array->pdata[i], "Final");
857
                }
858
        }
859
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
860
        if (new->len > 0) {
861
                g_ptr_array_add (new, NULL);
862
        } else {
863
                g_ptr_array_free (new, TRUE);
864
                new = NULL;
865
        }
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
866
867
        g_ptr_array_free (array, TRUE);
868
869
        return new;
870
}
871
872
static void
873
generate_fn_f7_configs (GsdXrandrManager *mgr)
874
{
875
        GPtrArray *array = g_ptr_array_new ();
876
        GnomeRRScreen *screen = mgr->priv->rw_screen;
877
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
878
        g_debug ("Generating configurations");
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
879
880
        /* Free any existing list of configurations */
881
        if (mgr->priv->fn_f7_configs) {
882
                int i;
883
884
                for (i = 0; mgr->priv->fn_f7_configs[i] != NULL; ++i)
885
                        gnome_rr_config_free (mgr->priv->fn_f7_configs[i]);
886
                g_free (mgr->priv->fn_f7_configs);
887
888
                mgr->priv->fn_f7_configs = NULL;
889
                mgr->priv->current_fn_f7_config = -1;
890
        }
891
892
        g_ptr_array_add (array, gnome_rr_config_new_current (screen));
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
893
        g_ptr_array_add (array, make_clone_setup (screen));
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
894
        g_ptr_array_add (array, make_xinerama_setup (screen));
895
        g_ptr_array_add (array, make_laptop_setup (screen));
896
        g_ptr_array_add (array, make_other_setup (screen));
897
        g_ptr_array_add (array, gnome_rr_config_new_stored (screen, NULL)); /* NULL-GError - if this can't read the stored config, no big deal */
898
1.1.24 by Chris Coulson
Import upstream version 2.27.5
899
        array = sanitize (mgr, array);
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
900
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
901
        if (array) {
902
                mgr->priv->fn_f7_configs = (GnomeRRConfig **)g_ptr_array_free (array, FALSE);
903
                mgr->priv->current_fn_f7_config = 0;
904
        }
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
905
}
906
907
static void
908
error_message (GsdXrandrManager *mgr, const char *primary_text, GError *error_to_display, const char *secondary_text)
909
{
910
#ifdef HAVE_LIBNOTIFY
911
        GsdXrandrManagerPrivate *priv = mgr->priv;
912
        NotifyNotification *notification;
913
914
        g_assert (error_to_display == NULL || secondary_text == NULL);
915
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
916
        if (priv->status_icon)
917
                notification = notify_notification_new_with_status_icon (primary_text,
918
                                                                         error_to_display ? error_to_display->message : secondary_text,
919
                                                                         GSD_XRANDR_ICON_NAME,
920
                                                                         priv->status_icon);
921
        else
922
                notification = notify_notification_new (primary_text,
923
                                                        error_to_display ? error_to_display->message : secondary_text,
924
                                                        GSD_XRANDR_ICON_NAME,
925
                                                        NULL);
926
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
927
        notify_notification_show (notification, NULL); /* NULL-GError */
928
#else
929
        GtkWidget *dialog;
930
931
	dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
932
                                         "%s", primary_text);
933
        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s",
934
                                                  error_to_display ? error_to_display->message : secondary_text);
935
936
        gtk_dialog_run (GTK_DIALOG (dialog));
937
        gtk_widget_destroy (dialog);
938
#endif /* HAVE_LIBNOTIFY */
939
}
940
941
static void
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
942
handle_fn_f7 (GsdXrandrManager *mgr, guint32 timestamp)
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
943
{
944
        GsdXrandrManagerPrivate *priv = mgr->priv;
945
        GnomeRRScreen *screen = priv->rw_screen;
946
        GnomeRRConfig *current;
947
        GError *error;
948
949
        /* Theory of fn-F7 operation
950
         *
951
         * We maintain a datastructure "fn_f7_status", that contains
952
         * a list of GnomeRRConfig's. Each of the GnomeRRConfigs has a
953
         * mode (or "off") for each connected output.
954
         *
955
         * When the user hits fn-F7, we cycle to the next GnomeRRConfig
956
         * in the data structure. If the data structure does not exist, it
957
         * is generated. If the configs in the data structure do not match
958
         * the current hardware reality, it is regenerated.
959
         *
960
         */
961
        g_debug ("Handling fn-f7");
962
963
        error = NULL;
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
964
        if (!gnome_rr_screen_refresh (screen, &error) && error) {
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
965
                char *str;
966
967
                str = g_strdup_printf (_("Could not refresh the screen information: %s"), error->message);
968
                g_error_free (error);
969
970
                error_message (mgr, str, NULL, _("Trying to switch the monitor configuration anyway."));
971
                g_free (str);
972
        }
973
974
        if (!priv->fn_f7_configs)
975
                generate_fn_f7_configs (mgr);
976
977
        current = gnome_rr_config_new_current (screen);
978
979
        if (priv->fn_f7_configs &&
980
            (!gnome_rr_config_match (current, priv->fn_f7_configs[0]) ||
981
             !gnome_rr_config_equal (current, priv->fn_f7_configs[mgr->priv->current_fn_f7_config]))) {
982
                    /* Our view of the world is incorrect, so regenerate the
983
                     * configurations
984
                     */
985
                    generate_fn_f7_configs (mgr);
986
            }
987
988
        gnome_rr_config_free (current);
989
990
        if (priv->fn_f7_configs) {
991
                mgr->priv->current_fn_f7_config++;
992
993
                if (priv->fn_f7_configs[mgr->priv->current_fn_f7_config] == NULL)
994
                        mgr->priv->current_fn_f7_config = 0;
995
996
                g_debug ("cycling to next configuration (%d)", mgr->priv->current_fn_f7_config);
997
998
                print_configuration (priv->fn_f7_configs[mgr->priv->current_fn_f7_config], "new config");
999
1000
                g_debug ("applying");
1001
1.1.32 by Chris Coulson
Import upstream version 2.29.90
1002
                apply_configuration_and_display_error (mgr, priv->fn_f7_configs[mgr->priv->current_fn_f7_config], timestamp);
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
1003
        }
1004
        else {
1005
                g_debug ("no configurations generated");
1006
        }
1007
        g_debug ("done handling fn-f7");
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1008
}
1009
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1010
static GnomeOutputInfo *
1.1.34 by Sebastien Bacher
Import upstream version 2.29.92
1011
get_laptop_output_info (GnomeRRScreen *screen, GnomeRRConfig *config)
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1012
{
1013
        int i;
1014
1015
        for (i = 0; config->outputs[i] != NULL; i++) {
1016
                GnomeOutputInfo *info;
1017
1018
                info = config->outputs[i];
1.1.34 by Sebastien Bacher
Import upstream version 2.29.92
1019
                if (is_laptop (screen, info))
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1020
                        return info;
1021
        }
1022
1023
        return NULL;
1024
1025
}
1026
1027
static GnomeRRRotation
1028
get_next_rotation (GnomeRRRotation allowed_rotations, GnomeRRRotation current_rotation)
1029
{
1030
        int i;
1031
        int current_index;
1032
1033
        /* First, find the index of the current rotation */
1034
1035
        current_index = -1;
1036
1037
        for (i = 0; i < G_N_ELEMENTS (possible_rotations); i++) {
1038
                GnomeRRRotation r;
1039
1040
                r = possible_rotations[i];
1041
                if (r == current_rotation) {
1042
                        current_index = i;
1043
                        break;
1044
                }
1045
        }
1046
1047
        if (current_index == -1) {
1048
                /* Huh, the current_rotation was not one of the supported rotations.  Bail out. */
1049
                return current_rotation;
1050
        }
1051
1052
        /* Then, find the next rotation that is allowed */
1053
1054
        i = (current_index + 1) % G_N_ELEMENTS (possible_rotations);
1055
1056
        while (1) {
1057
                GnomeRRRotation r;
1058
1059
                r = possible_rotations[i];
1060
                if (r == current_rotation) {
1061
                        /* We wrapped around and no other rotation is suported.  Bummer. */
1062
                        return current_rotation;
1063
                } else if (r & allowed_rotations)
1064
                        return r;
1065
1066
                i = (i + 1) % G_N_ELEMENTS (possible_rotations);
1067
        }
1068
}
1069
1070
/* We use this when the XF86RotateWindows key is pressed.  That key is present
1071
 * on some tablet PCs; they use it so that the user can rotate the tablet
1072
 * easily.
1073
 */
1074
static void
1075
handle_rotate_windows (GsdXrandrManager *mgr, guint32 timestamp)
1076
{
1077
        GsdXrandrManagerPrivate *priv = mgr->priv;
1078
        GnomeRRScreen *screen = priv->rw_screen;
1079
        GnomeRRConfig *current;
1080
        GnomeOutputInfo *rotatable_output_info;
1081
        int num_allowed_rotations;
1082
        GnomeRRRotation allowed_rotations;
1083
        GnomeRRRotation next_rotation;
1084
1085
        g_debug ("Handling XF86RotateWindows");
1086
1087
        /* Which output? */
1088
1089
        current = gnome_rr_config_new_current (screen);
1090
1.1.34 by Sebastien Bacher
Import upstream version 2.29.92
1091
        rotatable_output_info = get_laptop_output_info (screen, current);
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1092
        if (rotatable_output_info == NULL) {
1093
                g_debug ("No laptop outputs found to rotate; XF86RotateWindows key will do nothing");
1094
                goto out;
1095
        }
1096
1097
        /* Which rotation? */
1098
1099
        get_allowed_rotations_for_output (current, priv->rw_screen, rotatable_output_info, &num_allowed_rotations, &allowed_rotations);
1100
        next_rotation = get_next_rotation (allowed_rotations, rotatable_output_info->rotation);
1101
1102
        if (next_rotation == rotatable_output_info->rotation) {
1103
                g_debug ("No rotations are supported other than the current one; XF86RotateWindows key will do nothing");
1104
                goto out;
1105
        }
1106
1107
        /* Rotate */
1108
1109
        rotatable_output_info->rotation = next_rotation;
1110
1.1.32 by Chris Coulson
Import upstream version 2.29.90
1111
        apply_configuration_and_display_error (mgr, current, timestamp);
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1112
1113
out:
1114
        gnome_rr_config_free (current);
1115
}
1116
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1117
static GdkFilterReturn
1118
event_filter (GdkXEvent           *xevent,
1119
              GdkEvent            *event,
1120
              gpointer             data)
1121
{
1122
        GsdXrandrManager *manager = data;
1123
        XEvent *xev = (XEvent *) xevent;
1124
1125
        if (!manager->priv->running)
1126
                return GDK_FILTER_CONTINUE;
1127
1128
        /* verify we have a key event */
1129
        if (xev->xany.type != KeyPress && xev->xany.type != KeyRelease)
1130
                return GDK_FILTER_CONTINUE;
1131
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1132
        if (xev->xany.type == KeyPress) {
1133
                if (xev->xkey.keycode == manager->priv->switch_video_mode_keycode)
1134
                        handle_fn_f7 (manager, xev->xkey.time);
1135
                else if (xev->xkey.keycode == manager->priv->rotate_windows_keycode)
1136
                        handle_rotate_windows (manager, xev->xkey.time);
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1137
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1138
                return GDK_FILTER_CONTINUE;
1139
        }
1140
1141
        return GDK_FILTER_CONTINUE;
1142
}
1143
1144
static void
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1145
refresh_tray_icon_menu_if_active (GsdXrandrManager *manager, guint32 timestamp)
1146
{
1147
        GsdXrandrManagerPrivate *priv = manager->priv;
1148
1149
        if (priv->popup_menu) {
1150
                gtk_menu_shell_cancel (GTK_MENU_SHELL (priv->popup_menu)); /* status_icon_popup_menu_selection_done_cb() will free everything */
1151
                status_icon_popup_menu (manager, 0, timestamp);
1152
        }
1153
}
1154
1155
static void
1156
auto_configure_outputs (GsdXrandrManager *manager, guint32 timestamp)
1157
{
1158
        GsdXrandrManagerPrivate *priv = manager->priv;
1159
        GnomeRRConfig *config;
1160
        int i;
1161
        GList *just_turned_on;
1162
        GList *l;
1163
        int x;
1164
        GError *error;
1.1.24 by Chris Coulson
Import upstream version 2.27.5
1165
        gboolean applicable;
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1166
1167
        config = gnome_rr_config_new_current (priv->rw_screen);
1168
1169
        /* For outputs that are connected and on (i.e. they have a CRTC assigned
1170
         * to them, so they are getting a signal), we leave them as they are
1171
         * with their current modes.
1172
         *
1173
         * For other outputs, we will turn on connected-but-off outputs and turn
1174
         * off disconnected-but-on outputs.
1175
         *
1176
         * FIXME: If an output remained connected+on, it would be nice to ensure
1177
         * that the output's CRTCs still has a reasonable mode (think of
1178
         * changing one monitor for another with different capabilities).
1179
         */
1180
1181
        just_turned_on = NULL;
1182
1183
        for (i = 0; config->outputs[i] != NULL; i++) {
1184
                GnomeOutputInfo *output = config->outputs[i];
1185
1186
                if (output->connected && !output->on) {
1187
                        output->on = TRUE;
1188
                        output->rotation = GNOME_RR_ROTATION_0;
1189
                        just_turned_on = g_list_prepend (just_turned_on, GINT_TO_POINTER (i));
1190
                } else if (!output->connected && output->on)
1191
                        output->on = FALSE;
1192
        }
1193
1194
        /* Now, lay out the outputs from left to right.  Put first the outputs
1195
         * which remained on; put last the outputs that were newly turned on.
1196
         */
1197
1198
        x = 0;
1199
1200
        /* First, outputs that remained on */
1201
1202
        for (i = 0; config->outputs[i] != NULL; i++) {
1203
                GnomeOutputInfo *output = config->outputs[i];
1204
1205
                if (g_list_find (just_turned_on, GINT_TO_POINTER (i)))
1206
                        continue;
1207
1208
                if (output->on) {
1209
                        g_assert (output->connected);
1210
1211
                        output->x = x;
1212
                        output->y = 0;
1213
1214
                        x += output->width;
1215
                }
1216
        }
1217
1218
        /* Second, outputs that were newly-turned on */
1219
1220
        for (l = just_turned_on; l; l = l->next) {
1221
                GnomeOutputInfo *output;
1222
1223
                i = GPOINTER_TO_INT (l->data);
1224
                output = config->outputs[i];
1225
1226
                g_assert (output->on && output->connected);
1227
1228
                output->x = x;
1229
                output->y = 0;
1230
1231
                /* since the output was off, use its preferred width/height (it doesn't have a real width/height yet) */
1232
                output->width = output->pref_width;
1233
                output->height = output->pref_height;
1234
1235
                x += output->width;
1236
        }
1237
1.1.24 by Chris Coulson
Import upstream version 2.27.5
1238
        /* Check if we have a large enough framebuffer size.  If not, turn off
1239
         * outputs from right to left until we reach a usable size.
1240
         */
1241
1242
        just_turned_on = g_list_reverse (just_turned_on); /* now the outputs here are from right to left */
1243
1244
        l = just_turned_on;
1245
        while (1) {
1246
                GnomeOutputInfo *output;
1247
                gboolean is_bounds_error;
1248
1249
                error = NULL;
1250
                applicable = gnome_rr_config_applicable (config, priv->rw_screen, &error);
1251
1252
                if (applicable)
1253
                        break;
1254
1255
                is_bounds_error = g_error_matches (error, GNOME_RR_ERROR, GNOME_RR_ERROR_BOUNDS_ERROR);
1256
                g_error_free (error);
1257
1258
                if (!is_bounds_error)
1259
                        break;
1260
1261
                if (l) {
1262
                        i = GPOINTER_TO_INT (l->data);
1263
                        l = l->next;
1264
1265
                        output = config->outputs[i];
1266
                        output->on = FALSE;
1267
                } else
1268
                        break;
1269
        }
1270
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1271
        /* Apply the configuration! */
1272
1.1.32 by Chris Coulson
Import upstream version 2.29.90
1273
        if (applicable)
1274
                apply_configuration_and_display_error (manager, config, timestamp);
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1275
1276
        g_list_free (just_turned_on);
1277
        gnome_rr_config_free (config);
1278
1279
        /* Finally, even though we did a best-effort job in sanitizing the
1280
         * outputs, we don't know the physical layout of the monitors.  We'll
1281
         * start the display capplet so that the user can tweak things to his
1282
         * liking.
1283
         */
1284
1285
#if 0
1286
        /* FIXME: This is disabled for now.  The capplet is not a single-instance application.
1287
         * If you do this:
1288
         *
1289
         *   1. Start the display capplet
1290
         *
1291
         *   2. Plug an extra monitor
1292
         *
1293
         *   3. Hit the "Detect displays" button
1294
         *
1295
         * Then we will get a RANDR event because X re-probes the outputs.  We don't want to
1296
         * start up a second display capplet right there!
1297
         */
1298
1299
        run_display_capplet (NULL);
1300
#endif
1301
}
1302
1303
static void
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1304
apply_color_profiles (void)
1305
{
1306
        gboolean ret;
1307
        GError *error = NULL;
1308
1309
        /* run the gnome-color-manager apply program */
1310
        ret = g_spawn_command_line_async (BINDIR "/gcm-apply", &error);
1311
        if (!ret) {
1312
                /* only print the warning if the binary is installed */
1313
                if (error->code != G_SPAWN_ERROR_NOENT) {
1314
                        g_warning ("failed to apply color profiles: %s", error->message);
1315
                }
1316
                g_error_free (error);
1317
        }
1318
}
1319
1320
static void
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1321
on_randr_event (GnomeRRScreen *screen, gpointer data)
1322
{
1323
        GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1324
        GsdXrandrManagerPrivate *priv = manager->priv;
1325
        guint32 change_timestamp, config_timestamp;
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1326
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1327
        if (!priv->running)
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1328
                return;
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1329
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1330
        gnome_rr_screen_get_timestamps (screen, &change_timestamp, &config_timestamp);
1331
1332
        if (change_timestamp >= config_timestamp) {
1333
                /* The event is due to an explicit configuration change.
1334
                 *
1335
                 * If the change was performed by us, then we need to do nothing.
1336
                 *
1337
                 * If the change was done by some other X client, we don't need
1338
                 * to do anything, either; the screen is already configured.
1339
                 */
1340
                show_timestamps_dialog (manager, "ignoring since change > config");
1341
        } else {
1342
                /* Here, config_timestamp > change_timestamp.  This means that
1343
                 * the screen got reconfigured because of hotplug/unplug; the X
1344
                 * server is just notifying us, and we need to configure the
1345
                 * outputs in a sane way.
1346
                 */
1347
1348
1349
#if 1
1350
                if (config_timestamp != priv->last_config_timestamp) {
1351
                        priv->last_config_timestamp = config_timestamp;
1352
                        auto_configure_outputs (manager, config_timestamp);
1353
                }
1354
#else
1355
                /* WHY THIS CODE IS DISABLED:
1356
                 *
1357
                 * The strategy of "on hotplug or unsuspend, restore a
1358
                 * known-good configuration, and fall back to autoconfiguration"
1359
                 * works fine as long as you don't happen to be running
1360
                 * gnome-display-properties and click its "Detect displays"
1361
                 * button.
1362
                 *
1363
                 * If you do that, the RANDR calls from g-d-p will cause the X
1364
                 * server to re-probe the RANDR outputs.  The server will send
1365
                 * us an event, we'll restore the configuration to something
1366
                 * else... and you'll be weirded out, because "just detecting
1367
                 * your monitors" should not change the current configuration,
1368
                 * right?
1369
                 *
1370
                 * We may need some kind of D-bus API so that g-d-p can inhibit
1371
                 * this RANDR plugin's reconfiguration-fu when the "Detect
1372
                 * displays" button is being used.
1373
                 */
1374
1375
                char *intended_filename;
1376
                GError *error;
1377
                gboolean success;
1378
1379
                show_timestamps_dialog (manager, "need to deal with reconfiguration, as config >= change");
1380
1381
                intended_filename = gnome_rr_config_get_intended_filename ();
1382
1383
                error = NULL;
1384
                success = apply_configuration_from_filename (manager, intended_filename, TRUE, config_timestamp, &error);
1385
                g_free (intended_filename);
1386
1387
                if (!success) {
1388
                        /* We don't bother checking the error type.
1389
                         *
1390
                         * Both G_FILE_ERROR_NOENT and
1391
                         * GNOME_RR_ERROR_NO_MATCHING_CONFIG would mean, "there
1392
                         * was no configuration to apply, or none that matched
1393
                         * the current outputs", and in that case we need to run
1394
                         * our fallback.
1395
                         *
1396
                         * Any other error means "we couldn't do the smart thing
1397
                         * of using a previously- saved configuration, anyway,
1398
                         * for some other reason.  In that case, we also need to
1399
                         * run our fallback to avoid leaving the user with a
1400
                         * bogus configuration.
1401
                         */
1402
1403
                        if (error)
1404
                                g_error_free (error);
1405
1406
                        auto_configure_outputs (manager, config_timestamp);
1407
                }
1408
#endif
1409
        }
1410
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1411
        /* poke gnome-color-manager */
1412
        apply_color_profiles ();
1413
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1414
        refresh_tray_icon_menu_if_active (manager, MAX (change_timestamp, config_timestamp));
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1415
}
1416
1417
static void
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1418
run_display_capplet (GtkWidget *widget)
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1419
{
1420
        GdkScreen *screen;
1421
        GError *error;
1422
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1423
        if (widget)
1424
                screen = gtk_widget_get_screen (widget);
1425
        else
1426
                screen = gdk_screen_get_default ();
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1427
1428
        error = NULL;
1429
        if (!gdk_spawn_command_line_on_screen (screen, GSD_XRANDR_DISPLAY_CAPPLET, &error)) {
1430
		GtkWidget *dialog;
1431
1432
		dialog = gtk_message_dialog_new_with_markup (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
1433
                                                             "<span weight=\"bold\" size=\"larger\">"
1434
                                                             "Display configuration could not be run"
1435
                                                             "</span>\n\n"
1436
                                                             "%s", error->message);
1437
		gtk_dialog_run (GTK_DIALOG (dialog));
1438
		gtk_widget_destroy (dialog);
1439
1440
		g_error_free (error);
1441
        }
1442
}
1443
1444
static void
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1445
popup_menu_configure_display_cb (GtkMenuItem *item, gpointer data)
1446
{
1447
        run_display_capplet (GTK_WIDGET (item));
1448
}
1449
1450
static void
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1451
status_icon_popup_menu_selection_done_cb (GtkMenuShell *menu_shell, gpointer data)
1452
{
1453
        GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
1454
        struct GsdXrandrManagerPrivate *priv = manager->priv;
1455
1456
        gtk_widget_destroy (priv->popup_menu);
1457
        priv->popup_menu = NULL;
1458
1459
        gnome_rr_labeler_hide (priv->labeler);
1460
        g_object_unref (priv->labeler);
1461
        priv->labeler = NULL;
1462
1463
        gnome_rr_config_free (priv->configuration);
1464
        priv->configuration = NULL;
1465
}
1466
1467
#define OUTPUT_TITLE_ITEM_BORDER 2
1468
#define OUTPUT_TITLE_ITEM_PADDING 4
1469
1470
/* This is an expose-event hander for the title label for each GnomeRROutput.
1471
 * We want each title to have a colored background, so we paint that background, then
1472
 * return FALSE to let GtkLabel expose itself (i.e. paint the label's text), and then
1473
 * we have a signal_connect_after handler as well.  See the comments below
1474
 * to see why that "after" handler is needed.
1475
 */
1476
static gboolean
1477
output_title_label_expose_event_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1478
{
1479
        GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
1480
        struct GsdXrandrManagerPrivate *priv = manager->priv;
1481
        GnomeOutputInfo *output;
1482
        GdkColor color;
1483
        cairo_t *cr;
1484
1485
        g_assert (GTK_IS_LABEL (widget));
1486
1487
        output = g_object_get_data (G_OBJECT (widget), "output");
1488
        g_assert (output != NULL);
1489
1490
        g_assert (priv->labeler != NULL);
1491
1492
        /* Draw a black rectangular border, filled with the color that corresponds to this output */
1493
1494
        gnome_rr_labeler_get_color_for_output (priv->labeler, output, &color);
1495
1496
        cr = gdk_cairo_create (widget->window);
1497
1498
        cairo_set_source_rgb (cr, 0, 0, 0);
1499
        cairo_set_line_width (cr, OUTPUT_TITLE_ITEM_BORDER);
1500
        cairo_rectangle (cr,
1501
                         widget->allocation.x + OUTPUT_TITLE_ITEM_BORDER / 2.0,
1502
                         widget->allocation.y + OUTPUT_TITLE_ITEM_BORDER / 2.0,
1503
                         widget->allocation.width - OUTPUT_TITLE_ITEM_BORDER,
1504
                         widget->allocation.height - OUTPUT_TITLE_ITEM_BORDER);
1505
        cairo_stroke (cr);
1506
1507
        gdk_cairo_set_source_color (cr, &color);
1508
        cairo_rectangle (cr,
1509
                         widget->allocation.x + OUTPUT_TITLE_ITEM_BORDER,
1510
                         widget->allocation.y + OUTPUT_TITLE_ITEM_BORDER,
1511
                         widget->allocation.width - 2 * OUTPUT_TITLE_ITEM_BORDER,
1512
                         widget->allocation.height - 2 * OUTPUT_TITLE_ITEM_BORDER);
1513
1514
        cairo_fill (cr);
1515
1516
        /* We want the label to always show up as if it were sensitive
1517
         * ("style->fg[GTK_STATE_NORMAL]"), even though the label is insensitive
1518
         * due to being inside an insensitive menu item.  So, here we have a
1519
         * HACK in which we frob the label's state directly.  GtkLabel's expose
1520
         * handler will be run after this function, so it will think that the
1521
         * label is in GTK_STATE_NORMAL.  We reset the label's state back to
1522
         * insensitive in output_title_label_after_expose_event_cb().
1523
         *
1524
         * Yay for fucking with GTK+'s internals.
1525
         */
1526
1527
        widget->state = GTK_STATE_NORMAL;
1528
1.1.15 by Sebastien Bacher
Import upstream version 2.25.2
1529
        return FALSE;
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1530
}
1531
1532
/* See the comment in output_title_event_box_expose_event_cb() about this funny label widget */
1533
static gboolean
1534
output_title_label_after_expose_event_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
1535
{
1536
        g_assert (GTK_IS_LABEL (widget));
1537
        widget->state = GTK_STATE_INSENSITIVE;
1538
1539
        return FALSE;
1540
}
1541
1542
static void
1543
title_item_size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation, gpointer data)
1544
{
1545
        /* When GtkMenu does size_request on its items, it asks them for their "toggle size",
1546
         * which will be non-zero when there are check/radio items.  GtkMenu remembers
1547
         * the largest of those sizes.  During the size_allocate pass, GtkMenu calls
1548
         * gtk_menu_item_toggle_size_allocate() with that value, to tell the menu item
1549
         * that it should later paint its child a bit to the right of its edge.
1550
         *
1551
         * However, we want the "title" menu items for each RANDR output to span the *whole*
1552
         * allocation of the menu item, not just the "allocation minus toggle" area.
1553
         *
1554
         * So, we let the menu item size_allocate itself as usual, but this
1555
         * callback gets run afterward.  Here we hack a toggle size of 0 into
1556
         * the menu item, and size_allocate it by hand *again*.  We also need to
1557
         * avoid recursing into this function.
1558
         */
1559
1560
        g_assert (GTK_IS_MENU_ITEM (widget));
1561
1562
        gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (widget), 0);
1563
1564
        g_signal_handlers_block_by_func (widget, title_item_size_allocate_cb, NULL);
1565
1566
        /* Sigh. There is no way to turn on GTK_ALLOC_NEEDED outside of GTK+
1567
         * itself; also, since calling size_allocate on a widget with the same
1568
         * allcation is a no-op, we need to allocate with a "different" size
1569
         * first.
1570
         */
1571
1572
        allocation->width++;
1573
        gtk_widget_size_allocate (widget, allocation);
1574
1575
        allocation->width--;
1576
        gtk_widget_size_allocate (widget, allocation);
1577
1578
        g_signal_handlers_unblock_by_func (widget, title_item_size_allocate_cb, NULL);
1579
}
1580
1581
static GtkWidget *
1582
make_menu_item_for_output_title (GsdXrandrManager *manager, GnomeOutputInfo *output)
1583
{
1584
        GtkWidget *item;
1585
        GtkWidget *label;
1586
        char *str;
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1587
	GdkColor black = { 0, 0, 0, 0 };
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1588
1589
        item = gtk_menu_item_new ();
1590
1591
        g_signal_connect (item, "size-allocate",
1592
                          G_CALLBACK (title_item_size_allocate_cb), NULL);
1593
1594
        str = g_markup_printf_escaped ("<b>%s</b>", output->display_name);
1595
        label = gtk_label_new (NULL);
1596
        gtk_label_set_markup (GTK_LABEL (label), str);
1597
        g_free (str);
1598
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1599
	/* Make the label explicitly black.  We don't want it to follow the
1600
	 * theme's colors, since the label is always shown against a light
1601
	 * pastel background.  See bgo#556050
1602
	 */
1603
	gtk_widget_modify_fg (label, GTK_WIDGET_STATE (label), &black);
1604
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1605
        /* Add padding around the label to fit the box that we'll draw for color-coding */
1606
        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1607
        gtk_misc_set_padding (GTK_MISC (label),
1608
                              OUTPUT_TITLE_ITEM_BORDER + OUTPUT_TITLE_ITEM_PADDING,
1609
                              OUTPUT_TITLE_ITEM_BORDER + OUTPUT_TITLE_ITEM_PADDING);
1610
1611
        gtk_container_add (GTK_CONTAINER (item), label);
1612
1613
        /* We want to paint a colored box as the background of the label, so we connect
1614
         * to its expose-event signal.  See the comment in *** to see why need to connect
1615
         * to the label both 'before' and 'after'.
1616
         */
1617
        g_signal_connect (label, "expose-event",
1618
                          G_CALLBACK (output_title_label_expose_event_cb), manager);
1619
        g_signal_connect_after (label, "expose-event",
1620
                                G_CALLBACK (output_title_label_after_expose_event_cb), manager);
1621
1622
        g_object_set_data (G_OBJECT (label), "output", output);
1623
1624
        gtk_widget_set_sensitive (item, FALSE); /* the title is not selectable */
1625
        gtk_widget_show_all (item);
1626
1627
        return item;
1628
}
1629
1630
static void
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1631
get_allowed_rotations_for_output (GnomeRRConfig *config,
1632
                                  GnomeRRScreen *rr_screen,
1633
                                  GnomeOutputInfo *output,
1634
                                  int *out_num_rotations,
1635
                                  GnomeRRRotation *out_rotations)
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1636
{
1637
        GnomeRRRotation current_rotation;
1638
        int i;
1639
1640
        *out_num_rotations = 0;
1641
        *out_rotations = 0;
1642
1643
        current_rotation = output->rotation;
1644
1645
        /* Yay for brute force */
1646
1647
        for (i = 0; i < G_N_ELEMENTS (possible_rotations); i++) {
1648
                GnomeRRRotation rotation_to_test;
1649
1650
                rotation_to_test = possible_rotations[i];
1651
1652
                output->rotation = rotation_to_test;
1653
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1654
                if (gnome_rr_config_applicable (config, rr_screen, NULL)) { /* NULL-GError */
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1655
                        (*out_num_rotations)++;
1656
                        (*out_rotations) |= rotation_to_test;
1657
                }
1658
        }
1659
1660
        output->rotation = current_rotation;
1661
1662
        if (*out_num_rotations == 0 || *out_rotations == 0) {
1663
                g_warning ("Huh, output %p says it doesn't support any rotations, and yet it has a current rotation?", output);
1664
                *out_num_rotations = 1;
1665
                *out_rotations = output->rotation;
1666
        }
1667
}
1668
1669
static void
1670
add_unsupported_rotation_item (GsdXrandrManager *manager)
1671
{
1672
        struct GsdXrandrManagerPrivate *priv = manager->priv;
1673
        GtkWidget *item;
1674
        GtkWidget *label;
1675
1676
        item = gtk_menu_item_new ();
1677
1678
        label = gtk_label_new (NULL);
1679
        gtk_label_set_markup (GTK_LABEL (label), _("<i>Rotation not supported</i>"));
1680
        gtk_container_add (GTK_CONTAINER (item), label);
1681
1682
        gtk_widget_show_all (item);
1683
        gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
1684
}
1685
1686
static void
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
1687
ensure_current_configuration_is_saved (void)
1688
{
1689
        GnomeRRScreen *rr_screen;
1690
        GnomeRRConfig *rr_config;
1691
1692
        /* Normally, gnome_rr_config_save() creates a backup file based on the
1693
         * old monitors.xml.  However, if *that* file didn't exist, there is
1694
         * nothing from which to create a backup.  So, here we'll save the
1695
         * current/unchanged configuration and then let our caller call
1696
         * gnome_rr_config_save() again with the new/changed configuration, so
1697
         * that there *will* be a backup file in the end.
1698
         */
1699
1700
        rr_screen = gnome_rr_screen_new (gdk_screen_get_default (), NULL, NULL, NULL); /* NULL-GError */
1701
        if (!rr_screen)
1702
                return;
1703
1704
        rr_config = gnome_rr_config_new_current (rr_screen);
1705
        gnome_rr_config_save (rr_config, NULL); /* NULL-GError */
1706
1707
        gnome_rr_config_free (rr_config);
1708
        gnome_rr_screen_destroy (rr_screen);
1709
}
1710
1711
static void
1.1.15 by Sebastien Bacher
Import upstream version 2.25.2
1712
output_rotation_item_activate_cb (GtkCheckMenuItem *item, gpointer data)
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1713
{
1714
        GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
1715
        struct GsdXrandrManagerPrivate *priv = manager->priv;
1716
        GnomeOutputInfo *output;
1717
        GnomeRRRotation rotation;
1718
        GError *error;
1719
1.1.15 by Sebastien Bacher
Import upstream version 2.25.2
1720
	/* Not interested in deselected items */
1721
	if (!gtk_check_menu_item_get_active (item))
1722
		return;
1723
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
1724
        ensure_current_configuration_is_saved ();
1725
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1726
        output = g_object_get_data (G_OBJECT (item), "output");
1727
        rotation = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "rotation"));
1728
1729
        output->rotation = rotation;
1730
1731
        error = NULL;
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
1732
        if (!gnome_rr_config_save (priv->configuration, &error)) {
1733
                error_message (manager, _("Could not save monitor configuration"), error, NULL);
1734
                if (error)
1735
                        g_error_free (error);
1736
1737
                return;
0.2.1 by Josselin Mouette
Import upstream version 2.24.1
1738
        }
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
1739
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1740
        try_to_apply_intended_configuration (manager, NULL, gtk_get_current_event_time (), NULL); /* NULL-GError */
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1741
}
1742
1743
static void
1744
add_items_for_rotations (GsdXrandrManager *manager, GnomeOutputInfo *output, GnomeRRRotation allowed_rotations)
1745
{
1746
        typedef struct {
1747
                GnomeRRRotation	rotation;
1748
                const char *	name;
1749
        } RotationInfo;
1750
        static const RotationInfo rotations[] = {
1751
                { GNOME_RR_ROTATION_0, N_("Normal") },
1752
                { GNOME_RR_ROTATION_90, N_("Left") },
1753
                { GNOME_RR_ROTATION_270, N_("Right") },
1754
                { GNOME_RR_ROTATION_180, N_("Upside Down") },
1755
                /* We don't allow REFLECT_X or REFLECT_Y for now, as gnome-display-properties doesn't allow them, either */
1756
        };
1757
1758
        struct GsdXrandrManagerPrivate *priv = manager->priv;
1759
        int i;
1760
        GSList *group;
1761
        GtkWidget *active_item;
1762
        gulong active_item_activate_id;
1763
1764
        group = NULL;
1765
        active_item = NULL;
1766
        active_item_activate_id = 0;
1767
1768
        for (i = 0; i < G_N_ELEMENTS (rotations); i++) {
1769
                GnomeRRRotation rot;
1770
                GtkWidget *item;
1771
                gulong activate_id;
1772
1773
                rot = rotations[i].rotation;
1774
1775
                if ((allowed_rotations & rot) == 0) {
1776
                        /* don't display items for rotations which are
1777
                         * unavailable.  Their availability is not under the
1778
                         * user's control, anyway.
1779
                         */
1780
                        continue;
1781
                }
1782
1783
                item = gtk_radio_menu_item_new_with_label (group, _(rotations[i].name));
1784
                gtk_widget_show_all (item);
1785
                gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
1786
1787
                g_object_set_data (G_OBJECT (item), "output", output);
1788
                g_object_set_data (G_OBJECT (item), "rotation", GINT_TO_POINTER (rot));
1789
1790
                activate_id = g_signal_connect (item, "activate",
1791
                                                G_CALLBACK (output_rotation_item_activate_cb), manager);
1792
1793
                group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
1794
1795
                if (rot == output->rotation) {
1796
                        active_item = item;
1797
                        active_item_activate_id = activate_id;
1798
                }
1799
        }
1800
1801
        if (active_item) {
1802
                /* Block the signal temporarily so our callback won't be called;
1803
                 * we are just setting up the UI.
1804
                 */
1805
                g_signal_handler_block (active_item, active_item_activate_id);
1806
1807
                gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (active_item), TRUE);
1808
1809
                g_signal_handler_unblock (active_item, active_item_activate_id);
1810
        }
1811
1812
}
1813
1814
static void
1815
add_rotation_items_for_output (GsdXrandrManager *manager, GnomeOutputInfo *output)
1816
{
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1817
        struct GsdXrandrManagerPrivate *priv = manager->priv;
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1818
        int num_rotations;
1819
        GnomeRRRotation rotations;
1820
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1821
        get_allowed_rotations_for_output (priv->configuration, priv->rw_screen, output, &num_rotations, &rotations);
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1822
1823
        if (num_rotations == 1)
1824
                add_unsupported_rotation_item (manager);
1825
        else
1826
                add_items_for_rotations (manager, output, rotations);
1827
}
1828
1829
static void
1830
add_menu_items_for_output (GsdXrandrManager *manager, GnomeOutputInfo *output)
1831
{
1832
        struct GsdXrandrManagerPrivate *priv = manager->priv;
1833
        GtkWidget *item;
1834
1835
        item = make_menu_item_for_output_title (manager, output);
1836
        gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
1837
1838
        add_rotation_items_for_output (manager, output);
1839
}
1840
1841
static void
1842
add_menu_items_for_outputs (GsdXrandrManager *manager)
1843
{
1844
        struct GsdXrandrManagerPrivate *priv = manager->priv;
1845
        int i;
1846
1847
        for (i = 0; priv->configuration->outputs[i] != NULL; i++) {
1848
                if (priv->configuration->outputs[i]->connected)
1849
                        add_menu_items_for_output (manager, priv->configuration->outputs[i]);
1850
        }
1851
}
1852
1853
static void
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1854
status_icon_popup_menu (GsdXrandrManager *manager, guint button, guint32 timestamp)
1855
{
1856
        struct GsdXrandrManagerPrivate *priv = manager->priv;
1857
        GtkWidget *item;
1858
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1859
        g_assert (priv->configuration == NULL);
1860
        priv->configuration = gnome_rr_config_new_current (priv->rw_screen);
1861
1862
        g_assert (priv->labeler == NULL);
1863
        priv->labeler = gnome_rr_labeler_new (priv->configuration);
1864
1865
        g_assert (priv->popup_menu == NULL);
1866
        priv->popup_menu = gtk_menu_new ();
1867
1868
        add_menu_items_for_outputs (manager);
1869
1870
        item = gtk_separator_menu_item_new ();
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1871
        gtk_widget_show (item);
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1872
        gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1873
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
1874
        item = gtk_menu_item_new_with_mnemonic (_("_Configure Display Settings ..."));
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1875
        g_signal_connect (item, "activate",
1876
                          G_CALLBACK (popup_menu_configure_display_cb), manager);
1877
        gtk_widget_show (item);
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1878
        gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), item);
1879
1880
        g_signal_connect (priv->popup_menu, "selection-done",
1881
                          G_CALLBACK (status_icon_popup_menu_selection_done_cb), manager);
1882
1883
        gtk_menu_popup (GTK_MENU (priv->popup_menu), NULL, NULL,
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1884
                        gtk_status_icon_position_menu,
1885
                        priv->status_icon, button, timestamp);
1886
}
1887
1888
static void
1889
status_icon_activate_cb (GtkStatusIcon *status_icon, gpointer data)
1890
{
1891
        GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
1892
1893
        /* Suck; we don't get a proper button/timestamp */
1894
        status_icon_popup_menu (manager, 0, gtk_get_current_event_time ());
1895
}
1896
1897
static void
1898
status_icon_popup_menu_cb (GtkStatusIcon *status_icon, guint button, guint32 timestamp, gpointer data)
1899
{
1900
        GsdXrandrManager *manager = GSD_XRANDR_MANAGER (data);
1901
1902
        status_icon_popup_menu (manager, button, timestamp);
1903
}
1904
1905
static void
1906
status_icon_start (GsdXrandrManager *manager)
1907
{
1908
        struct GsdXrandrManagerPrivate *priv = manager->priv;
1909
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1910
        /* Ideally, we should detect if we are on a tablet and only display
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1911
         * the icon in that case.
1912
         */
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
1913
        if (!priv->status_icon) {
1914
                priv->status_icon = gtk_status_icon_new_from_icon_name (GSD_XRANDR_ICON_NAME);
1.1.21 by Sebastien Bacher
Import upstream version 2.27.1
1915
                gtk_status_icon_set_tooltip_text (priv->status_icon, _("Configure display settings"));
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1916
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
1917
                g_signal_connect (priv->status_icon, "activate",
1918
                                  G_CALLBACK (status_icon_activate_cb), manager);
1919
                g_signal_connect (priv->status_icon, "popup-menu",
1920
                                  G_CALLBACK (status_icon_popup_menu_cb), manager);
1921
        }
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
1922
}
1923
1924
static void
1925
status_icon_stop (GsdXrandrManager *manager)
1926
{
1927
        struct GsdXrandrManagerPrivate *priv = manager->priv;
1928
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
1929
        if (priv->status_icon) {
1930
                g_signal_handlers_disconnect_by_func (
1931
                        priv->status_icon, G_CALLBACK (status_icon_activate_cb), manager);
1932
                g_signal_handlers_disconnect_by_func (
1933
                        priv->status_icon, G_CALLBACK (status_icon_popup_menu_cb), manager);
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
1934
1.1.30 by Chris Coulson
Import upstream version 2.29.5
1935
                /* hide the icon before unreffing it; otherwise we will leak
1936
                   whitespace in the notification area due to a bug in there */
1937
                gtk_status_icon_set_visible (priv->status_icon, FALSE);
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
1938
                g_object_unref (priv->status_icon);
1939
                priv->status_icon = NULL;
1940
        }
1941
}
1942
1943
static void
1944
start_or_stop_icon (GsdXrandrManager *manager)
1945
{
1946
        if (gconf_client_get_bool (manager->priv->client, CONF_DIR "/" CONF_KEY, NULL)) {
1947
                status_icon_start (manager);
1948
        }
1949
        else {
1950
                status_icon_stop (manager);
1951
        }
1952
}
1953
1954
static void
1955
on_config_changed (GConfClient          *client,
1956
                   guint                 cnxn_id,
1957
                   GConfEntry           *entry,
1958
                   GsdXrandrManager *manager)
1959
{
1960
        start_or_stop_icon (manager);
1 by Sebastien Bacher
Import upstream version 2.21.5.2
1961
}
1962
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
1963
static void
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1964
apply_intended_configuration (GsdXrandrManager *manager, const char *intended_filename, guint32 timestamp)
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
1965
{
1966
        GError *my_error;
1967
1968
        my_error = NULL;
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1969
        if (!apply_configuration_from_filename (manager, intended_filename, FALSE, timestamp, &my_error)) {
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
1970
                if (my_error) {
1.1.20 by Sebastien Bacher
Import upstream version 2.26.1
1971
                        if (!g_error_matches (my_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
1972
                                error_message (manager, _("Could not apply the stored configuration for monitors"), my_error, NULL);
1973
1974
                        g_error_free (my_error);
1975
                }
1976
        }
1977
}
1978
1979
static void
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1980
apply_stored_configuration_at_startup (GsdXrandrManager *manager, guint32 timestamp)
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
1981
{
1982
        GError *my_error;
1983
        gboolean success;
1984
        char *backup_filename;
1985
        char *intended_filename;
1986
1987
        backup_filename = gnome_rr_config_get_backup_filename ();
1988
        intended_filename = gnome_rr_config_get_intended_filename ();
1989
1990
        /* 1. See if there was a "saved" configuration.  If there is one, it means
1991
         * that the user had selected to change the display configuration, but the
1992
         * machine crashed.  In that case, we'll apply *that* configuration and save it on top of the
1993
         * "intended" one.
1994
         */
1995
1996
        my_error = NULL;
1997
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
1998
        success = apply_configuration_from_filename (manager, backup_filename, FALSE, timestamp, &my_error);
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
1999
        if (success) {
2000
                /* The backup configuration existed, and could be applied
2001
                 * successfully, so we must restore it on top of the
2002
                 * failed/intended one.
2003
                 */
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
2004
                restore_backup_configuration (manager, backup_filename, intended_filename, timestamp);
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
2005
                goto out;
2006
        }
2007
2008
        if (!g_error_matches (my_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
2009
                /* Epic fail:  there (probably) was a backup configuration, but
2010
                 * we could not apply it.  The only thing we can do is delete
2011
                 * the backup configuration.  Let's hope that the user doesn't
2012
                 * get left with an unusable display...
2013
                 */
2014
2015
                unlink (backup_filename);
2016
                goto out;
2017
        }
2018
2019
        /* 2. There was no backup configuration!  This means we are
2020
         * good.  Apply the intended configuration instead.
2021
         */
2022
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
2023
        apply_intended_configuration (manager, intended_filename, timestamp);
1.1.17 by Sebastien Bacher
Import upstream version 2.25.90
2024
2025
out:
2026
2027
        if (my_error)
2028
                g_error_free (my_error);
2029
2030
        g_free (backup_filename);
2031
        g_free (intended_filename);
2032
}
2033
1 by Sebastien Bacher
Import upstream version 2.21.5.2
2034
gboolean
2035
gsd_xrandr_manager_start (GsdXrandrManager *manager,
2036
                          GError          **error)
2037
{
2038
        g_debug ("Starting xrandr manager");
1.1.15 by Sebastien Bacher
Import upstream version 2.25.2
2039
        gnome_settings_profile_start (NULL);
1 by Sebastien Bacher
Import upstream version 2.21.5.2
2040
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
2041
        manager->priv->rw_screen = gnome_rr_screen_new (
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
2042
                gdk_screen_get_default (), on_randr_event, manager, error);
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
2043
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
2044
        if (manager->priv->rw_screen == NULL)
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
2045
                return FALSE;
2046
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
2047
        manager->priv->running = TRUE;
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
2048
        manager->priv->client = gconf_client_get_default ();
2049
2050
        g_assert (manager->priv->notify_id == 0);
2051
2052
        gconf_client_add_dir (manager->priv->client, CONF_DIR,
1.1.15 by Sebastien Bacher
Import upstream version 2.25.2
2053
                              GCONF_CLIENT_PRELOAD_ONELEVEL,
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
2054
                              NULL);
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
2055
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
2056
        manager->priv->notify_id =
2057
                gconf_client_notify_add (
2058
                        manager->priv->client, CONF_DIR,
2059
                        (GConfClientNotifyFunc)on_config_changed,
2060
                        manager, NULL, NULL);
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
2061
1.1.30 by Chris Coulson
Import upstream version 2.29.5
2062
        if (manager->priv->switch_video_mode_keycode) {
2063
                gdk_error_trap_push ();
2064
2065
                XGrabKey (gdk_x11_get_default_xdisplay(),
2066
                          manager->priv->switch_video_mode_keycode, AnyModifier,
2067
                          gdk_x11_get_default_root_xwindow(),
2068
                          True, GrabModeAsync, GrabModeAsync);
2069
2070
                gdk_flush ();
2071
                gdk_error_trap_pop ();
2072
        }
2073
2074
        if (manager->priv->rotate_windows_keycode) {
2075
                gdk_error_trap_push ();
2076
2077
                XGrabKey (gdk_x11_get_default_xdisplay(),
2078
                          manager->priv->rotate_windows_keycode, AnyModifier,
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
2079
                          gdk_x11_get_default_root_xwindow(),
2080
                          True, GrabModeAsync, GrabModeAsync);
2081
2082
                gdk_flush ();
2083
                gdk_error_trap_pop ();
2084
        }
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
2085
1.1.22 by Sebastien Bacher
Import upstream version 2.27.3
2086
        show_timestamps_dialog (manager, "Startup");
2087
        apply_stored_configuration_at_startup (manager, GDK_CURRENT_TIME); /* we don't have a real timestamp at startup anyway */
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
2088
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
2089
        gdk_window_add_filter (gdk_get_default_root_window(),
2090
                               (GdkFilterFunc)event_filter,
2091
                               manager);
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
2092
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
2093
        start_or_stop_icon (manager);
0.1.1 by Sebastian Dröge
Import upstream version 2.22.2.1
2094
1.1.15 by Sebastien Bacher
Import upstream version 2.25.2
2095
        gnome_settings_profile_end (NULL);
2096
1 by Sebastien Bacher
Import upstream version 2.21.5.2
2097
        return TRUE;
2098
}
2099
2100
void
2101
gsd_xrandr_manager_stop (GsdXrandrManager *manager)
2102
{
2103
        g_debug ("Stopping xrandr manager");
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
2104
2105
        manager->priv->running = FALSE;
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
2106
1.1.30 by Chris Coulson
Import upstream version 2.29.5
2107
        if (manager->priv->switch_video_mode_keycode) {
2108
                gdk_error_trap_push ();
2109
2110
                XUngrabKey (gdk_x11_get_default_xdisplay(),
2111
                            manager->priv->switch_video_mode_keycode, AnyModifier,
2112
                            gdk_x11_get_default_root_xwindow());
2113
2114
                gdk_error_trap_pop ();
2115
        }
2116
2117
        if (manager->priv->rotate_windows_keycode) {
2118
                gdk_error_trap_push ();
2119
2120
                XUngrabKey (gdk_x11_get_default_xdisplay(),
2121
                            manager->priv->rotate_windows_keycode, AnyModifier,
2122
                            gdk_x11_get_default_root_xwindow());
2123
2124
                gdk_error_trap_pop ();
2125
        }
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
2126
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
2127
        gdk_window_remove_filter (gdk_get_default_root_window (),
2128
                                  (GdkFilterFunc) event_filter,
2129
                                  manager);
2130
1.1.10 by Sebastien Bacher
Import upstream version 2.23.6
2131
        if (manager->priv->notify_id != 0) {
2132
                gconf_client_remove_dir (manager->priv->client,
2133
                                         CONF_DIR, NULL);
2134
                gconf_client_notify_remove (manager->priv->client,
2135
                                            manager->priv->notify_id);
2136
                manager->priv->notify_id = 0;
2137
        }
2138
2139
        if (manager->priv->client != NULL) {
2140
                g_object_unref (manager->priv->client);
2141
                manager->priv->client = NULL;
2142
        }
2143
1.1.11 by Sebastien Bacher
Import upstream version 2.23.90
2144
        if (manager->priv->rw_screen != NULL) {
2145
                gnome_rr_screen_destroy (manager->priv->rw_screen);
2146
                manager->priv->rw_screen = NULL;
2147
        }
2148
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
2149
        if (manager->priv->dbus_connection != NULL) {
2150
                dbus_g_connection_unref (manager->priv->dbus_connection);
2151
                manager->priv->dbus_connection = NULL;
2152
        }
2153
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
2154
        status_icon_stop (manager);
1 by Sebastien Bacher
Import upstream version 2.21.5.2
2155
}
2156
2157
static void
2158
gsd_xrandr_manager_set_property (GObject        *object,
2159
                               guint           prop_id,
2160
                               const GValue   *value,
2161
                               GParamSpec     *pspec)
2162
{
2163
        GsdXrandrManager *self;
2164
2165
        self = GSD_XRANDR_MANAGER (object);
2166
2167
        switch (prop_id) {
2168
        default:
2169
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2170
                break;
2171
        }
2172
}
2173
2174
static void
2175
gsd_xrandr_manager_get_property (GObject        *object,
2176
                               guint           prop_id,
2177
                               GValue         *value,
2178
                               GParamSpec     *pspec)
2179
{
2180
        GsdXrandrManager *self;
2181
2182
        self = GSD_XRANDR_MANAGER (object);
2183
2184
        switch (prop_id) {
2185
        default:
2186
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2187
                break;
2188
        }
2189
}
2190
2191
static GObject *
2192
gsd_xrandr_manager_constructor (GType                  type,
2193
                              guint                  n_construct_properties,
2194
                              GObjectConstructParam *construct_properties)
2195
{
2196
        GsdXrandrManager      *xrandr_manager;
2197
        GsdXrandrManagerClass *klass;
2198
2199
        klass = GSD_XRANDR_MANAGER_CLASS (g_type_class_peek (GSD_TYPE_XRANDR_MANAGER));
2200
2201
        xrandr_manager = GSD_XRANDR_MANAGER (G_OBJECT_CLASS (gsd_xrandr_manager_parent_class)->constructor (type,
2202
                                                                                                      n_construct_properties,
2203
                                                                                                      construct_properties));
2204
2205
        return G_OBJECT (xrandr_manager);
2206
}
2207
2208
static void
2209
gsd_xrandr_manager_dispose (GObject *object)
2210
{
2211
        GsdXrandrManager *xrandr_manager;
2212
2213
        xrandr_manager = GSD_XRANDR_MANAGER (object);
2214
2215
        G_OBJECT_CLASS (gsd_xrandr_manager_parent_class)->dispose (object);
2216
}
2217
2218
static void
2219
gsd_xrandr_manager_class_init (GsdXrandrManagerClass *klass)
2220
{
1.1.7 by Sebastien Bacher
Import upstream version 2.23.1.1
2221
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
1 by Sebastien Bacher
Import upstream version 2.21.5.2
2222
2223
        object_class->get_property = gsd_xrandr_manager_get_property;
2224
        object_class->set_property = gsd_xrandr_manager_set_property;
2225
        object_class->constructor = gsd_xrandr_manager_constructor;
2226
        object_class->dispose = gsd_xrandr_manager_dispose;
2227
        object_class->finalize = gsd_xrandr_manager_finalize;
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
2228
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
2229
        dbus_g_object_type_install_info (GSD_TYPE_XRANDR_MANAGER, &dbus_glib_gsd_xrandr_manager_object_info);
2230
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
2231
        g_type_class_add_private (klass, sizeof (GsdXrandrManagerPrivate));
1 by Sebastien Bacher
Import upstream version 2.21.5.2
2232
}
2233
1.1.30 by Chris Coulson
Import upstream version 2.29.5
2234
static guint
2235
get_keycode_for_keysym_name (const char *name)
2236
{
2237
        Display *dpy;
2238
        guint keyval;
2239
2240
        dpy = gdk_x11_get_default_xdisplay ();
2241
2242
        keyval = gdk_keyval_from_name (name);
2243
        return XKeysymToKeycode (dpy, keyval);
2244
}
2245
1 by Sebastien Bacher
Import upstream version 2.21.5.2
2246
static void
2247
gsd_xrandr_manager_init (GsdXrandrManager *manager)
2248
{
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
2249
        manager->priv = GSD_XRANDR_MANAGER_GET_PRIVATE (manager);
2250
1.1.30 by Chris Coulson
Import upstream version 2.29.5
2251
        manager->priv->switch_video_mode_keycode = get_keycode_for_keysym_name (VIDEO_KEYSYM);
2252
        manager->priv->rotate_windows_keycode = get_keycode_for_keysym_name (ROTATE_KEYSYM);
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
2253
2254
        manager->priv->current_fn_f7_config = -1;
2255
        manager->priv->fn_f7_configs = NULL;
1 by Sebastien Bacher
Import upstream version 2.21.5.2
2256
}
2257
2258
static void
2259
gsd_xrandr_manager_finalize (GObject *object)
2260
{
2261
        GsdXrandrManager *xrandr_manager;
2262
2263
        g_return_if_fail (object != NULL);
2264
        g_return_if_fail (GSD_IS_XRANDR_MANAGER (object));
2265
2266
        xrandr_manager = GSD_XRANDR_MANAGER (object);
2267
1.1.9 by Sebastien Bacher
Import upstream version 2.23.5
2268
        g_return_if_fail (xrandr_manager->priv != NULL);
2269
1 by Sebastien Bacher
Import upstream version 2.21.5.2
2270
        G_OBJECT_CLASS (gsd_xrandr_manager_parent_class)->finalize (object);
2271
}
2272
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
2273
static gboolean
2274
register_manager_dbus (GsdXrandrManager *manager)
2275
{
2276
        GError *error = NULL;
2277
2278
        manager->priv->dbus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
2279
        if (manager->priv->dbus_connection == NULL) {
2280
                if (error != NULL) {
2281
                        g_warning ("Error getting session bus: %s", error->message);
2282
                        g_error_free (error);
2283
                }
2284
                return FALSE;
2285
        }
2286
2287
        /* Hmm, should we do this in gsd_xrandr_manager_start()? */
2288
        dbus_g_connection_register_g_object (manager->priv->dbus_connection, GSD_XRANDR_DBUS_PATH, G_OBJECT (manager));
2289
2290
        return TRUE;
2291
}
2292
1 by Sebastien Bacher
Import upstream version 2.21.5.2
2293
GsdXrandrManager *
2294
gsd_xrandr_manager_new (void)
2295
{
2296
        if (manager_object != NULL) {
2297
                g_object_ref (manager_object);
2298
        } else {
2299
                manager_object = g_object_new (GSD_TYPE_XRANDR_MANAGER, NULL);
2300
                g_object_add_weak_pointer (manager_object,
2301
                                           (gpointer *) &manager_object);
1.1.16 by Sebastien Bacher
Import upstream version 2.25.3
2302
2303
                if (!register_manager_dbus (manager_object)) {
2304
                        g_object_unref (manager_object);
2305
                        return NULL;
2306
                }
1 by Sebastien Bacher
Import upstream version 2.21.5.2
2307
        }
2308
2309
        return GSD_XRANDR_MANAGER (manager_object);
2310
}