1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2001-2003 Bastien Nocera <hadess@hadess.net>
4 * Copyright (C) 2006-2007 William Jon McCann <mccann@jhu.edu>
5 * Copyright (C) 2014 Michal Ratajsky <michal.ratajsky@gmail.com>
6 * Copyright (C) 2012-2021 MATE Developers
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
21 *
22 */
23
24 #include "config.h"
25
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gdk/gdk.h>
29 #include <gdk/gdkx.h>
30 #include <gtk/gtk.h>
31 #include <gio/gio.h>
32
33 #include <dbus/dbus-glib.h>
34 #include <dbus/dbus-glib-lowlevel.h>
35
36 #ifdef HAVE_LIBMATEMIXER
37 #include <libmatemixer/matemixer.h>
38 #endif
39
40 #ifdef HAVE_LIBCANBERRA
41 #include <canberra-gtk.h>
42 #endif
43
44 #include "mate-settings-profile.h"
45 #include "msd-marshal.h"
46 #include "msd-media-keys-manager.h"
47 #include "msd-media-keys-manager-glue.h"
48
49 #include "eggaccelerators.h"
50 #include "acme.h"
51 #include "msd-media-keys-window.h"
52 #include "msd-input-helper.h"
53
54 #define MSD_DBUS_PATH "/org/mate/SettingsDaemon"
55 #define MSD_DBUS_NAME "org.mate.SettingsDaemon"
56 #define MSD_MEDIA_KEYS_DBUS_PATH MSD_DBUS_PATH "/MediaKeys"
57 #define MSD_MEDIA_KEYS_DBUS_NAME MSD_DBUS_NAME ".MediaKeys"
58
59 #define TOUCHPAD_SCHEMA "org.mate.peripherals-touchpad"
60 #define TOUCHPAD_ENABLED_KEY "touchpad-enabled"
61
62 typedef struct {
63 char *application;
64 guint32 time;
65 } MediaPlayer;
66
67 struct _MsdMediaKeysManagerPrivate
68 {
69 #ifdef HAVE_LIBMATEMIXER
70 /* Volume bits */
71 MateMixerContext *context;
72 MateMixerStream *stream;
73 MateMixerStream *source_stream;
74 MateMixerStreamControl *control;
75 MateMixerStreamControl *source_control;
76 #endif
77 GtkWidget *dialog;
78 GSettings *settings;
79 GVolumeMonitor *volume_monitor;
80
81 /* Multihead stuff */
82 GdkScreen *current_screen;
83 GSList *screens;
84
85 /* RFKill stuff */
86 guint rfkill_watch_id;
87 GDBusProxy *rfkill_proxy;
88 GCancellable *rfkill_cancellable;
89
90 GList *media_players;
91
92 DBusGConnection *connection;
93 guint notify[HANDLED_KEYS];
94 };
95
96 enum {
97 MEDIA_PLAYER_KEY_PRESSED,
98 LAST_SIGNAL
99 };
100
101 static guint signals[LAST_SIGNAL] = { 0 };
102
103 G_DEFINE_TYPE_WITH_PRIVATE (MsdMediaKeysManager, msd_media_keys_manager, G_TYPE_OBJECT)
104
105 static gpointer manager_object = NULL;
106
107 static void
init_screens(MsdMediaKeysManager * manager)108 init_screens (MsdMediaKeysManager *manager)
109 {
110 GdkDisplay *display;
111
112 display = gdk_display_get_default ();
113
114 GdkScreen *screen;
115
116 screen = gdk_display_get_default_screen (display);
117
118 if (screen != NULL) {
119 manager->priv->screens = g_slist_append (manager->priv->screens, screen);
120 }
121
122 manager->priv->current_screen = manager->priv->screens->data;
123 }
124
125 static void
acme_error(char * msg)126 acme_error (char * msg)
127 {
128 GtkWidget *error_dialog;
129
130 error_dialog = gtk_message_dialog_new (NULL,
131 GTK_DIALOG_MODAL,
132 GTK_MESSAGE_ERROR,
133 GTK_BUTTONS_OK,
134 msg, NULL);
135 gtk_dialog_set_default_response (GTK_DIALOG (error_dialog),
136 GTK_RESPONSE_OK);
137 gtk_widget_show (error_dialog);
138 g_signal_connect (error_dialog,
139 "response",
140 G_CALLBACK (gtk_widget_destroy),
141 NULL);
142 }
143
144 static char *
get_term_command(MsdMediaKeysManager * manager)145 get_term_command (MsdMediaKeysManager *manager)
146 {
147 char *cmd_term, *cmd_args;
148 char *cmd = NULL;
149 GSettings *settings;
150
151 settings = g_settings_new ("org.mate.applications-terminal");
152 cmd_term = g_settings_get_string (settings, "exec");
153 cmd_args = g_settings_get_string (settings, "exec-arg");
154
155 if (cmd_term[0] != '\0') {
156 cmd = g_strdup_printf ("%s %s -e", cmd_term, cmd_args);
157 } else {
158 cmd = g_strdup_printf ("mate-terminal -e");
159 }
160
161 g_free (cmd_args);
162 g_free (cmd_term);
163 g_object_unref (settings);
164
165 return cmd;
166 }
167
168 static void
execute(MsdMediaKeysManager * manager,char * cmd,gboolean sync,gboolean need_term)169 execute (MsdMediaKeysManager *manager,
170 char *cmd,
171 gboolean sync,
172 gboolean need_term)
173 {
174 gboolean retval;
175 char **argv;
176 int argc;
177 char *exec;
178 char *term = NULL;
179
180 retval = FALSE;
181
182 if (need_term) {
183 term = get_term_command (manager);
184 if (term == NULL) {
185 acme_error (_("Could not get default terminal. Verify that your default "
186 "terminal command is set and points to a valid application."));
187 return;
188 }
189 }
190
191 if (term) {
192 exec = g_strdup_printf ("%s %s", term, cmd);
193 g_free (term);
194 } else {
195 exec = g_strdup (cmd);
196 }
197
198 if (g_shell_parse_argv (exec, &argc, &argv, NULL)) {
199 if (sync != FALSE) {
200 retval = g_spawn_sync (g_get_home_dir (),
201 argv,
202 NULL,
203 G_SPAWN_SEARCH_PATH,
204 NULL,
205 NULL,
206 NULL,
207 NULL,
208 NULL,
209 NULL);
210 } else {
211 retval = g_spawn_async (g_get_home_dir (),
212 argv,
213 NULL,
214 G_SPAWN_SEARCH_PATH,
215 NULL,
216 NULL,
217 NULL,
218 NULL);
219 }
220 g_strfreev (argv);
221 }
222
223 if (retval == FALSE) {
224 char *msg;
225 msg = g_strdup_printf (_("Couldn't execute command: %s\n"
226 "Verify that this is a valid command."),
227 exec);
228
229 acme_error (msg);
230 g_free (msg);
231 }
232 g_free (exec);
233 }
234
235 static void
dialog_init(MsdMediaKeysManager * manager)236 dialog_init (MsdMediaKeysManager *manager)
237 {
238 if (manager->priv->dialog != NULL
239 && !msd_osd_window_is_valid (MSD_OSD_WINDOW (manager->priv->dialog))) {
240 gtk_widget_destroy (manager->priv->dialog);
241 manager->priv->dialog = NULL;
242 }
243
244 if (manager->priv->dialog == NULL) {
245 manager->priv->dialog = msd_media_keys_window_new ();
246 }
247 }
248
249 static gboolean
is_valid_shortcut(const char * string)250 is_valid_shortcut (const char *string)
251 {
252 if (string == NULL || string[0] == '\0') {
253 return FALSE;
254 }
255 if (strcmp (string, "disabled") == 0) {
256 return FALSE;
257 }
258
259 return TRUE;
260 }
261
262 static void
update_kbd_cb(GSettings * settings,gchar * settings_key,MsdMediaKeysManager * manager)263 update_kbd_cb (GSettings *settings,
264 gchar *settings_key,
265 MsdMediaKeysManager *manager)
266 {
267 int i;
268 GdkDisplay *dpy;
269 gboolean need_flush = TRUE;
270
271 g_return_if_fail (settings_key != NULL);
272
273 dpy = gdk_display_get_default ();
274 gdk_x11_display_error_trap_push (dpy);
275
276 /* Find the key that was modified */
277 for (i = 0; i < HANDLED_KEYS; i++) {
278 if (g_strcmp0 (settings_key, keys[i].settings_key) == 0) {
279 char *tmp;
280 Key *key;
281
282 if (keys[i].key != NULL) {
283 need_flush = TRUE;
284 grab_key_unsafe (keys[i].key, FALSE, manager->priv->screens);
285 }
286
287 g_free (keys[i].key);
288 keys[i].key = NULL;
289
290 /* We can't have a change in a hard-coded key */
291 g_assert (keys[i].settings_key != NULL);
292
293 tmp = g_settings_get_string (settings,
294 keys[i].settings_key);
295
296 if (is_valid_shortcut (tmp) == FALSE) {
297 g_free (tmp);
298 break;
299 }
300
301 key = g_new0 (Key, 1);
302 if (!egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycodes, &key->state)) {
303 g_free (tmp);
304 g_free (key);
305 break;
306 }
307
308 need_flush = TRUE;
309 grab_key_unsafe (key, TRUE, manager->priv->screens);
310 keys[i].key = key;
311
312 g_free (tmp);
313
314 break;
315 }
316 }
317
318 if (need_flush)
319 gdk_display_flush (dpy);
320 if (gdk_x11_display_error_trap_pop (dpy))
321 g_warning ("Grab failed for some keys, another application may already have access the them.");
322 }
323
init_kbd(MsdMediaKeysManager * manager)324 static void init_kbd(MsdMediaKeysManager* manager)
325 {
326 int i;
327 GdkDisplay *dpy;
328 gboolean need_flush = FALSE;
329
330 mate_settings_profile_start(NULL);
331
332 dpy = gdk_display_get_default ();
333 gdk_x11_display_error_trap_push (dpy);
334
335 for (i = 0; i < HANDLED_KEYS; i++)
336 {
337 char* tmp;
338 Key* key;
339
340 gchar* signal_name;
341 signal_name = g_strdup_printf ("changed::%s", keys[i].settings_key);
342 g_signal_connect (manager->priv->settings,
343 signal_name,
344 G_CALLBACK (update_kbd_cb),
345 manager);
346 g_free (signal_name);
347
348 if (keys[i].settings_key != NULL) {
349 tmp = g_settings_get_string (manager->priv->settings, keys[i].settings_key);
350 } else {
351 tmp = g_strdup (keys[i].hard_coded);
352 }
353
354 if (!is_valid_shortcut(tmp))
355 {
356 g_debug("Not a valid shortcut: '%s'", tmp);
357 g_free(tmp);
358 continue;
359 }
360
361 key = g_new0(Key, 1);
362
363 if (!egg_accelerator_parse_virtual(tmp, &key->keysym, &key->keycodes, &key->state))
364 {
365 g_debug("Unable to parse: '%s'", tmp);
366 g_free(tmp);
367 g_free(key);
368 continue;
369 }
370
371 g_free(tmp);
372
373 keys[i].key = key;
374
375 need_flush = TRUE;
376 grab_key_unsafe(key, TRUE, manager->priv->screens);
377 }
378
379 if (need_flush)
380 {
381 gdk_display_flush (dpy);
382 }
383
384 if (gdk_x11_display_error_trap_pop (dpy))
385 {
386 g_warning("Grab failed for some keys, another application may already have access the them.");
387 }
388
389 mate_settings_profile_end(NULL);
390 }
391
392 static void
ensure_cancellable(GCancellable ** cancellable)393 ensure_cancellable (GCancellable **cancellable)
394 {
395 if (*cancellable == NULL) {
396 *cancellable = g_cancellable_new ();
397 g_object_add_weak_pointer (G_OBJECT (*cancellable),
398 (gpointer *)cancellable);
399 } else {
400 g_object_ref (*cancellable);
401 }
402 }
403
404 static void
dialog_show(MsdMediaKeysManager * manager)405 dialog_show (MsdMediaKeysManager *manager)
406 {
407 int orig_w;
408 int orig_h;
409 int screen_w;
410 int screen_h;
411 int x;
412 int y;
413 GdkDisplay *display;
414 GdkSeat *seat;
415 GdkDevice *pointer;
416 int pointer_x;
417 int pointer_y;
418 GtkRequisition win_req;
419 GdkScreen *pointer_screen;
420 GdkRectangle geometry;
421 GdkMonitor *monitor;
422
423 gtk_window_set_screen (GTK_WINDOW (manager->priv->dialog),
424 manager->priv->current_screen);
425
426 /* Return if OSD notifications are disabled */
427 if (!g_settings_get_boolean (manager->priv->settings, "enable-osd"))
428 return;
429
430 /*
431 * get the window size
432 * if the window hasn't been mapped, it doesn't necessarily
433 * know its true size, yet, so we need to jump through hoops
434 */
435 gtk_window_get_default_size (GTK_WINDOW (manager->priv->dialog), &orig_w, &orig_h);
436 gtk_widget_get_preferred_size (manager->priv->dialog, NULL, &win_req);
437
438 if (win_req.width > orig_w) {
439 orig_w = win_req.width;
440 }
441 if (win_req.height > orig_h) {
442 orig_h = win_req.height;
443 }
444
445 pointer_screen = NULL;
446 display = gdk_screen_get_display (manager->priv->current_screen);
447 seat = gdk_display_get_default_seat (display);
448 pointer = gdk_seat_get_pointer (seat);
449
450 gdk_device_get_position (pointer,
451 &pointer_screen,
452 &pointer_x,
453 &pointer_y);
454
455 if (pointer_screen != manager->priv->current_screen) {
456 /* The pointer isn't on the current screen, so just
457 * assume the default monitor
458 */
459 monitor = gdk_display_get_monitor (display, 0);
460 } else {
461 monitor = gdk_display_get_monitor_at_point (display, pointer_x, pointer_y);
462 }
463
464 gdk_monitor_get_geometry (monitor, &geometry);
465
466 screen_w = geometry.width;
467 screen_h = geometry.height;
468
469 x = ((screen_w - orig_w) / 2) + geometry.x;
470 y = geometry.y + (screen_h / 2) + (screen_h / 2 - orig_h) / 2;
471
472 gtk_window_move (GTK_WINDOW (manager->priv->dialog), x, y);
473
474 gtk_widget_show (manager->priv->dialog);
475
476 gdk_display_sync (gdk_screen_get_display (manager->priv->current_screen));
477 }
478
479 static void
do_url_action(MsdMediaKeysManager * manager,const gchar * scheme)480 do_url_action (MsdMediaKeysManager *manager,
481 const gchar *scheme)
482 {
483 GError *error = NULL;
484 GAppInfo *app_info;
485
486 app_info = g_app_info_get_default_for_uri_scheme (scheme);
487
488 if (app_info != NULL) {
489 if (!g_app_info_launch (app_info, NULL, NULL, &error)) {
490 g_warning ("Could not launch '%s': %s",
491 g_app_info_get_commandline (app_info),
492 error->message);
493 g_object_unref (app_info);
494 g_error_free (error);
495 }
496 }
497 else {
498 g_warning ("Could not find default application for '%s' scheme", scheme);
499 }
500 }
501
502 static void
do_media_action(MsdMediaKeysManager * manager)503 do_media_action (MsdMediaKeysManager *manager)
504 {
505 GError *error = NULL;
506 GAppInfo *app_info;
507
508 app_info = g_app_info_get_default_for_type ("audio/x-vorbis+ogg", FALSE);
509
510 if (app_info != NULL) {
511 if (!g_app_info_launch (app_info, NULL, NULL, &error)) {
512 g_warning ("Could not launch '%s': %s",
513 g_app_info_get_commandline (app_info),
514 error->message);
515 g_error_free (error);
516 }
517 }
518 else {
519 g_warning ("Could not find default application for '%s' mime-type", "audio/x-vorbis+ogg");
520 }
521 }
522
523 static void
do_calculator_action(MsdMediaKeysManager * manager)524 do_calculator_action (MsdMediaKeysManager *manager)
525 {
526 GSettings *settings;
527 char *calc;
528
529 settings = g_settings_new ("org.mate.applications-calculator");
530 calc = g_settings_get_string (settings, "exec");
531
532 if (calc)
533 execute (manager, calc, FALSE, FALSE);
534
535 g_free (calc);
536 g_object_unref (settings);
537 }
538
539 static void
do_messenger_action(MsdMediaKeysManager * manager)540 do_messenger_action (MsdMediaKeysManager *manager)
541 {
542 GSettings *settings;
543 char *messenger;
544
545 settings = g_settings_new ("org.mate.applications-messenger");
546 messenger = g_settings_get_string (settings, "exec");
547
548 if (messenger)
549 execute (manager, messenger, FALSE, FALSE);
550
551 g_free (messenger);
552 g_object_unref (settings);
553 }
554
555 static void
do_shutdown_action(MsdMediaKeysManager * manager)556 do_shutdown_action (MsdMediaKeysManager *manager)
557 {
558 execute (manager, "mate-session-save --shutdown-dialog", FALSE, FALSE);
559 }
560
561 static void
do_logout_action(MsdMediaKeysManager * manager)562 do_logout_action (MsdMediaKeysManager *manager)
563 {
564 execute (manager, "mate-session-save --logout-dialog", FALSE, FALSE);
565 }
566
567 static void
do_eject_action_cb(GDrive * drive,GAsyncResult * res,MsdMediaKeysManager * manager)568 do_eject_action_cb (GDrive *drive,
569 GAsyncResult *res,
570 MsdMediaKeysManager *manager)
571 {
572 g_drive_eject_with_operation_finish (drive, res, NULL);
573 }
574
575 #define NO_SCORE 0
576 #define SCORE_CAN_EJECT 50
577 #define SCORE_HAS_MEDIA 100
578 static void
do_eject_action(MsdMediaKeysManager * manager)579 do_eject_action (MsdMediaKeysManager *manager)
580 {
581 GList *drives, *l;
582 GDrive *fav_drive;
583 guint score;
584
585 /* Find the best drive to eject */
586 fav_drive = NULL;
587 score = NO_SCORE;
588 drives = g_volume_monitor_get_connected_drives (manager->priv->volume_monitor);
589 for (l = drives; l != NULL; l = l->next) {
590 GDrive *drive = l->data;
591
592 if (g_drive_can_eject (drive) == FALSE)
593 continue;
594 if (g_drive_is_media_removable (drive) == FALSE)
595 continue;
596 if (score < SCORE_CAN_EJECT) {
597 fav_drive = drive;
598 score = SCORE_CAN_EJECT;
599 }
600 if (g_drive_has_media (drive) == FALSE)
601 continue;
602 if (score < SCORE_HAS_MEDIA) {
603 fav_drive = drive;
604 break;
605 }
606 }
607
608 /* Show the dialogue */
609 dialog_init (manager);
610 msd_media_keys_window_set_action_custom (MSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
611 "media-eject",
612 NULL);
613 dialog_show (manager);
614
615 /* Clean up the drive selection and exit if no suitable
616 * drives are found */
617 if (fav_drive != NULL)
618 fav_drive = g_object_ref (fav_drive);
619
620 g_list_free_full (drives, g_object_unref);
621 if (fav_drive == NULL)
622 return;
623
624 /* Eject! */
625 g_drive_eject_with_operation (fav_drive, G_MOUNT_UNMOUNT_FORCE,
626 NULL, NULL,
627 (GAsyncReadyCallback) do_eject_action_cb,
628 manager);
629 g_object_unref (fav_drive);
630 }
631
632 static void
do_touchpad_osd_action(MsdMediaKeysManager * manager,gboolean state)633 do_touchpad_osd_action (MsdMediaKeysManager *manager, gboolean state)
634 {
635 dialog_init (manager);
636 msd_media_keys_window_set_action_custom (MSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
637 state ? "input-touchpad" : "touchpad-disabled",
638 state ? _("Touchpad enabled") : _("Touchpad disabled"));
639 dialog_show (manager);
640 }
641
642 static void
do_touchpad_action(MsdMediaKeysManager * manager)643 do_touchpad_action (MsdMediaKeysManager *manager)
644 {
645 GSettings *settings = g_settings_new (TOUCHPAD_SCHEMA);
646 gboolean state = g_settings_get_boolean (settings, TOUCHPAD_ENABLED_KEY);
647
648 if (touchpad_is_present () == FALSE) {
649 do_touchpad_osd_action (manager, FALSE);
650 return;
651 }
652
653 do_touchpad_osd_action (manager, !state);
654
655 g_settings_set_boolean (settings, TOUCHPAD_ENABLED_KEY, !state);
656 g_object_unref (settings);
657 }
658
659 #ifdef HAVE_LIBMATEMIXER
660 static void
update_dialog(MsdMediaKeysManager * manager,guint volume,gboolean muted,gboolean sound_changed,gboolean quiet,gboolean is_mic)661 update_dialog (MsdMediaKeysManager *manager,
662 guint volume,
663 gboolean muted,
664 gboolean sound_changed,
665 gboolean quiet,
666 gboolean is_mic)
667 {
668 if (muted)
669 volume = 0;
670
671 dialog_init (manager);
672
673 if (is_mic)
674 msd_media_keys_window_set_mic_muted (MSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
675 muted);
676 else
677 msd_media_keys_window_set_volume_muted (MSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
678 muted);
679
680 msd_media_keys_window_set_volume_level (MSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
681 volume);
682
683 msd_media_keys_window_set_action (MSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
684 MSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
685 dialog_show (manager);
686
687 #ifdef HAVE_LIBCANBERRA
688 if (quiet == FALSE && sound_changed != FALSE && muted == FALSE && is_mic == FALSE)
689 ca_gtk_play_for_widget (manager->priv->dialog, 0,
690 CA_PROP_EVENT_ID, "audio-volume-change",
691 CA_PROP_EVENT_DESCRIPTION, "Volume changed through key press",
692 CA_PROP_APPLICATION_NAME, PACKAGE_NAME,
693 CA_PROP_APPLICATION_VERSION, PACKAGE_VERSION,
694 CA_PROP_APPLICATION_ID, "org.mate.SettingsDaemon",
695 NULL);
696 #endif
697 }
698
699 static void
do_sound_action(MsdMediaKeysManager * manager,int type,gboolean quiet)700 do_sound_action (MsdMediaKeysManager *manager,
701 int type,
702 gboolean quiet)
703 {
704 gboolean muted;
705 gboolean muted_last;
706 gboolean sound_changed = FALSE;
707 guint volume;
708 guint volume_min, volume_max;
709 gint volume_step;
710 guint volume_step_scaled;
711 guint volume_last;
712 MateMixerStreamControl *control;
713
714 gboolean is_input_control =
715 type == MIC_MUTE_KEY ? TRUE : FALSE;
716 if (is_input_control)
717 control = manager->priv->source_control;
718 else
719 control = manager->priv->control;
720 if (control == NULL)
721 return;
722
723 /* Theoretically the volume limits might be different for different
724 * streams, also the minimum might not always start at 0 */
725 volume_min = mate_mixer_stream_control_get_min_volume (control);
726 volume_max = mate_mixer_stream_control_get_normal_volume (control);
727
728 volume_step = g_settings_get_int (manager->priv->settings, "volume-step");
729 if (volume_step <= 0 || volume_step > 100) {
730 GVariant *variant = g_settings_get_default_value (manager->priv->settings, "volume-step");
731 gint32 volume_step_default = g_variant_get_int32 (variant);
732 volume_step = (gint) volume_step_default;
733 g_variant_unref (variant);
734 }
735
736 /* Scale the volume step size accordingly to the range used by the control */
737 volume_step_scaled = (volume_max - volume_min) * (guint) volume_step / 100;
738
739 volume = volume_last =
740 mate_mixer_stream_control_get_volume (control);
741 muted = muted_last =
742 mate_mixer_stream_control_get_mute (control);
743
744 switch (type) {
745 case MUTE_KEY:
746 case MIC_MUTE_KEY:
747 muted = !muted;
748 break;
749 case VOLUME_DOWN_KEY:
750 if (volume <= (volume_min + volume_step_scaled)) {
751 volume = volume_min;
752 muted = TRUE;
753 } else {
754 volume -= volume_step_scaled;
755 muted = FALSE;
756 }
757 break;
758 case VOLUME_UP_KEY:
759 if (muted) {
760 muted = FALSE;
761 if (volume <= volume_min)
762 volume = volume_min + volume_step_scaled;
763 } else
764 volume = CLAMP (volume + volume_step_scaled,
765 volume_min,
766 volume_max);
767 break;
768 }
769
770 if (muted != muted_last) {
771 if (mate_mixer_stream_control_set_mute (control, muted))
772 sound_changed = TRUE;
773 else
774 muted = muted_last;
775 }
776
777 if (volume != mate_mixer_stream_control_get_volume (control)) {
778 if (mate_mixer_stream_control_set_volume (control, volume))
779 sound_changed = TRUE;
780 else
781 volume = volume_last;
782 }
783
784 update_dialog (manager,
785 MIN (100 * volume / (volume_max - volume_min), 100),
786 muted,
787 sound_changed,
788 quiet,
789 is_input_control);
790 }
791
792 static void
update_default_output(MsdMediaKeysManager * manager)793 update_default_output (MsdMediaKeysManager *manager)
794 {
795 MateMixerStream *stream;
796 MateMixerStreamControl *control = NULL;
797
798 stream = mate_mixer_context_get_default_output_stream (manager->priv->context);
799 if (stream != NULL)
800 control = mate_mixer_stream_get_default_control (stream);
801
802 if (stream == manager->priv->stream)
803 return;
804
805 g_clear_object (&manager->priv->stream);
806 g_clear_object (&manager->priv->control);
807
808 if (control != NULL) {
809 MateMixerStreamControlFlags flags = mate_mixer_stream_control_get_flags (control);
810
811 /* Do not use the stream if it is not possible to mute it or
812 * change the volume */
813 if (!(flags & MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE) &&
814 !(flags & MATE_MIXER_STREAM_CONTROL_VOLUME_WRITABLE))
815 return;
816
817 manager->priv->stream = g_object_ref (stream);
818 manager->priv->control = g_object_ref (control);
819 g_debug ("Default output stream updated to %s",
820 mate_mixer_stream_get_name (stream));
821 } else
822 g_debug ("Default output stream unset");
823 }
824
825 static void
update_default_input(MsdMediaKeysManager * manager)826 update_default_input (MsdMediaKeysManager *manager)
827 {
828 MateMixerStream *stream;
829 MateMixerStreamControl *control = NULL;
830
831 stream = mate_mixer_context_get_default_input_stream (manager->priv->context);
832 if (stream != NULL)
833 control = mate_mixer_stream_get_default_control (stream);
834
835 if (stream == manager->priv->source_stream)
836 return;
837
838 g_clear_object (&manager->priv->source_stream);
839 g_clear_object (&manager->priv->source_control);
840
841 if (control != NULL) {
842 MateMixerStreamControlFlags flags = mate_mixer_stream_control_get_flags (control);
843
844 /* Do not use the stream if it is not possible to mute it or
845 * change the volume */
846 if (!(flags & MATE_MIXER_STREAM_CONTROL_MUTE_WRITABLE))
847 return;
848
849 manager->priv->source_stream = g_object_ref (stream);
850 manager->priv->source_control = g_object_ref (control);
851 g_debug ("Default input stream updated to %s",
852 mate_mixer_stream_get_name (stream));
853 } else
854 g_debug ("Default input stream unset");
855 }
856
857 static void
on_context_state_notify(MateMixerContext * context G_GNUC_UNUSED,GParamSpec * pspec G_GNUC_UNUSED,MsdMediaKeysManager * manager)858 on_context_state_notify (MateMixerContext *context G_GNUC_UNUSED,
859 GParamSpec *pspec G_GNUC_UNUSED,
860 MsdMediaKeysManager *manager)
861 {
862 update_default_output (manager);
863 update_default_input (manager);
864 }
865
866 static void
on_context_default_output_notify(MateMixerContext * context G_GNUC_UNUSED,GParamSpec * pspec G_GNUC_UNUSED,MsdMediaKeysManager * manager)867 on_context_default_output_notify (MateMixerContext *context G_GNUC_UNUSED,
868 GParamSpec *pspec G_GNUC_UNUSED,
869 MsdMediaKeysManager *manager)
870 {
871 update_default_output (manager);
872 }
873
874 static void
on_context_default_input_notify(MateMixerContext * context G_GNUC_UNUSED,GParamSpec * pspec G_GNUC_UNUSED,MsdMediaKeysManager * manager)875 on_context_default_input_notify (MateMixerContext *context G_GNUC_UNUSED,
876 GParamSpec *pspec G_GNUC_UNUSED,
877 MsdMediaKeysManager *manager)
878 {
879 update_default_input (manager);
880 }
881
882 static void
on_context_stream_removed(MateMixerContext * context G_GNUC_UNUSED,const gchar * name,MsdMediaKeysManager * manager)883 on_context_stream_removed (MateMixerContext *context G_GNUC_UNUSED,
884 const gchar *name,
885 MsdMediaKeysManager *manager)
886 {
887 if (manager->priv->stream != NULL) {
888 MateMixerStream *stream =
889 mate_mixer_context_get_stream (manager->priv->context, name);
890
891 if (stream == manager->priv->stream) {
892 g_clear_object (&manager->priv->stream);
893 g_clear_object (&manager->priv->control);
894 }
895 }
896 if (manager->priv->source_stream != NULL) {
897 MateMixerStream *stream =
898 mate_mixer_context_get_stream (manager->priv->context, name);
899
900 if (stream == manager->priv->source_stream) {
901 g_clear_object (&manager->priv->source_stream);
902 g_clear_object (&manager->priv->source_control);
903 }
904 }
905 }
906 #endif /* HAVE_LIBMATEMIXER */
907
908 static gboolean
get_rfkill_property(MsdMediaKeysManager * manager,const char * property)909 get_rfkill_property (MsdMediaKeysManager *manager,
910 const char *property)
911 {
912 GVariant *v;
913 gboolean ret;
914
915 v = g_dbus_proxy_get_cached_property (manager->priv->rfkill_proxy, property);
916 if (!v)
917 return FALSE;
918 ret = g_variant_get_boolean (v);
919 g_variant_unref (v);
920
921 return ret;
922 }
923
924 typedef struct {
925 MsdMediaKeysManager *manager;
926 char *property;
927 gboolean bluetooth;
928 gboolean target_state;
929 } RfkillData;
930
931 static void
set_rfkill_complete(GObject * object,GAsyncResult * result,gpointer user_data)932 set_rfkill_complete (GObject *object,
933 GAsyncResult *result,
934 gpointer user_data)
935 {
936 GError *error = NULL;
937 GVariant *variant;
938 RfkillData *data = user_data;
939
940 variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (object), result, &error);
941
942 if (variant == NULL) {
943 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
944 g_warning ("Failed to set '%s' property: %s", data->property, error->message);
945 g_error_free (error);
946 goto out;
947 }
948 g_variant_unref (variant);
949
950 g_debug ("Finished changing rfkill, property %s is now %s",
951 data->property, data->target_state ? "true" : "false");
952
953 if (data->bluetooth){
954 if (data->target_state)
955 msd_media_keys_window_set_action_custom (MSD_MEDIA_KEYS_WINDOW (data->manager->priv->dialog),
956 "bluetooth-disabled-symbolic", _("Bluetooth disabled"));
957 else
958 msd_media_keys_window_set_action_custom (MSD_MEDIA_KEYS_WINDOW (data->manager->priv->dialog),
959 "bluetooth-active-symbolic", _("Bluetooth enabled"));
960 } else {
961 if (data->target_state)
962 msd_media_keys_window_set_action_custom (MSD_MEDIA_KEYS_WINDOW (data->manager->priv->dialog),
963 "airplane-mode-symbolic", _("Airplane mode enabled"));
964 else
965 msd_media_keys_window_set_action_custom (MSD_MEDIA_KEYS_WINDOW (data->manager->priv->dialog),
966 "network-wireless-signal-excellent-symbolic", _("Airplane mode disabled"));
967 }
968 dialog_show (data->manager);
969 out:
970 g_free (data->property);
971 g_free (data);
972 }
973
974 static void
do_rfkill_action(MsdMediaKeysManager * manager,gboolean bluetooth)975 do_rfkill_action (MsdMediaKeysManager *manager,
976 gboolean bluetooth)
977 {
978 const char *has_mode, *hw_mode, *mode;
979 gboolean new_state;
980 RfkillData *data;
981
982 dialog_init (manager);
983
984 has_mode = bluetooth ? "BluetoothHasAirplaneMode" : "HasAirplaneMode";
985 hw_mode = bluetooth ? "BluetoothHardwareAirplaneMode" : "HardwareAirplaneMode";
986 mode = bluetooth ? "BluetoothAirplaneMode" : "AirplaneMode";
987
988 if (manager->priv->rfkill_proxy == NULL)
989 return;
990
991 if (get_rfkill_property (manager, has_mode) == FALSE)
992 return;
993
994 if (get_rfkill_property (manager, hw_mode)) {
995 msd_media_keys_window_set_action_custom (MSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
996 "airplane-mode-symbolic",
997 _("Hardware Airplane Mode"));
998 dialog_show (manager);
999 return;
1000 }
1001
1002 new_state = !get_rfkill_property (manager, mode);
1003 data = g_new0 (RfkillData, 1);
1004 data->manager = manager;
1005 data->property = g_strdup (mode);
1006 data->bluetooth = bluetooth;
1007 data->target_state = new_state;
1008 g_dbus_proxy_call (manager->priv->rfkill_proxy,
1009 "org.freedesktop.DBus.Properties.Set",
1010 g_variant_new ("(ssv)",
1011 "org.mate.SettingsDaemon.Rfkill",
1012 data->property,
1013 g_variant_new_boolean (new_state)),
1014 G_DBUS_CALL_FLAGS_NONE, -1,
1015 manager->priv->rfkill_cancellable,
1016 set_rfkill_complete, data);
1017
1018 g_debug ("Setting rfkill property %s to %s",
1019 data->property, new_state ? "true" : "false");
1020 }
1021
1022 static void
do_display_osd_action(MsdMediaKeysManager * manager)1023 do_display_osd_action (MsdMediaKeysManager *manager)
1024 {
1025 GdkDisplay *display;
1026 int n_monitors;
1027
1028 display = gdk_display_get_default ();
1029 n_monitors = gdk_display_get_n_monitors (display);
1030
1031 dialog_init (manager);
1032 if (n_monitors > 1)
1033 msd_media_keys_window_set_action_custom (MSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
1034 "video-joined-displays-symbolic",
1035 _("Changing Screen Layout"));
1036 else
1037 msd_media_keys_window_set_action_custom (MSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
1038 "video-single-display-symbolic",
1039 _("No External Display"));
1040 dialog_show (manager);
1041 }
1042
1043 static gint
find_by_application(gconstpointer a,gconstpointer b)1044 find_by_application (gconstpointer a,
1045 gconstpointer b)
1046 {
1047 return strcmp (((MediaPlayer *)a)->application, b);
1048 }
1049
1050 static gint
find_by_time(gconstpointer a,gconstpointer b)1051 find_by_time (gconstpointer a,
1052 gconstpointer b)
1053 {
1054 return ((MediaPlayer *)a)->time < ((MediaPlayer *)b)->time;
1055 }
1056
1057 /*
1058 * Register a new media player. Most applications will want to call
1059 * this with time = GDK_CURRENT_TIME. This way, the last registered
1060 * player will receive media events. In some cases, applications
1061 * may want to register with a lower priority (usually 1), to grab
1062 * events only nobody is interested.
1063 */
1064 gboolean
msd_media_keys_manager_grab_media_player_keys(MsdMediaKeysManager * manager,const char * application,guint32 time,GError ** error)1065 msd_media_keys_manager_grab_media_player_keys (MsdMediaKeysManager *manager,
1066 const char *application,
1067 guint32 time,
1068 GError **error)
1069 {
1070 GList *iter;
1071 MediaPlayer *media_player;
1072
1073 if (time == GDK_CURRENT_TIME) {
1074 time = (guint32)(g_get_monotonic_time () / 1000);
1075 }
1076
1077 iter = g_list_find_custom (manager->priv->media_players,
1078 application,
1079 find_by_application);
1080
1081 if (iter != NULL) {
1082 if (((MediaPlayer *)iter->data)->time < time) {
1083 g_free (((MediaPlayer *)iter->data)->application);
1084 g_free (iter->data);
1085 manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter);
1086 } else {
1087 return TRUE;
1088 }
1089 }
1090
1091 g_debug ("Registering %s at %u", application, time);
1092 media_player = g_new0 (MediaPlayer, 1);
1093 media_player->application = g_strdup (application);
1094 media_player->time = time;
1095
1096 manager->priv->media_players = g_list_insert_sorted (manager->priv->media_players,
1097 media_player,
1098 find_by_time);
1099
1100 return TRUE;
1101 }
1102
1103 gboolean
msd_media_keys_manager_release_media_player_keys(MsdMediaKeysManager * manager,const char * application,GError ** error)1104 msd_media_keys_manager_release_media_player_keys (MsdMediaKeysManager *manager,
1105 const char *application,
1106 GError **error)
1107 {
1108 GList *iter;
1109
1110 iter = g_list_find_custom (manager->priv->media_players,
1111 application,
1112 find_by_application);
1113
1114 if (iter != NULL) {
1115 g_debug ("Deregistering %s", application);
1116 g_free (((MediaPlayer *)iter->data)->application);
1117 g_free (iter->data);
1118 manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter);
1119 }
1120
1121 return TRUE;
1122 }
1123
1124 static gboolean
msd_media_player_key_pressed(MsdMediaKeysManager * manager,const char * key)1125 msd_media_player_key_pressed (MsdMediaKeysManager *manager,
1126 const char *key)
1127 {
1128 const char *application = NULL;
1129 gboolean have_listeners;
1130
1131 have_listeners = (manager->priv->media_players != NULL);
1132
1133 if (have_listeners) {
1134 application = ((MediaPlayer *)manager->priv->media_players->data)->application;
1135 }
1136
1137 g_signal_emit (manager, signals[MEDIA_PLAYER_KEY_PRESSED], 0, application, key);
1138
1139 return !have_listeners;
1140 }
1141
1142 static gboolean
do_multimedia_player_action(MsdMediaKeysManager * manager,const char * key)1143 do_multimedia_player_action (MsdMediaKeysManager *manager,
1144 const char *key)
1145 {
1146 return msd_media_player_key_pressed (manager, key);
1147 }
1148
1149 static void
do_toggle_accessibility_key(const char * key)1150 do_toggle_accessibility_key (const char *key)
1151 {
1152 GSettings *settings;
1153 gboolean state;
1154
1155 settings = g_settings_new ("org.gnome.desktop.a11y.applications");
1156 state = g_settings_get_boolean (settings, key);
1157 g_settings_set_boolean (settings, key, !state);
1158 g_object_unref (settings);
1159 }
1160
1161 static void
do_magnifier_action(MsdMediaKeysManager * manager)1162 do_magnifier_action (MsdMediaKeysManager *manager)
1163 {
1164 do_toggle_accessibility_key ("screen-magnifier-enabled");
1165 }
1166
1167 static void
do_screenreader_action(MsdMediaKeysManager * manager)1168 do_screenreader_action (MsdMediaKeysManager *manager)
1169 {
1170 do_toggle_accessibility_key ("screen-reader-enabled");
1171 }
1172
1173 static void
do_on_screen_keyboard_action(MsdMediaKeysManager * manager)1174 do_on_screen_keyboard_action (MsdMediaKeysManager *manager)
1175 {
1176 do_toggle_accessibility_key ("screen-keyboard-enabled");
1177 }
1178
1179 static gboolean
do_action(MsdMediaKeysManager * manager,int type)1180 do_action (MsdMediaKeysManager *manager,
1181 int type)
1182 {
1183 char *cmd;
1184 char *path;
1185
1186 switch (type) {
1187 case TOUCHPAD_KEY:
1188 do_touchpad_action (manager);
1189 break;
1190 case TOUCHPAD_ON_KEY:
1191 do_touchpad_osd_action(manager, TRUE);
1192 break;
1193 case TOUCHPAD_OFF_KEY:
1194 do_touchpad_osd_action(manager, FALSE);
1195 break;
1196 case MUTE_KEY:
1197 case VOLUME_DOWN_KEY:
1198 case VOLUME_UP_KEY:
1199 case MIC_MUTE_KEY:
1200 #ifdef HAVE_LIBMATEMIXER
1201 do_sound_action (manager, type, FALSE);
1202 #endif
1203 break;
1204 case MUTE_QUIET_KEY:
1205 #ifdef HAVE_LIBMATEMIXER
1206 do_sound_action (manager, MUTE_KEY, TRUE);
1207 #endif
1208 break;
1209 case VOLUME_DOWN_QUIET_KEY:
1210 #ifdef HAVE_LIBMATEMIXER
1211 do_sound_action (manager, VOLUME_DOWN_KEY, TRUE);
1212 #endif
1213 break;
1214 case VOLUME_UP_QUIET_KEY:
1215 #ifdef HAVE_LIBMATEMIXER
1216 do_sound_action (manager, VOLUME_UP_KEY, TRUE);
1217 #endif
1218 break;
1219 case POWER_KEY:
1220 do_shutdown_action (manager);
1221 break;
1222 case LOGOUT_KEY:
1223 do_logout_action (manager);
1224 break;
1225 case EJECT_KEY:
1226 do_eject_action (manager);
1227 break;
1228 case HOME_KEY:
1229 path = g_shell_quote (g_get_home_dir ());
1230 cmd = g_strconcat ("caja --no-desktop ", path, NULL);
1231 g_free (path);
1232 execute (manager, cmd, FALSE, FALSE);
1233 g_free (cmd);
1234 break;
1235 case SEARCH_KEY:
1236 cmd = NULL;
1237 if ((cmd = g_find_program_in_path ("beagle-search"))) {
1238 execute (manager, "beagle-search", FALSE, FALSE);
1239 } else if ((cmd = g_find_program_in_path ("tracker-search-tool"))) {
1240 execute (manager, "tracker-search-tool", FALSE, FALSE);
1241 } else {
1242 execute (manager, "mate-search-tool", FALSE, FALSE);
1243 }
1244 g_free (cmd);
1245 break;
1246 case EMAIL_KEY:
1247 do_url_action (manager, "mailto");
1248 break;
1249 case CONTROL_CENTER_KEY:
1250 if ((cmd = g_find_program_in_path ("mate-control-center")))
1251 execute (manager, "mate-control-center", FALSE, FALSE);
1252
1253 g_free (cmd);
1254 break;
1255 case SCREENSAVER_KEY:
1256 if ((cmd = g_find_program_in_path ("mate-screensaver-command"))) {
1257 execute (manager, "mate-screensaver-command --lock", FALSE, FALSE);
1258 } else {
1259 execute (manager, "xscreensaver-command -lock", FALSE, FALSE);
1260 }
1261
1262 g_free (cmd);
1263 break;
1264 case HELP_KEY:
1265 do_url_action (manager, "help");
1266 break;
1267 case WWW_KEY:
1268 do_url_action (manager, "http");
1269 break;
1270 case MEDIA_KEY:
1271 do_media_action (manager);
1272 break;
1273 case CALCULATOR_KEY:
1274 do_calculator_action (manager);
1275 break;
1276 case MESSENGER_KEY:
1277 do_messenger_action (manager);
1278 break;
1279 case PLAY_KEY:
1280 return do_multimedia_player_action (manager, "Play");
1281 case PAUSE_KEY:
1282 return do_multimedia_player_action (manager, "Pause");
1283 case STOP_KEY:
1284 return do_multimedia_player_action (manager, "Stop");
1285 case PREVIOUS_KEY:
1286 return do_multimedia_player_action (manager, "Previous");
1287 case NEXT_KEY:
1288 return do_multimedia_player_action (manager, "Next");
1289 case REWIND_KEY:
1290 return do_multimedia_player_action (manager, "Rewind");
1291 case FORWARD_KEY:
1292 return do_multimedia_player_action (manager, "FastForward");
1293 case REPEAT_KEY:
1294 return do_multimedia_player_action (manager, "Repeat");
1295 case RANDOM_KEY:
1296 return do_multimedia_player_action (manager, "Shuffle");
1297 case MAGNIFIER_KEY:
1298 do_magnifier_action (manager);
1299 break;
1300 case SCREENREADER_KEY:
1301 do_screenreader_action (manager);
1302 break;
1303 case ON_SCREEN_KEYBOARD_KEY:
1304 do_on_screen_keyboard_action (manager);
1305 break;
1306 case RFKILL_KEY:
1307 do_rfkill_action (manager, FALSE);
1308 break;
1309 case BLUETOOTH_RFKILL_KEY:
1310 do_rfkill_action (manager, TRUE);
1311 break;
1312 case DISPLAY_KEY:
1313 do_display_osd_action (manager);
1314 break;
1315 default:
1316 g_assert_not_reached ();
1317 }
1318
1319 return FALSE;
1320 }
1321
1322 static GdkScreen *
acme_get_screen_from_event(MsdMediaKeysManager * manager,XAnyEvent * xanyev)1323 acme_get_screen_from_event (MsdMediaKeysManager *manager,
1324 XAnyEvent *xanyev)
1325 {
1326 GdkWindow *window;
1327 GdkScreen *screen;
1328 GSList *l;
1329
1330 /* Look for which screen we're receiving events */
1331 for (l = manager->priv->screens; l != NULL; l = l->next) {
1332 screen = (GdkScreen *) l->data;
1333 window = gdk_screen_get_root_window (screen);
1334
1335 if (GDK_WINDOW_XID (window) == xanyev->window) {
1336 return screen;
1337 }
1338 }
1339
1340 return NULL;
1341 }
1342
1343 static GdkFilterReturn
acme_filter_events(GdkXEvent * xevent,GdkEvent * event,MsdMediaKeysManager * manager)1344 acme_filter_events (GdkXEvent *xevent,
1345 GdkEvent *event,
1346 MsdMediaKeysManager *manager)
1347 {
1348 XEvent *xev = (XEvent *) xevent;
1349 XAnyEvent *xany = (XAnyEvent *) xevent;
1350 int i;
1351
1352 /* verify we have a key event */
1353 if (xev->type != KeyPress) {
1354 return GDK_FILTER_CONTINUE;
1355 }
1356
1357 for (i = 0; i < HANDLED_KEYS; i++) {
1358 if (match_key (keys[i].key, xev)) {
1359 switch (keys[i].key_type) {
1360 case VOLUME_DOWN_KEY:
1361 case VOLUME_UP_KEY:
1362 case VOLUME_DOWN_QUIET_KEY:
1363 case VOLUME_UP_QUIET_KEY:
1364 /* auto-repeatable keys */
1365 if (xev->type != KeyPress) {
1366 return GDK_FILTER_CONTINUE;
1367 }
1368 break;
1369 }
1370
1371 manager->priv->current_screen = acme_get_screen_from_event (manager, xany);
1372
1373 if (do_action (manager, keys[i].key_type) == FALSE) {
1374 return GDK_FILTER_REMOVE;
1375 } else {
1376 return GDK_FILTER_CONTINUE;
1377 }
1378 }
1379 }
1380
1381 return GDK_FILTER_CONTINUE;
1382 }
1383
1384 static void
on_rfkill_proxy_ready(GObject * source,GAsyncResult * result,gpointer data)1385 on_rfkill_proxy_ready (GObject *source,
1386 GAsyncResult *result,
1387 gpointer data)
1388 {
1389 MsdMediaKeysManager *manager = data;
1390
1391 manager->priv->rfkill_proxy =
1392 g_dbus_proxy_new_for_bus_finish (result, NULL);
1393 }
1394
1395 static void
rfkill_appeared_cb(GDBusConnection * connection,const gchar * name,const gchar * name_owner,gpointer user_data)1396 rfkill_appeared_cb (GDBusConnection *connection,
1397 const gchar *name,
1398 const gchar *name_owner,
1399 gpointer user_data)
1400 {
1401 MsdMediaKeysManager *manager = user_data;
1402
1403 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
1404 0, NULL,
1405 "org.mate.SettingsDaemon.Rfkill",
1406 "/org/mate/SettingsDaemon/Rfkill",
1407 "org.mate.SettingsDaemon.Rfkill",
1408 manager->priv->rfkill_cancellable,
1409 on_rfkill_proxy_ready, manager);
1410 }
1411
1412 static gboolean
start_media_keys_idle_cb(MsdMediaKeysManager * manager)1413 start_media_keys_idle_cb (MsdMediaKeysManager *manager)
1414 {
1415 GSList *l;
1416 GdkDisplay *dpy;
1417 Display *xdpy;
1418
1419 g_debug ("Starting media_keys manager");
1420 mate_settings_profile_start (NULL);
1421
1422 dpy = gdk_display_get_default ();
1423 xdpy = GDK_DISPLAY_XDISPLAY (dpy);
1424
1425 manager->priv->volume_monitor = g_volume_monitor_get ();
1426 manager->priv->settings = g_settings_new (BINDING_SCHEMA);
1427
1428 ensure_cancellable (&manager->priv->rfkill_cancellable);
1429
1430 init_screens (manager);
1431 init_kbd (manager);
1432
1433 /* Start filtering the events */
1434 for (l = manager->priv->screens; l != NULL; l = l->next) {
1435 GdkWindow *window;
1436 Window xwindow;
1437 XWindowAttributes atts;
1438
1439 mate_settings_profile_start ("gdk_window_add_filter");
1440
1441 window = gdk_screen_get_root_window (l->data);
1442 xwindow = GDK_WINDOW_XID (window);
1443
1444 g_debug ("adding key filter for screen: %d",
1445 gdk_x11_screen_get_screen_number (l->data));
1446
1447 gdk_window_add_filter (window,
1448 (GdkFilterFunc)acme_filter_events,
1449 manager);
1450
1451 gdk_x11_display_error_trap_push (dpy);
1452 /* Add KeyPressMask to the currently reportable event masks */
1453 XGetWindowAttributes (xdpy, xwindow, &atts);
1454 XSelectInput (xdpy, xwindow, atts.your_event_mask | KeyPressMask);
1455 gdk_x11_display_error_trap_pop_ignored (dpy);
1456
1457 mate_settings_profile_end ("gdk_window_add_filter");
1458 }
1459
1460 manager->priv->rfkill_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
1461 "org.mate.SettingsDaemon.Rfkill",
1462 G_BUS_NAME_WATCHER_FLAGS_NONE,
1463 rfkill_appeared_cb,
1464 NULL,
1465 manager, NULL);
1466
1467 mate_settings_profile_end (NULL);
1468
1469 return FALSE;
1470 }
1471
1472 gboolean
msd_media_keys_manager_start(MsdMediaKeysManager * manager,GError ** error)1473 msd_media_keys_manager_start (MsdMediaKeysManager *manager, GError **error)
1474 {
1475 mate_settings_profile_start (NULL);
1476
1477 #ifdef HAVE_LIBMATEMIXER
1478 if (G_LIKELY (mate_mixer_is_initialized ())) {
1479 mate_settings_profile_start ("mate_mixer_context_new");
1480
1481 manager->priv->context = mate_mixer_context_new ();
1482
1483 g_signal_connect (manager->priv->context,
1484 "notify::state",
1485 G_CALLBACK (on_context_state_notify),
1486 manager);
1487 g_signal_connect (manager->priv->context,
1488 "notify::default-output-stream",
1489 G_CALLBACK (on_context_default_output_notify),
1490 manager);
1491 g_signal_connect (manager->priv->context,
1492 "notify::default-input-stream",
1493 G_CALLBACK (on_context_default_input_notify),
1494 manager);
1495 g_signal_connect (manager->priv->context,
1496 "stream-removed",
1497 G_CALLBACK (on_context_stream_removed),
1498 manager);
1499
1500 mate_mixer_context_open (manager->priv->context);
1501
1502 mate_settings_profile_end ("mate_mixer_context_new");
1503 }
1504 #endif
1505 g_idle_add ((GSourceFunc) start_media_keys_idle_cb, manager);
1506
1507 mate_settings_profile_end (NULL);
1508
1509 return TRUE;
1510 }
1511
1512 void
msd_media_keys_manager_stop(MsdMediaKeysManager * manager)1513 msd_media_keys_manager_stop (MsdMediaKeysManager *manager)
1514 {
1515 MsdMediaKeysManagerPrivate *priv = manager->priv;
1516 GdkDisplay *dpy;
1517 GSList *ls;
1518 GList *l;
1519 int i;
1520 gboolean need_flush;
1521
1522 g_debug ("Stopping media_keys manager");
1523
1524 for (ls = priv->screens; ls != NULL; ls = ls->next) {
1525 gdk_window_remove_filter (gdk_screen_get_root_window (ls->data),
1526 (GdkFilterFunc) acme_filter_events,
1527 manager);
1528 }
1529
1530 if (manager->priv->rfkill_watch_id > 0) {
1531 g_bus_unwatch_name (manager->priv->rfkill_watch_id);
1532 manager->priv->rfkill_watch_id = 0;
1533 }
1534
1535 if (priv->settings != NULL) {
1536 g_object_unref (priv->settings);
1537 priv->settings = NULL;
1538 }
1539
1540 if (priv->volume_monitor != NULL) {
1541 g_object_unref (priv->volume_monitor);
1542 priv->volume_monitor = NULL;
1543 }
1544
1545 if (priv->connection != NULL) {
1546 dbus_g_connection_unref (priv->connection);
1547 priv->connection = NULL;
1548 }
1549
1550 need_flush = FALSE;
1551 dpy = gdk_display_get_default ();
1552 gdk_x11_display_error_trap_push (dpy);
1553
1554 for (i = 0; i < HANDLED_KEYS; ++i) {
1555 if (keys[i].key) {
1556 need_flush = TRUE;
1557 grab_key_unsafe (keys[i].key, FALSE, priv->screens);
1558
1559 g_free (keys[i].key->keycodes);
1560 g_free (keys[i].key);
1561 keys[i].key = NULL;
1562 }
1563 }
1564
1565 if (need_flush)
1566 gdk_display_flush (dpy);
1567
1568 gdk_x11_display_error_trap_pop_ignored (dpy);
1569
1570 g_slist_free (priv->screens);
1571 priv->screens = NULL;
1572
1573 if (priv->rfkill_cancellable != NULL) {
1574 g_cancellable_cancel (priv->rfkill_cancellable);
1575 g_clear_object (&priv->rfkill_cancellable);
1576 }
1577
1578 #ifdef HAVE_LIBMATEMIXER
1579 g_clear_object (&priv->stream);
1580 g_clear_object (&priv->source_stream);
1581 g_clear_object (&priv->control);
1582 g_clear_object (&priv->source_control);
1583 g_clear_object (&priv->context);
1584 #endif
1585
1586 if (priv->dialog != NULL) {
1587 gtk_widget_destroy (priv->dialog);
1588 priv->dialog = NULL;
1589 }
1590
1591 for (l = priv->media_players; l; l = l->next) {
1592 MediaPlayer *mp = l->data;
1593 g_free (mp->application);
1594 g_free (mp);
1595 }
1596 g_list_free (priv->media_players);
1597 priv->media_players = NULL;
1598 }
1599
1600 static void
msd_media_keys_manager_class_init(MsdMediaKeysManagerClass * klass)1601 msd_media_keys_manager_class_init (MsdMediaKeysManagerClass *klass)
1602 {
1603 signals[MEDIA_PLAYER_KEY_PRESSED] =
1604 g_signal_new ("media-player-key-pressed",
1605 G_OBJECT_CLASS_TYPE (klass),
1606 G_SIGNAL_RUN_LAST,
1607 G_STRUCT_OFFSET (MsdMediaKeysManagerClass, media_player_key_pressed),
1608 NULL,
1609 NULL,
1610 msd_marshal_VOID__STRING_STRING,
1611 G_TYPE_NONE,
1612 2,
1613 G_TYPE_STRING,
1614 G_TYPE_STRING);
1615
1616 dbus_g_object_type_install_info (MSD_TYPE_MEDIA_KEYS_MANAGER, &dbus_glib_msd_media_keys_manager_object_info);
1617 }
1618
1619 static void
msd_media_keys_manager_init(MsdMediaKeysManager * manager)1620 msd_media_keys_manager_init (MsdMediaKeysManager *manager)
1621 {
1622 manager->priv = msd_media_keys_manager_get_instance_private (manager);
1623 }
1624
1625 static gboolean
register_manager(MsdMediaKeysManager * manager)1626 register_manager (MsdMediaKeysManager *manager)
1627 {
1628 GError *error = NULL;
1629
1630 manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
1631 if (manager->priv->connection == NULL) {
1632 if (error != NULL) {
1633 g_error ("Error getting session bus: %s", error->message);
1634 g_error_free (error);
1635 }
1636 return FALSE;
1637 }
1638
1639 dbus_g_connection_register_g_object (manager->priv->connection, MSD_MEDIA_KEYS_DBUS_PATH, G_OBJECT (manager));
1640
1641 return TRUE;
1642 }
1643
1644 MsdMediaKeysManager *
msd_media_keys_manager_new(void)1645 msd_media_keys_manager_new (void)
1646 {
1647 if (manager_object != NULL) {
1648 g_object_ref (manager_object);
1649 } else {
1650 gboolean res;
1651
1652 manager_object = g_object_new (MSD_TYPE_MEDIA_KEYS_MANAGER, NULL);
1653 g_object_add_weak_pointer (manager_object,
1654 (gpointer *) &manager_object);
1655 res = register_manager (manager_object);
1656 if (! res) {
1657 g_object_unref (manager_object);
1658 return NULL;
1659 }
1660 }
1661
1662 return MSD_MEDIA_KEYS_MANAGER (manager_object);
1663 }
1664