cinnamon-settings-daemon-5.2.0/0000775000175000017500000000000014144454032015344 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/0000775000175000017500000000000014144454032017025 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/a11y-keyboard/0000775000175000017500000000000014144454032021376 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/a11y-keyboard/csd-a11y-preferences-dialog.ui0000664000175000017500000002611714144454032027022 0ustar fabiofabio GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 Universal Access Preferences center-on-parent preferences-desktop-accessibility dialog False True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 2 True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 10 True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 0 preferences-desktop-accessibility 6 0 True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 6 Use on-screen _keyboard True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 0 Use screen _reader True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 1 Use screen _magnifier True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 2 Enhance _contrast in colors True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 3 Make _text larger and easier to read True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 4 _Press keyboard shortcuts one key at a time (Sticky Keys) True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 5 _Ignore duplicate keypresses (Bounce Keys) True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 6 Press and _hold keys to accept them (Slow Keys) True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True True 7 False False 1 1 True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK end gtk-close True True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True False False 0 False end 0 button1 cinnamon-settings-daemon-5.2.0/plugins/a11y-keyboard/meson.build0000664000175000017500000000232714144454032023544 0ustar fabiofabioplugin_name = 'a11y-keyboard' a11y_keyboard_sources = [ 'csd-a11y-keyboard-manager.c', 'csd-a11y-preferences-dialog.c', 'main.c', ] a11y_keyboard_deps = [ common_dep, csd_dep, libnotify, ] executable( 'csd-a11y-keyboard', a11y_keyboard_sources, include_directories: [include_dirs, common_inc], dependencies: a11y_keyboard_deps, c_args: [ '-DPLUGIN_NAME="@0@"'.format(plugin_name), ], install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-a11y-keyboard') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-a11y-keyboard') endif test_a11y_prefs_dialog_sources = [ 'csd-a11y-preferences-dialog.c', 'test-a11y-preferences-dialog.c', ] executable( 'test-a11y-preferences-dialog', test_a11y_prefs_dialog_sources, dependencies: a11y_keyboard_deps, install: false, ) configure_file( input: 'cinnamon-settings-daemon-a11y-keyboard.desktop.in', output: 'cinnamon-settings-daemon-a11y-keyboard.desktop', configuration: desktop_conf, install_dir: autostartdir, ) install_data( 'csd-a11y-preferences-dialog.ui', install_dir: pkgdatadir, ) cinnamon-settings-daemon-5.2.0/plugins/a11y-keyboard/test-a11y-preferences-dialog.c0000664000175000017500000000317514144454032027034 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * */ #include "config.h" #include #include #include #include "csd-a11y-preferences-dialog.h" static void test_window (void) { GtkWidget *window; window = csd_a11y_preferences_dialog_new (); gtk_dialog_run (GTK_DIALOG (window)); } int main (int argc, char **argv) { GError *error = NULL; bindtextdomain (GETTEXT_PACKAGE, CINNAMON_SETTINGS_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); if (! gtk_init_with_args (&argc, &argv, NULL, NULL, NULL, &error)) { fprintf (stderr, "%s", error->message); g_error_free (error); exit (1); } test_window (); return 0; } cinnamon-settings-daemon-5.2.0/plugins/a11y-keyboard/csd-a11y-keyboard-manager.h0000664000175000017500000000475014144454032026305 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CSD_A11Y_KEYBOARD_MANAGER_H #define __CSD_A11Y_KEYBOARD_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_A11Y_KEYBOARD_MANAGER (csd_a11y_keyboard_manager_get_type ()) #define CSD_A11Y_KEYBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_A11Y_KEYBOARD_MANAGER, CsdA11yKeyboardManager)) #define CSD_A11Y_KEYBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_A11Y_KEYBOARD_MANAGER, CsdA11yKeyboardManagerClass)) #define CSD_IS_A11Y_KEYBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_A11Y_KEYBOARD_MANAGER)) #define CSD_IS_A11Y_KEYBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_A11Y_KEYBOARD_MANAGER)) #define CSD_A11Y_KEYBOARD_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_A11Y_KEYBOARD_MANAGER, CsdA11yKeyboardManagerClass)) typedef struct CsdA11yKeyboardManagerPrivate CsdA11yKeyboardManagerPrivate; typedef struct { GObject parent; CsdA11yKeyboardManagerPrivate *priv; } CsdA11yKeyboardManager; typedef struct { GObjectClass parent_class; } CsdA11yKeyboardManagerClass; GType csd_a11y_keyboard_manager_get_type (void); CsdA11yKeyboardManager *csd_a11y_keyboard_manager_new (void); gboolean csd_a11y_keyboard_manager_start (CsdA11yKeyboardManager *manager, GError **error); void csd_a11y_keyboard_manager_stop (CsdA11yKeyboardManager *manager); G_END_DECLS #endif /* __CSD_A11Y_KEYBOARD_MANAGER_H */ cinnamon-settings-daemon-5.2.0/plugins/a11y-keyboard/main.c0000664000175000017500000000105414144454032022466 0ustar fabiofabio#define NEW csd_a11y_keyboard_manager_new #define START csd_a11y_keyboard_manager_start #define STOP csd_a11y_keyboard_manager_stop #define MANAGER CsdA11yKeyboardManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-a11y-keyboard-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-5.2.0/plugins/a11y-keyboard/csd-a11y-keyboard-manager.c0000664000175000017500000013266114144454032026303 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright © 2001 Ximian, Inc. * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-a11y-keyboard-manager.h" #include "csd-a11y-preferences-dialog.h" #define KEYBOARD_A11Y_SCHEMA "org.cinnamon.desktop.a11y.keyboard" #define NOTIFICATION_TIMEOUT 30 #define CSD_A11Y_KEYBOARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_A11Y_KEYBOARD_MANAGER, CsdA11yKeyboardManagerPrivate)) struct CsdA11yKeyboardManagerPrivate { guint start_idle_id; int xkbEventBase; GdkDeviceManager *device_manager; guint device_added_id; gboolean stickykeys_shortcut_val; gboolean slowkeys_shortcut_val; GtkWidget *stickykeys_alert; GtkWidget *slowkeys_alert; GtkWidget *preferences_dialog; GtkStatusIcon *status_icon; GSettings *settings; NotifyNotification *notification; }; static void csd_a11y_keyboard_manager_finalize (GObject *object); static void csd_a11y_keyboard_manager_ensure_status_icon (CsdA11yKeyboardManager *manager); static void set_server_from_gsettings (CsdA11yKeyboardManager *manager); G_DEFINE_TYPE (CsdA11yKeyboardManager, csd_a11y_keyboard_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static void device_added_cb (GdkDeviceManager *device_manager, GdkDevice *device, CsdA11yKeyboardManager *manager) { if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) set_server_from_gsettings (manager); } static void set_devicepresence_handler (CsdA11yKeyboardManager *manager) { GdkDeviceManager *device_manager; device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); if (device_manager == NULL) return; manager->priv->device_manager = device_manager; manager->priv->device_added_id = g_signal_connect (G_OBJECT (device_manager), "device-added", G_CALLBACK (device_added_cb), manager); } static gboolean xkb_enabled (CsdA11yKeyboardManager *manager) { int opcode, errorBase, major, minor; if (!XkbQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &opcode, &manager->priv->xkbEventBase, &errorBase, &major, &minor)) return FALSE; if (!XkbUseExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &major, &minor)) return FALSE; return TRUE; } static XkbDescRec * get_xkb_desc_rec (CsdA11yKeyboardManager *manager) { XkbDescRec *desc; Status status = Success; gdk_x11_display_error_trap_push (gdk_display_get_default ()); desc = XkbGetMap (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbAllMapComponentsMask, XkbUseCoreKbd); if (desc != NULL) { desc->ctrls = NULL; status = XkbGetControls (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbAllControlsMask, desc); } gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); g_return_val_if_fail (desc != NULL, NULL); g_return_val_if_fail (desc->ctrls != NULL, NULL); g_return_val_if_fail (status == Success, NULL); return desc; } static int get_int (GSettings *settings, char const *key) { int res = g_settings_get_int (settings, key); if (res <= 0) { res = 1; } return res; } static gboolean set_int (GSettings *settings, char const *key, int val) { int prev_val; prev_val = g_settings_get_int (settings, key); g_settings_set_int (settings, key, val); if (val != prev_val) { g_debug ("%s changed", key); } return val != prev_val; } static gboolean set_bool (GSettings *settings, char const *key, int val) { gboolean bval = (val != 0); gboolean prev_val; prev_val = g_settings_get_boolean (settings, key); g_settings_set_boolean (settings, key, bval ? TRUE : FALSE); if (bval != prev_val) { g_debug ("%s changed", key); return TRUE; } return (bval != prev_val); } static unsigned long set_clear (gboolean flag, unsigned long value, unsigned long mask) { if (flag) { return value | mask; } return value & ~mask; } static gboolean set_ctrl_from_gsettings (XkbDescRec *desc, GSettings *settings, char const *key, unsigned long mask) { gboolean result = g_settings_get_boolean (settings, key); desc->ctrls->enabled_ctrls = set_clear (result, desc->ctrls->enabled_ctrls, mask); return result; } static void set_server_from_gsettings (CsdA11yKeyboardManager *manager) { XkbDescRec *desc; gboolean enable_accessX; GSettings *settings; cinnamon_settings_profile_start (NULL); desc = get_xkb_desc_rec (manager); if (!desc) { return; } settings = manager->priv->settings; /* general */ enable_accessX = g_settings_get_boolean (settings, "enable"); desc->ctrls->enabled_ctrls = set_clear (enable_accessX, desc->ctrls->enabled_ctrls, XkbAccessXKeysMask); if (set_ctrl_from_gsettings (desc, settings, "timeout-enable", XkbAccessXTimeoutMask)) { desc->ctrls->ax_timeout = get_int (settings, "disable-timeout"); /* disable only the master flag via the server we will disable * the rest on the rebound without affecting GSettings state * don't change the option flags at all. */ desc->ctrls->axt_ctrls_mask = XkbAccessXKeysMask | XkbAccessXFeedbackMask; desc->ctrls->axt_ctrls_values = 0; desc->ctrls->axt_opts_mask = 0; } desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "feature-state-change-beep"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask); /* bounce keys */ if (set_ctrl_from_gsettings (desc, settings, "bouncekeys-enable", XkbBounceKeysMask)) { desc->ctrls->debounce_delay = get_int (settings, "bouncekeys-delay"); desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "bouncekeys-beep-reject"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_BKRejectFBMask); } /* mouse keys */ if (set_ctrl_from_gsettings (desc, settings, "mousekeys-enable", XkbMouseKeysMask | XkbMouseKeysAccelMask)) { desc->ctrls->mk_interval = 100; /* msec between mousekey events */ desc->ctrls->mk_curve = 50; /* We store pixels / sec, XKB wants pixels / event */ desc->ctrls->mk_max_speed = get_int (settings, "mousekeys-max-speed") / (1000 / desc->ctrls->mk_interval); if (desc->ctrls->mk_max_speed <= 0) desc->ctrls->mk_max_speed = 1; desc->ctrls->mk_time_to_max = get_int (settings, /* events before max */ "mousekeys-accel-time") / desc->ctrls->mk_interval; if (desc->ctrls->mk_time_to_max <= 0) desc->ctrls->mk_time_to_max = 1; desc->ctrls->mk_delay = get_int (settings, /* ms before 1st event */ "mousekeys-init-delay"); } /* slow keys */ if (set_ctrl_from_gsettings (desc, settings, "slowkeys-enable", XkbSlowKeysMask)) { desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "slowkeys-beep-press"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKPressFBMask); desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "slowkeys-beep-accept"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKAcceptFBMask); desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "slowkeys-beep-reject"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKRejectFBMask); desc->ctrls->slow_keys_delay = get_int (settings, "slowkeys-delay"); /* anything larger than 500 seems to loose all keyboard input */ if (desc->ctrls->slow_keys_delay > 500) desc->ctrls->slow_keys_delay = 500; } /* sticky keys */ if (set_ctrl_from_gsettings (desc, settings, "stickykeys-enable", XkbStickyKeysMask)) { desc->ctrls->ax_options |= XkbAX_LatchToLockMask; desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "stickykeys-two-key-off"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_TwoKeysMask); desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "stickykeys-modifier-beep"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_StickyKeysFBMask); } /* g_debug ("CHANGE to : 0x%x", desc->ctrls->enabled_ctrls); g_debug ("CHANGE to : 0x%x (2)", desc->ctrls->ax_options); */ gdk_x11_display_error_trap_push (gdk_display_get_default ()); XkbSetControls (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbSlowKeysMask | XkbBounceKeysMask | XkbStickyKeysMask | XkbMouseKeysMask | XkbMouseKeysAccelMask | XkbAccessXKeysMask | XkbAccessXTimeoutMask | XkbAccessXFeedbackMask | XkbControlsEnabledMask, desc); XkbFreeKeyboard (desc, XkbAllComponentsMask, True); XSync (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), FALSE); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); cinnamon_settings_profile_end (NULL); } static gboolean ax_response_callback (CsdA11yKeyboardManager *manager, GtkWindow *parent, gint response_id, guint revert_controls_mask, gboolean enabled) { GSettings *settings; GdkScreen *screen; GError *err; settings = manager->priv->settings; switch (response_id) { case GTK_RESPONSE_DELETE_EVENT: case GTK_RESPONSE_REJECT: case GTK_RESPONSE_CANCEL: /* we're reverting, so we invert sense of 'enabled' flag */ g_debug ("cancelling AccessX request"); if (revert_controls_mask == XkbStickyKeysMask) { g_settings_set_boolean (settings, "stickykeys-enable", !enabled); } else if (revert_controls_mask == XkbSlowKeysMask) { g_settings_set_boolean (settings, "slowkeys-enable", !enabled); } set_server_from_gsettings (manager); break; case GTK_RESPONSE_HELP: if (!parent) screen = gdk_screen_get_default (); else screen = gtk_widget_get_screen (GTK_WIDGET (parent)); err = NULL; if (!gtk_show_uri (screen, "help:gnome-help/a11y", gtk_get_current_event_time(), &err)) { GtkWidget *error_dialog = gtk_message_dialog_new (parent, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("There was an error displaying help: %s"), err->message); g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); gtk_window_set_resizable (GTK_WINDOW (error_dialog), FALSE); gtk_widget_show (error_dialog); g_error_free (err); } return FALSE; default: break; } return TRUE; } static void ax_stickykeys_response (GtkDialog *dialog, gint response_id, CsdA11yKeyboardManager *manager) { if (ax_response_callback (manager, GTK_WINDOW (dialog), response_id, XkbStickyKeysMask, manager->priv->stickykeys_shortcut_val)) { gtk_widget_destroy (GTK_WIDGET (dialog)); } } static void ax_slowkeys_response (GtkDialog *dialog, gint response_id, CsdA11yKeyboardManager *manager) { if (ax_response_callback (manager, GTK_WINDOW (dialog), response_id, XkbSlowKeysMask, manager->priv->slowkeys_shortcut_val)) { gtk_widget_destroy (GTK_WIDGET (dialog)); } } static void maybe_show_status_icon (CsdA11yKeyboardManager *manager) { gboolean show; /* for now, show if accessx is enabled */ show = g_settings_get_boolean (manager->priv->settings, "enable"); if (!show && manager->priv->status_icon == NULL) return; csd_a11y_keyboard_manager_ensure_status_icon (manager); gtk_status_icon_set_visible (manager->priv->status_icon, show); } static void on_notification_closed (NotifyNotification *notification, CsdA11yKeyboardManager *manager) { g_object_unref (manager->priv->notification); manager->priv->notification = NULL; } static void on_slow_keys_action (NotifyNotification *notification, const char *action, CsdA11yKeyboardManager *manager) { gboolean res; int response_id; g_assert (action != NULL); if (strcmp (action, "accept") == 0) { response_id = GTK_RESPONSE_ACCEPT; } else if (strcmp (action, "reject") == 0) { response_id = GTK_RESPONSE_REJECT; } else { return; } res = ax_response_callback (manager, NULL, response_id, XkbSlowKeysMask, manager->priv->slowkeys_shortcut_val); if (res) { notify_notification_close (manager->priv->notification, NULL); } } static void on_sticky_keys_action (NotifyNotification *notification, const char *action, CsdA11yKeyboardManager *manager) { gboolean res; int response_id; g_assert (action != NULL); if (strcmp (action, "accept") == 0) { response_id = GTK_RESPONSE_ACCEPT; } else if (strcmp (action, "reject") == 0) { response_id = GTK_RESPONSE_REJECT; } else { return; } res = ax_response_callback (manager, NULL, response_id, XkbStickyKeysMask, manager->priv->stickykeys_shortcut_val); if (res) { notify_notification_close (manager->priv->notification, NULL); } } static gboolean ax_slowkeys_warning_post_bubble (CsdA11yKeyboardManager *manager, gboolean enabled) { gboolean res; const char *title; const char *message; GError *error; title = enabled ? _("Slow Keys Turned On") : _("Slow Keys Turned Off"); message = _("You just held down the Shift key for 8 seconds. This is the shortcut " "for the Slow Keys feature, which affects the way your keyboard works."); if (manager->priv->status_icon == NULL || ! gtk_status_icon_is_embedded (manager->priv->status_icon)) { return FALSE; } if (manager->priv->slowkeys_alert != NULL) { gtk_widget_destroy (manager->priv->slowkeys_alert); } if (manager->priv->notification != NULL) { notify_notification_close (manager->priv->notification, NULL); } csd_a11y_keyboard_manager_ensure_status_icon (manager); manager->priv->notification = notify_notification_new (title, message, "preferences-desktop-accessibility-symbolic"); notify_notification_set_app_name (manager->priv->notification, _("Universal Access")); notify_notification_set_timeout (manager->priv->notification, NOTIFICATION_TIMEOUT * 1000); notify_notification_set_hint (manager->priv->notification, "transient", g_variant_new_boolean (TRUE)); notify_notification_add_action (manager->priv->notification, "reject", enabled ? _("Turn Off") : _("Turn On"), (NotifyActionCallback) on_slow_keys_action, manager, NULL); notify_notification_add_action (manager->priv->notification, "accept", enabled ? _("Leave On") : _("Leave Off"), (NotifyActionCallback) on_slow_keys_action, manager, NULL); g_signal_connect (manager->priv->notification, "closed", G_CALLBACK (on_notification_closed), manager); error = NULL; res = notify_notification_show (manager->priv->notification, &error); if (! res) { g_warning ("CsdA11yKeyboardManager: unable to show notification: %s", error->message); g_error_free (error); notify_notification_close (manager->priv->notification, NULL); } return res; } static void ax_slowkeys_warning_post_dialog (CsdA11yKeyboardManager *manager, gboolean enabled) { const char *title; const char *message; title = enabled ? _("Slow Keys Turned On") : _("Slow Keys Turned Off"); message = _("You just held down the Shift key for 8 seconds. This is the shortcut " "for the Slow Keys feature, which affects the way your keyboard works."); if (manager->priv->slowkeys_alert != NULL) { gtk_widget_show (manager->priv->slowkeys_alert); return; } manager->priv->slowkeys_alert = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s", title); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (manager->priv->slowkeys_alert), "%s", message); gtk_dialog_add_button (GTK_DIALOG (manager->priv->slowkeys_alert), GTK_STOCK_HELP, GTK_RESPONSE_HELP); gtk_dialog_add_button (GTK_DIALOG (manager->priv->slowkeys_alert), enabled ? _("_Turn Off") : _("_Turn On"), GTK_RESPONSE_REJECT); gtk_dialog_add_button (GTK_DIALOG (manager->priv->slowkeys_alert), enabled ? _("_Leave On") : _("_Leave Off"), GTK_RESPONSE_ACCEPT); gtk_window_set_title (GTK_WINDOW (manager->priv->slowkeys_alert), ""); gtk_window_set_icon_name (GTK_WINDOW (manager->priv->slowkeys_alert), "preferences-desktop-accessibility"); gtk_dialog_set_default_response (GTK_DIALOG (manager->priv->slowkeys_alert), GTK_RESPONSE_ACCEPT); g_signal_connect (manager->priv->slowkeys_alert, "response", G_CALLBACK (ax_slowkeys_response), manager); gtk_widget_show (manager->priv->slowkeys_alert); g_object_add_weak_pointer (G_OBJECT (manager->priv->slowkeys_alert), (gpointer*) &manager->priv->slowkeys_alert); } static void ax_slowkeys_warning_post (CsdA11yKeyboardManager *manager, gboolean enabled) { manager->priv->slowkeys_shortcut_val = enabled; /* alway try to show something */ if (! ax_slowkeys_warning_post_bubble (manager, enabled)) { ax_slowkeys_warning_post_dialog (manager, enabled); } } static gboolean ax_stickykeys_warning_post_bubble (CsdA11yKeyboardManager *manager, gboolean enabled) { #if 1 gboolean res; const char *title; const char *message; GError *error; title = enabled ? _("Sticky Keys Turned On") : _("Sticky Keys Turned Off"); message = enabled ? _("You just pressed the Shift key 5 times in a row. This is the shortcut " "for the Sticky Keys feature, which affects the way your keyboard works.") : _("You just pressed two keys at once, or pressed the Shift key 5 times in a row. " "This turns off the Sticky Keys feature, which affects the way your keyboard works."); if (manager->priv->status_icon == NULL || ! gtk_status_icon_is_embedded (manager->priv->status_icon)) { return FALSE; } if (manager->priv->slowkeys_alert != NULL) { gtk_widget_destroy (manager->priv->slowkeys_alert); } if (manager->priv->notification != NULL) { notify_notification_close (manager->priv->notification, NULL); } csd_a11y_keyboard_manager_ensure_status_icon (manager); manager->priv->notification = notify_notification_new (title, message, "preferences-desktop-accessibility-symbolic"); notify_notification_set_app_name (manager->priv->notification, _("Universal Access")); notify_notification_set_timeout (manager->priv->notification, NOTIFICATION_TIMEOUT * 1000); notify_notification_set_hint (manager->priv->notification, "transient", g_variant_new_boolean (TRUE)); notify_notification_add_action (manager->priv->notification, "reject", enabled ? _("Turn Off") : _("Turn On"), (NotifyActionCallback) on_sticky_keys_action, manager, NULL); notify_notification_add_action (manager->priv->notification, "accept", enabled ? _("Leave On") : _("Leave Off"), (NotifyActionCallback) on_sticky_keys_action, manager, NULL); g_signal_connect (manager->priv->notification, "closed", G_CALLBACK (on_notification_closed), manager); error = NULL; res = notify_notification_show (manager->priv->notification, &error); if (! res) { g_warning ("CsdA11yKeyboardManager: unable to show notification: %s", error->message); g_error_free (error); notify_notification_close (manager->priv->notification, NULL); } return res; #endif /* 1 */ } static void ax_stickykeys_warning_post_dialog (CsdA11yKeyboardManager *manager, gboolean enabled) { const char *title; const char *message; title = enabled ? _("Sticky Keys Turned On") : _("Sticky Keys Turned Off"); message = enabled ? _("You just pressed the Shift key 5 times in a row. This is the shortcut " "for the Sticky Keys feature, which affects the way your keyboard works.") : _("You just pressed two keys at once, or pressed the Shift key 5 times in a row. " "This turns off the Sticky Keys feature, which affects the way your keyboard works."); if (manager->priv->stickykeys_alert != NULL) { gtk_widget_show (manager->priv->stickykeys_alert); return; } manager->priv->stickykeys_alert = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s", title); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (manager->priv->stickykeys_alert), "%s", message); gtk_dialog_add_button (GTK_DIALOG (manager->priv->stickykeys_alert), GTK_STOCK_HELP, GTK_RESPONSE_HELP); gtk_dialog_add_button (GTK_DIALOG (manager->priv->stickykeys_alert), enabled ? _("_Turn Off") : _("_Turn On"), GTK_RESPONSE_REJECT); gtk_dialog_add_button (GTK_DIALOG (manager->priv->stickykeys_alert), enabled ? _("_Leave On") : _("_Leave Off"), GTK_RESPONSE_ACCEPT); gtk_window_set_title (GTK_WINDOW (manager->priv->stickykeys_alert), ""); gtk_window_set_icon_name (GTK_WINDOW (manager->priv->stickykeys_alert), "preferences-desktop-accessibility"); gtk_dialog_set_default_response (GTK_DIALOG (manager->priv->stickykeys_alert), GTK_RESPONSE_ACCEPT); g_signal_connect (manager->priv->stickykeys_alert, "response", G_CALLBACK (ax_stickykeys_response), manager); gtk_widget_show (manager->priv->stickykeys_alert); g_object_add_weak_pointer (G_OBJECT (manager->priv->stickykeys_alert), (gpointer*) &manager->priv->stickykeys_alert); } static void ax_stickykeys_warning_post (CsdA11yKeyboardManager *manager, gboolean enabled) { manager->priv->stickykeys_shortcut_val = enabled; /* alway try to show something */ if (! ax_stickykeys_warning_post_bubble (manager, enabled)) { ax_stickykeys_warning_post_dialog (manager, enabled); } } static void set_gsettings_from_server (CsdA11yKeyboardManager *manager) { XkbDescRec *desc; gboolean changed = FALSE; gboolean slowkeys_changed; gboolean stickykeys_changed; GSettings *settings; desc = get_xkb_desc_rec (manager); if (! desc) { return; } /* Create a new one, so that only those settings * are delayed */ settings = g_settings_new (KEYBOARD_A11Y_SCHEMA); g_settings_delay (settings); /* fprintf (stderr, "changed to : 0x%x\n", desc->ctrls->enabled_ctrls); fprintf (stderr, "changed to : 0x%x (2)\n", desc->ctrls->ax_options); */ changed |= set_bool (settings, "enable", desc->ctrls->enabled_ctrls & XkbAccessXKeysMask); changed |= set_bool (settings, "feature-state-change-beep", desc->ctrls->ax_options & (XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask)); changed |= set_bool (settings, "timeout-enable", desc->ctrls->enabled_ctrls & XkbAccessXTimeoutMask); changed |= set_int (settings, "disable-timeout", desc->ctrls->ax_timeout); changed |= set_bool (settings, "bouncekeys-enable", desc->ctrls->enabled_ctrls & XkbBounceKeysMask); changed |= set_int (settings, "bouncekeys-delay", desc->ctrls->debounce_delay); changed |= set_bool (settings, "bouncekeys-beep-reject", desc->ctrls->ax_options & XkbAX_BKRejectFBMask); changed |= set_bool (settings, "mousekeys-enable", desc->ctrls->enabled_ctrls & XkbMouseKeysMask); changed |= set_int (settings, "mousekeys-max-speed", desc->ctrls->mk_max_speed * (1000 / desc->ctrls->mk_interval)); /* NOTE : mk_time_to_max is measured in events not time */ changed |= set_int (settings, "mousekeys-accel-time", desc->ctrls->mk_time_to_max * desc->ctrls->mk_interval); changed |= set_int (settings, "mousekeys-init-delay", desc->ctrls->mk_delay); slowkeys_changed = set_bool (settings, "slowkeys-enable", desc->ctrls->enabled_ctrls & XkbSlowKeysMask); changed |= set_bool (settings, "slowkeys-beep-press", desc->ctrls->ax_options & XkbAX_SKPressFBMask); changed |= set_bool (settings, "slowkeys-beep-accept", desc->ctrls->ax_options & XkbAX_SKAcceptFBMask); changed |= set_bool (settings, "slowkeys-beep-reject", desc->ctrls->ax_options & XkbAX_SKRejectFBMask); changed |= set_int (settings, "slowkeys-delay", desc->ctrls->slow_keys_delay); stickykeys_changed = set_bool (settings, "stickykeys-enable", desc->ctrls->enabled_ctrls & XkbStickyKeysMask); changed |= set_bool (settings, "stickykeys-two-key-off", desc->ctrls->ax_options & XkbAX_TwoKeysMask); changed |= set_bool (settings, "stickykeys-modifier-beep", desc->ctrls->ax_options & XkbAX_StickyKeysFBMask); if (!changed && stickykeys_changed ^ slowkeys_changed) { /* * sticky or slowkeys has changed, singly, without our intervention. * 99% chance this is due to a keyboard shortcut being used. * we need to detect via this hack until we get * XkbAXN_AXKWarning notifications working (probable XKB bug), * at which time we can directly intercept such shortcuts instead. * See cb_xkb_event_filter () below. */ /* sanity check: are keyboard shortcuts available? */ if (desc->ctrls->enabled_ctrls & XkbAccessXKeysMask) { if (slowkeys_changed) { ax_slowkeys_warning_post (manager, desc->ctrls->enabled_ctrls & XkbSlowKeysMask); } else { ax_stickykeys_warning_post (manager, desc->ctrls->enabled_ctrls & XkbStickyKeysMask); } } } XkbFreeKeyboard (desc, XkbAllComponentsMask, True); g_settings_apply (settings); g_object_unref (settings); } static GdkFilterReturn cb_xkb_event_filter (GdkXEvent *xevent, GdkEvent *ignored1, CsdA11yKeyboardManager *manager) { XEvent *xev = (XEvent *) xevent; XkbEvent *xkbEv = (XkbEvent *) xevent; /* 'event_type' is set to zero on notifying us of updates in * response to client requests (including our own) and non-zero * to notify us of key/mouse events causing changes (like * pressing shift 5 times to enable sticky keys). * * We only want to update GSettings when it's in response to an * explicit user input event, so require a non-zero event_type. */ if (xev->xany.type == (manager->priv->xkbEventBase + XkbEventCode) && xkbEv->any.xkb_type == XkbControlsNotify && xkbEv->ctrls.event_type != 0) { g_debug ("XKB state changed"); set_gsettings_from_server (manager); } else if (xev->xany.type == (manager->priv->xkbEventBase + XkbEventCode) && xkbEv->any.xkb_type == XkbAccessXNotify) { if (xkbEv->accessx.detail == XkbAXN_AXKWarning) { g_debug ("About to turn on an AccessX feature from the keyboard!"); /* * TODO: when XkbAXN_AXKWarnings start working, we need to * invoke ax_keys_warning_dialog_run here instead of in * set_gsettings_from_server(). */ } } return GDK_FILTER_CONTINUE; } static void keyboard_callback (GSettings *settings, const char *key, CsdA11yKeyboardManager *manager) { set_server_from_gsettings (manager); maybe_show_status_icon (manager); } static gboolean start_a11y_keyboard_idle_cb (CsdA11yKeyboardManager *manager) { guint event_mask; g_debug ("Starting a11y_keyboard manager"); cinnamon_settings_profile_start (NULL); if (!xkb_enabled (manager)) goto out; manager->priv->settings = g_settings_new (KEYBOARD_A11Y_SCHEMA); g_signal_connect (G_OBJECT (manager->priv->settings), "changed", G_CALLBACK (keyboard_callback), manager); set_devicepresence_handler (manager); event_mask = XkbControlsNotifyMask; event_mask |= XkbAccessXNotifyMask; /* make default when AXN_AXKWarning works */ /* be sure to init before starting to monitor the server */ set_server_from_gsettings (manager); XkbSelectEvents (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbUseCoreKbd, event_mask, event_mask); gdk_window_add_filter (NULL, (GdkFilterFunc) cb_xkb_event_filter, manager); maybe_show_status_icon (manager); out: cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } gboolean csd_a11y_keyboard_manager_start (CsdA11yKeyboardManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_a11y_keyboard_idle_cb, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_a11y_keyboard_manager_stop (CsdA11yKeyboardManager *manager) { CsdA11yKeyboardManagerPrivate *p = manager->priv; g_debug ("Stopping a11y_keyboard manager"); if (p->start_idle_id != 0) { g_source_remove (p->start_idle_id); p->start_idle_id = 0; } if (p->device_manager != NULL) { g_signal_handler_disconnect (p->device_manager, p->device_added_id); p->device_manager = NULL; } if (p->status_icon) { gtk_status_icon_set_visible (p->status_icon, FALSE); p->status_icon = NULL; } if (p->settings != NULL) { g_signal_handlers_disconnect_by_func (p->settings, keyboard_callback, manager); g_object_unref (p->settings); p->settings = NULL; } gdk_window_remove_filter (NULL, (GdkFilterFunc) cb_xkb_event_filter, manager); if (p->slowkeys_alert != NULL) { gtk_widget_destroy (p->slowkeys_alert); p->slowkeys_alert = NULL; } if (p->stickykeys_alert != NULL) { gtk_widget_destroy (p->stickykeys_alert); p->stickykeys_alert = NULL; } p->slowkeys_shortcut_val = FALSE; p->stickykeys_shortcut_val = FALSE; } static GObject * csd_a11y_keyboard_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdA11yKeyboardManager *a11y_keyboard_manager; a11y_keyboard_manager = CSD_A11Y_KEYBOARD_MANAGER (G_OBJECT_CLASS (csd_a11y_keyboard_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (a11y_keyboard_manager); } static void csd_a11y_keyboard_manager_class_init (CsdA11yKeyboardManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_a11y_keyboard_manager_constructor; object_class->finalize = csd_a11y_keyboard_manager_finalize; g_type_class_add_private (klass, sizeof (CsdA11yKeyboardManagerPrivate)); } static void on_preferences_dialog_response (GtkDialog *dialog, int response, CsdA11yKeyboardManager *manager) { g_signal_handlers_disconnect_by_func (dialog, on_preferences_dialog_response, manager); gtk_widget_destroy (GTK_WIDGET (dialog)); manager->priv->preferences_dialog = NULL; } static void on_status_icon_activate (GtkStatusIcon *status_icon, CsdA11yKeyboardManager *manager) { if (manager->priv->preferences_dialog == NULL) { manager->priv->preferences_dialog = csd_a11y_preferences_dialog_new (); g_signal_connect (manager->priv->preferences_dialog, "response", G_CALLBACK (on_preferences_dialog_response), manager); gtk_window_present (GTK_WINDOW (manager->priv->preferences_dialog)); } else { g_signal_handlers_disconnect_by_func (manager->priv->preferences_dialog, on_preferences_dialog_response, manager); gtk_widget_destroy (GTK_WIDGET (manager->priv->preferences_dialog)); manager->priv->preferences_dialog = NULL; } } static void on_status_icon_popup_menu (GtkStatusIcon *status_icon, guint button, guint activate_time, CsdA11yKeyboardManager *manager) { on_status_icon_activate (status_icon, manager); } static void csd_a11y_keyboard_manager_ensure_status_icon (CsdA11yKeyboardManager *manager) { cinnamon_settings_profile_start (NULL); if (!manager->priv->status_icon) { manager->priv->status_icon = gtk_status_icon_new_from_icon_name ("preferences-desktop-accessibility"); gtk_status_icon_set_name (manager->priv->status_icon, "a11y-keyboard"); g_signal_connect (manager->priv->status_icon, "activate", G_CALLBACK (on_status_icon_activate), manager); g_signal_connect (manager->priv->status_icon, "popup-menu", G_CALLBACK (on_status_icon_popup_menu), manager); } cinnamon_settings_profile_end (NULL); } static void csd_a11y_keyboard_manager_init (CsdA11yKeyboardManager *manager) { manager->priv = CSD_A11Y_KEYBOARD_MANAGER_GET_PRIVATE (manager); } static void csd_a11y_keyboard_manager_finalize (GObject *object) { CsdA11yKeyboardManager *a11y_keyboard_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_A11Y_KEYBOARD_MANAGER (object)); a11y_keyboard_manager = CSD_A11Y_KEYBOARD_MANAGER (object); g_return_if_fail (a11y_keyboard_manager->priv != NULL); if (a11y_keyboard_manager->priv->start_idle_id != 0) { g_source_remove (a11y_keyboard_manager->priv->start_idle_id); a11y_keyboard_manager->priv->start_idle_id = 0; } G_OBJECT_CLASS (csd_a11y_keyboard_manager_parent_class)->finalize (object); } CsdA11yKeyboardManager * csd_a11y_keyboard_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_A11Y_KEYBOARD_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_A11Y_KEYBOARD_MANAGER (manager_object); } cinnamon-settings-daemon-5.2.0/plugins/a11y-keyboard/csd-a11y-preferences-dialog.h0000664000175000017500000000441614144454032026632 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CSD_A11Y_PREFERENCES_DIALOG_H #define __CSD_A11Y_PREFERENCES_DIALOG_H #include #include G_BEGIN_DECLS #define CSD_TYPE_A11Y_PREFERENCES_DIALOG (csd_a11y_preferences_dialog_get_type ()) #define CSD_A11Y_PREFERENCES_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_A11Y_PREFERENCES_DIALOG, CsdA11yPreferencesDialog)) #define CSD_A11Y_PREFERENCES_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_A11Y_PREFERENCES_DIALOG, CsdA11yPreferencesDialogClass)) #define CSD_IS_A11Y_PREFERENCES_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_A11Y_PREFERENCES_DIALOG)) #define CSD_IS_A11Y_PREFERENCES_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_A11Y_PREFERENCES_DIALOG)) #define CSD_A11Y_PREFERENCES_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_A11Y_PREFERENCES_DIALOG, CsdA11yPreferencesDialogClass)) typedef struct CsdA11yPreferencesDialogPrivate CsdA11yPreferencesDialogPrivate; typedef struct { GtkDialog parent; CsdA11yPreferencesDialogPrivate *priv; } CsdA11yPreferencesDialog; typedef struct { GtkDialogClass parent_class; } CsdA11yPreferencesDialogClass; GType csd_a11y_preferences_dialog_get_type (void); GtkWidget * csd_a11y_preferences_dialog_new (void); G_END_DECLS #endif /* __CSD_A11Y_PREFERENCES_DIALOG_H */ ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootcinnamon-settings-daemon-5.2.0/plugins/a11y-keyboard/cinnamon-settings-daemon-a11y-keyboard.desktop.incinnamon-settings-daemon-5.2.0/plugins/a11y-keyboard/cinnamon-settings-daemon-a11y-keyboard.desktop.0000664000175000017500000000035214144454032032317 0ustar fabiofabio[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - a11y-keyboard Exec=csd-a11y-keyboard OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-5.2.0/plugins/a11y-keyboard/csd-a11y-preferences-dialog.c0000664000175000017500000004215414144454032026626 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "csd-a11y-preferences-dialog.h" #define SM_DBUS_NAME "org.gnome.SessionManager" #define SM_DBUS_PATH "/org/gnome/SessionManager" #define SM_DBUS_INTERFACE "org.gnome.SessionManager" #define CSD_A11Y_PREFERENCES_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_A11Y_PREFERENCES_DIALOG, CsdA11yPreferencesDialogPrivate)) #define GTKBUILDER_UI_FILE "csd-a11y-preferences-dialog.ui" #define INTERFACE_SCHEMA "org.cinnamon.desktop.interface" #define KEY_TEXT_SCALING_FACTOR "text-scaling-factor" #define KEYBOARD_A11Y_SCHEMA "org.cinnamon.desktop.a11y.keyboard" #define KEY_STICKY_KEYS_ENABLED "stickykeys-enable" #define KEY_BOUNCE_KEYS_ENABLED "bouncekeys-enable" #define KEY_SLOW_KEYS_ENABLED "slowkeys-enable" #define KEY_AT_SCHEMA "org.cinnamon.desktop.a11y.applications" #define KEY_AT_SCREEN_KEYBOARD_ENABLED "screen-keyboard-enabled" #define KEY_AT_SCREEN_MAGNIFIER_ENABLED "screen-magnifier-enabled" #define KEY_AT_SCREEN_READER_ENABLED "screen-reader-enabled" #define DPI_FACTOR_LARGE 1.25 #define DPI_FACTOR_LARGER 1.5 #define DPI_FACTOR_LARGEST 2.0 #define KEY_GTK_THEME "gtk-theme" #define KEY_ICON_THEME "icon-theme" #define KEY_METACITY_THEME "theme" #define HIGH_CONTRAST_THEME "HighContrast" struct CsdA11yPreferencesDialogPrivate { GtkWidget *large_print_checkbutton; GtkWidget *high_contrast_checkbutton; GSettings *a11y_settings; GSettings *interface_settings; GSettings *apps_settings; }; enum { PROP_0, }; static void csd_a11y_preferences_dialog_finalize (GObject *object); G_DEFINE_TYPE (CsdA11yPreferencesDialog, csd_a11y_preferences_dialog, GTK_TYPE_DIALOG) static GObject * csd_a11y_preferences_dialog_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdA11yPreferencesDialog *a11y_preferences_dialog; a11y_preferences_dialog = CSD_A11Y_PREFERENCES_DIALOG (G_OBJECT_CLASS (csd_a11y_preferences_dialog_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (a11y_preferences_dialog); } static void csd_a11y_preferences_dialog_class_init (CsdA11yPreferencesDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_a11y_preferences_dialog_constructor; object_class->finalize = csd_a11y_preferences_dialog_finalize; g_type_class_add_private (klass, sizeof (CsdA11yPreferencesDialogPrivate)); } static void on_response (CsdA11yPreferencesDialog *dialog, gint response_id) { switch (response_id) { default: break; } } static gboolean config_get_large_print (CsdA11yPreferencesDialog *dialog, gboolean *is_writable) { gboolean ret; gdouble factor; factor = g_settings_get_double (dialog->priv->interface_settings, KEY_TEXT_SCALING_FACTOR); ret = (factor > 1.0); *is_writable = g_settings_is_writable (dialog->priv->interface_settings, KEY_TEXT_SCALING_FACTOR); return ret; } static void config_set_large_print (CsdA11yPreferencesDialog *dialog, gboolean enabled) { if (enabled) g_settings_set_double (dialog->priv->interface_settings, KEY_TEXT_SCALING_FACTOR, DPI_FACTOR_LARGER); else g_settings_reset (dialog->priv->interface_settings, KEY_TEXT_SCALING_FACTOR); } static gboolean config_get_high_contrast (CsdA11yPreferencesDialog *dialog) { gboolean ret; char *gtk_theme; ret = FALSE; gtk_theme = g_settings_get_string (dialog->priv->interface_settings, KEY_GTK_THEME); if (gtk_theme != NULL && g_str_equal (gtk_theme, HIGH_CONTRAST_THEME)) { ret = TRUE; } g_free (gtk_theme); return ret; } static void config_set_high_contrast (gboolean enabled) { GSettings *settings; GSettings *wm_settings; settings = g_settings_new ("org.cinnamon.desktop.interface"); wm_settings = g_settings_new ("org.cinnamon.desktop.wm.preferences"); if (enabled) { g_settings_set_string (settings, KEY_GTK_THEME, HIGH_CONTRAST_THEME); g_settings_set_string (settings, KEY_ICON_THEME, HIGH_CONTRAST_THEME); /* there isn't a high contrast metacity theme afaik */ } else { g_settings_reset (settings, KEY_GTK_THEME); g_settings_reset (settings, KEY_ICON_THEME); g_settings_reset (wm_settings, KEY_METACITY_THEME); } g_object_unref (settings); g_object_unref (wm_settings); } static gboolean config_have_at_gsettings_condition (const char *condition) { GDBusProxy *sm_proxy; GDBusConnection *connection; GError *error; GVariant *res; gboolean is_handled; error = NULL; connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); if (connection == NULL) { g_warning ("Unable to connect to session bus: %s", error->message); g_error_free (error); return FALSE; } sm_proxy = g_dbus_proxy_new_sync (connection, 0, NULL, SM_DBUS_NAME, SM_DBUS_PATH, SM_DBUS_INTERFACE, NULL, &error); if (sm_proxy == NULL) { g_warning ("Unable to get proxy for %s: %s", SM_DBUS_NAME, error->message); g_error_free (error); return FALSE; } is_handled = FALSE; res = g_dbus_proxy_call_sync (sm_proxy, "IsAutostartConditionHandled", g_variant_new ("(s)", condition), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (! res) { g_warning ("Unable to call IsAutostartConditionHandled (%s): %s", condition, error->message); } if (g_variant_is_of_type (res, G_VARIANT_TYPE_BOOLEAN)) { is_handled = g_variant_get_boolean (res); } g_object_unref (sm_proxy); g_variant_unref (res); return is_handled; } static void on_high_contrast_checkbutton_toggled (GtkToggleButton *button, CsdA11yPreferencesDialog *dialog) { config_set_high_contrast (gtk_toggle_button_get_active (button)); } static void on_large_print_checkbutton_toggled (GtkToggleButton *button, CsdA11yPreferencesDialog *dialog) { config_set_large_print (dialog, gtk_toggle_button_get_active (button)); } static void ui_set_high_contrast (CsdA11yPreferencesDialog *dialog, gboolean enabled) { gboolean active; active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->high_contrast_checkbutton)); if (active != enabled) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->high_contrast_checkbutton), enabled); } } static void ui_set_large_print (CsdA11yPreferencesDialog *dialog, gboolean enabled) { gboolean active; active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->large_print_checkbutton)); if (active != enabled) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->large_print_checkbutton), enabled); } } static void setup_dialog (CsdA11yPreferencesDialog *dialog, GtkBuilder *builder) { GtkWidget *widget; gboolean enabled; gboolean is_writable; GSettings *settings; dialog->priv->a11y_settings = g_settings_new (KEYBOARD_A11Y_SCHEMA); settings = dialog->priv->a11y_settings; dialog->priv->interface_settings = g_settings_new (INTERFACE_SCHEMA); dialog->priv->apps_settings = g_settings_new (KEY_AT_SCHEMA); /* Sticky keys */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "sticky_keys_checkbutton")); g_settings_bind (settings, KEY_STICKY_KEYS_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (settings, KEY_STICKY_KEYS_ENABLED, G_OBJECT (widget), "sensitive", TRUE); /* Bounce keys */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "bounce_keys_checkbutton")); g_settings_bind (settings, KEY_BOUNCE_KEYS_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (settings, KEY_BOUNCE_KEYS_ENABLED, G_OBJECT (widget), "sensitive", TRUE); /* Slow keys */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "slow_keys_checkbutton")); g_settings_bind (settings, KEY_SLOW_KEYS_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (settings, KEY_SLOW_KEYS_ENABLED, G_OBJECT (widget), "sensitive", TRUE); /* High contrast */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "high_contrast_checkbutton")); g_settings_bind_writable (dialog->priv->interface_settings, KEY_GTK_THEME, G_OBJECT (widget), "sensitive", TRUE); dialog->priv->high_contrast_checkbutton = widget; g_signal_connect (widget, "toggled", G_CALLBACK (on_high_contrast_checkbutton_toggled), dialog); enabled = config_get_high_contrast (dialog); ui_set_high_contrast (dialog, enabled); /* On-screen keyboard */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "at_screen_keyboard_checkbutton")); g_settings_bind (dialog->priv->apps_settings, KEY_AT_SCREEN_KEYBOARD_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (dialog->priv->apps_settings, KEY_AT_SCREEN_KEYBOARD_ENABLED, G_OBJECT (widget), "sensitive", TRUE); gtk_widget_set_no_show_all (widget, TRUE); if (config_have_at_gsettings_condition ("GSettings " KEYBOARD_A11Y_SCHEMA " " KEY_AT_SCREEN_KEYBOARD_ENABLED)) { gtk_widget_show_all (widget); } else { gtk_widget_hide (widget); } /* Screen reader */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "at_screen_reader_checkbutton")); g_settings_bind (dialog->priv->apps_settings, KEY_AT_SCREEN_READER_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (dialog->priv->apps_settings, KEY_AT_SCREEN_READER_ENABLED, G_OBJECT (widget), "sensitive", TRUE); gtk_widget_set_no_show_all (widget, TRUE); if (config_have_at_gsettings_condition ("GSettings " KEYBOARD_A11Y_SCHEMA " " KEY_AT_SCREEN_READER_ENABLED)) { gtk_widget_show_all (widget); } else { gtk_widget_hide (widget); } /* Screen magnifier */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "at_screen_magnifier_checkbutton")); g_settings_bind (dialog->priv->apps_settings, KEY_AT_SCREEN_MAGNIFIER_ENABLED, G_OBJECT (widget), "active", G_SETTINGS_BIND_DEFAULT); g_settings_bind_writable (dialog->priv->apps_settings, KEY_AT_SCREEN_MAGNIFIER_ENABLED, G_OBJECT (widget), "sensitive", TRUE); gtk_widget_set_no_show_all (widget, TRUE); if (config_have_at_gsettings_condition ("GSettings " KEYBOARD_A11Y_SCHEMA " " KEY_AT_SCREEN_MAGNIFIER_ENABLED)) { gtk_widget_show_all (widget); } else { gtk_widget_hide (widget); } /* Large print */ widget = GTK_WIDGET (gtk_builder_get_object (builder, "large_print_checkbutton")); dialog->priv->large_print_checkbutton = widget; g_signal_connect (widget, "toggled", G_CALLBACK (on_large_print_checkbutton_toggled), dialog); enabled = config_get_large_print (dialog, &is_writable); ui_set_large_print (dialog, enabled); if (! is_writable) { gtk_widget_set_sensitive (widget, FALSE); } } static void csd_a11y_preferences_dialog_init (CsdA11yPreferencesDialog *dialog) { static const gchar *ui_file_path = GTKBUILDERDIR "/" GTKBUILDER_UI_FILE; gchar *objects[] = {"main_box", NULL}; GError *error = NULL; GtkBuilder *builder; dialog->priv = CSD_A11Y_PREFERENCES_DIALOG_GET_PRIVATE (dialog); builder = gtk_builder_new (); gtk_builder_set_translation_domain (builder, PACKAGE); if (gtk_builder_add_objects_from_file (builder, ui_file_path, objects, &error) == 0) { g_warning ("Could not load A11Y-UI: %s", error->message); g_error_free (error); } else { GtkWidget *widget; widget = GTK_WIDGET (gtk_builder_get_object (builder, "main_box")); gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), widget); gtk_container_set_border_width (GTK_CONTAINER (widget), 12); setup_dialog (dialog, builder); } g_object_unref (builder); gtk_container_set_border_width (GTK_CONTAINER (dialog), 12); gtk_window_set_title (GTK_WINDOW (dialog), _("Universal Access Preferences")); gtk_window_set_icon_name (GTK_WINDOW (dialog), "preferences-desktop-accessibility"); g_object_set (dialog, "resizable", FALSE, NULL); gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); g_signal_connect (dialog, "response", G_CALLBACK (on_response), dialog); gtk_widget_show_all (GTK_WIDGET (dialog)); } static void csd_a11y_preferences_dialog_finalize (GObject *object) { CsdA11yPreferencesDialog *dialog; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_A11Y_PREFERENCES_DIALOG (object)); dialog = CSD_A11Y_PREFERENCES_DIALOG (object); g_return_if_fail (dialog->priv != NULL); g_object_unref (dialog->priv->a11y_settings); g_object_unref (dialog->priv->interface_settings); g_object_unref (dialog->priv->apps_settings); G_OBJECT_CLASS (csd_a11y_preferences_dialog_parent_class)->finalize (object); } GtkWidget * csd_a11y_preferences_dialog_new (void) { GObject *object; object = g_object_new (CSD_TYPE_A11Y_PREFERENCES_DIALOG, NULL); return GTK_WIDGET (object); } cinnamon-settings-daemon-5.2.0/plugins/meson.build0000664000175000017500000000136614144454032021175 0ustar fabiofabiodesktop_conf = configuration_data() desktop_conf.set('libexecdir', join_paths(prefix, libexecdir)) ln_script = join_paths(meson.source_root(), 'install-scripts', 'meson_mk_symlink.py') # subdir('dummy') subdir('common') subdir('a11y-keyboard') subdir('a11y-settings') subdir('automount') subdir('background') subdir('clipboard') subdir('cursor') subdir('datetime') subdir('housekeeping') subdir('keyboard') subdir('media-keys') subdir('mouse') subdir('orientation') subdir('power') subdir('screensaver-proxy') subdir('sound') subdir('xrandr') subdir('xsettings') if colord.found() subdir('color') endif if cups.found() subdir('print-notifications') endif if nss.found() subdir('smartcard') endif if wacom.found() subdir('wacom') endif cinnamon-settings-daemon-5.2.0/plugins/datetime/0000775000175000017500000000000014144454032020621 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/datetime/csd-datetime-mechanism-fedora.h0000664000175000017500000000257214144454032026543 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include #include gboolean _get_using_ntp_fedora (DBusGMethodInvocation *context); gboolean _set_using_ntp_fedora (DBusGMethodInvocation *context, gboolean using_ntp); gboolean _update_etc_sysconfig_clock_fedora (DBusGMethodInvocation *context, const char *key, const char *value); cinnamon-settings-daemon-5.2.0/plugins/datetime/csd-datetime-mechanism.h0000664000175000017500000001321314144454032025277 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef CSD_DATETIME_MECHANISM_H #define CSD_DATETIME_MECHANISM_H #include #include G_BEGIN_DECLS #define CSD_DATETIME_TYPE_MECHANISM (csd_datetime_mechanism_get_type ()) #define CSD_DATETIME_MECHANISM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_DATETIME_TYPE_MECHANISM, CsdDatetimeMechanism)) #define CSD_DATETIME_MECHANISM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_DATETIME_TYPE_MECHANISM, CsdDatetimeMechanismClass)) #define CSD_DATETIME_IS_MECHANISM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_DATETIME_TYPE_MECHANISM)) #define CSD_DATETIME_IS_MECHANISM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_DATETIME_TYPE_MECHANISM)) #define CSD_DATETIME_MECHANISM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_DATETIME_TYPE_MECHANISM, CsdDatetimeMechanismClass)) typedef struct CsdDatetimeMechanismPrivate CsdDatetimeMechanismPrivate; typedef struct { GObject parent; CsdDatetimeMechanismPrivate *priv; } CsdDatetimeMechanism; typedef struct { GObjectClass parent_class; } CsdDatetimeMechanismClass; typedef enum { CSD_DATETIME_MECHANISM_ERROR_GENERAL, CSD_DATETIME_MECHANISM_ERROR_NOT_PRIVILEGED, CSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE, CSD_DATETIME_MECHANISM_NUM_ERRORS } CsdDatetimeMechanismError; #define CSD_DATETIME_MECHANISM_ERROR csd_datetime_mechanism_error_quark () GType csd_datetime_mechanism_error_get_type (void); #define CSD_DATETIME_MECHANISM_TYPE_ERROR (csd_datetime_mechanism_error_get_type ()) GQuark csd_datetime_mechanism_error_quark (void); GType csd_datetime_mechanism_get_type (void); CsdDatetimeMechanism *csd_datetime_mechanism_new (void); /* exported methods */ gboolean csd_datetime_mechanism_get_timezone (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_set_timezone (CsdDatetimeMechanism *mechanism, const char *zone_file, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_can_set_timezone (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_set_time (CsdDatetimeMechanism *mechanism, gint64 seconds_since_epoch, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_set_date (CsdDatetimeMechanism *mechanism, guint day, guint month, guint year, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_can_set_time (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_adjust_time (CsdDatetimeMechanism *mechanism, gint64 seconds_to_add, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_get_hardware_clock_using_utc (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_set_hardware_clock_using_utc (CsdDatetimeMechanism *mechanism, gboolean using_utc, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_get_using_ntp (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_set_using_ntp (CsdDatetimeMechanism *mechanism, gboolean using_ntp, DBusGMethodInvocation *context); gboolean csd_datetime_mechanism_can_set_using_ntp (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context); G_END_DECLS #endif /* CSD_DATETIME_MECHANISM_H */ cinnamon-settings-daemon-5.2.0/plugins/datetime/meson.build0000664000175000017500000000432614144454032022770 0ustar fabiofabioplugin_name = 'datetime' datetime_dbus = custom_target( 'datetime-dbus', input: 'csd-datetime-mechanism.xml', output: 'csd-datetime-mechanism-glue.h', command: [ dbus_binding_tool, '--prefix=csd_datetime_mechanism', '--mode=glib-server', '--output=@OUTPUT@', '@INPUT@', ], ) datetime_common_sources = [ 'system-timezone.c', 'system-timezone.h', ] datetime_sources = [ 'csd-datetime-mechanism.c', 'csd-datetime-mechanism.h', 'csd-datetime-mechanism-fedora.c', 'csd-datetime-mechanism-fedora.h', 'csd-datetime-mechanism-debian.c', 'csd-datetime-mechanism-debian.h', 'csd-datetime-mechanism-suse.c', 'csd-datetime-mechanism-suse.h', 'csd-datetime-mechanism-main.c', datetime_dbus, datetime_common_sources, ] test_timezone_sources = [ 'test-system-timezone.c', datetime_common_sources, ] datetime_deps = [ common_dep, csd_dep, dbus, dbus_glib, libnotify, polkit, xfixes, ] if polkit.found() executable( 'csd-datetime-mechanism', datetime_sources, include_directories: [include_dirs, common_inc], dependencies: datetime_deps, c_args: [ '-DPLUGIN_NAME="@0@"'.format(plugin_name), ], install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-datetime-mechanism') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-datetime-mechanism') endif executable( 'test-datetime', test_timezone_sources, dependencies: datetime_deps, install: false, ) endif datetime_conf = configuration_data() datetime_conf.set('LIBEXECDIR', join_paths(prefix, libexecdir)) configure_file( input: 'org.cinnamon.SettingsDaemon.DateTimeMechanism.service.in', output: 'org.cinnamon.SettingsDaemon.DateTimeMechanism.service', configuration: datetime_conf, install_dir: dbusservicedir, ) install_data( 'org.cinnamon.settingsdaemon.datetimemechanism.policy', install_dir: polkitdir, ) install_data( 'org.cinnamon.SettingsDaemon.DateTimeMechanism.conf', install_dir: dbussystemdir, ) cinnamon-settings-daemon-5.2.0/plugins/datetime/csd-datetime-mechanism-fedora.c0000664000175000017500000001711314144454032026533 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "csd-datetime-mechanism-fedora.h" #include "csd-datetime-mechanism.h" /* Return the name of the installed NTP client, prefer chrony if both chrony * and ntp are installed */ static const char * get_ntp_client () { if (g_file_test ("/etc/chrony.conf", G_FILE_TEST_EXISTS)) return "chronyd"; else if (g_file_test ("/etc/ntp.conf", G_FILE_TEST_EXISTS)) return "ntpd"; return NULL; } gboolean _get_using_ntp_fedora (DBusGMethodInvocation *context) { int exit_status; GError *error = NULL; gboolean can_use_ntp; gboolean is_using_ntp; const char *ntp_client; char *cmd; ntp_client = get_ntp_client (); if (ntp_client) { can_use_ntp = TRUE; cmd = g_strconcat ("/sbin/service ", ntp_client, " status", NULL); if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /sbin/service: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); if (exit_status == 0) is_using_ntp = TRUE; else is_using_ntp = FALSE; } else { can_use_ntp = FALSE; is_using_ntp = FALSE; } dbus_g_method_return (context, can_use_ntp, is_using_ntp); return TRUE; } gboolean _set_using_ntp_fedora (DBusGMethodInvocation *context, gboolean using_ntp) { GError *error; int exit_status; const char *ntp_client; char *cmd; error = NULL; ntp_client = get_ntp_client (); /* We omit --level 2345 so that systemd doesn't try to use the * SysV init scripts */ cmd = g_strconcat ("/sbin/chkconfig ", ntp_client, " ", using_ntp ? "on" : "off", NULL); if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); cmd = g_strconcat ("/sbin/service ", ntp_client, " ", using_ntp ? "restart" : "stop", NULL);; if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); dbus_g_method_return (context); return TRUE; } gboolean _update_etc_sysconfig_clock_fedora (DBusGMethodInvocation *context, const char *key, const char *value) { char **lines; int n; gboolean replaced; char *data; gsize len; GError *error; /* On Red Hat / Fedora, the /etc/sysconfig/clock file needs to be kept in sync */ if (!g_file_test ("/etc/sysconfig/clock", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error reading /etc/sysconfig/clock file: %s", "No such file"); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } error = NULL; if (!g_file_get_contents ("/etc/sysconfig/clock", &data, &len, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error reading /etc/sysconfig/clock file: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } replaced = FALSE; lines = g_strsplit (data, "\n", 0); g_free (data); for (n = 0; lines[n] != NULL; n++) { if (g_str_has_prefix (lines[n], key)) { g_free (lines[n]); lines[n] = g_strdup_printf ("%s%s", key, value); replaced = TRUE; } } if (replaced) { GString *str; str = g_string_new (NULL); for (n = 0; lines[n] != NULL; n++) { g_string_append (str, lines[n]); if (lines[n + 1] != NULL) g_string_append_c (str, '\n'); } data = g_string_free (str, FALSE); len = strlen (data); if (!g_file_set_contents ("/etc/sysconfig/clock", data, len, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error updating /etc/sysconfig/clock: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (data); return FALSE; } g_free (data); } g_strfreev (lines); return TRUE; } cinnamon-settings-daemon-5.2.0/plugins/datetime/csd-datetime-mechanism-debian.c0000664000175000017500000001631714144454032026522 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "csd-datetime-mechanism-debian.h" #include "csd-datetime-mechanism.h" static void _get_using_ntpdate (gboolean *can_use, gboolean *is_using, GError ** error) { if (!g_file_test ("/usr/sbin/ntpdate-debian", G_FILE_TEST_EXISTS)) return; *can_use = TRUE; if (g_file_test ("/etc/network/if-up.d/ntpdate", G_FILE_TEST_EXISTS)) *is_using = TRUE; } static void _get_using_ntpd (gboolean *can_use, gboolean *is_using, GError ** error) { int exit_status; GError *tmp_error = NULL; if (!g_file_test ("/usr/sbin/ntpd", G_FILE_TEST_EXISTS)) return; *can_use = TRUE; if (!g_spawn_command_line_sync ("/usr/sbin/service ntp status", NULL, NULL, &exit_status, &tmp_error)) { if (error != NULL && *error == NULL) { *error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /usr/sbin/service: %s", tmp_error->message); } g_error_free (tmp_error); return; } if (exit_status == 0) *is_using = TRUE; } gboolean _get_using_ntp_debian (DBusGMethodInvocation *context) { gboolean can_use_ntp = FALSE; gboolean is_using_ntp = FALSE; GError *error = NULL; /* In Debian, ntpdate is used whenever the network comes up. So if either ntpdate or ntpd is installed and available, can_use is true. If either is active, is_using is true. */ _get_using_ntpdate (&can_use_ntp, &is_using_ntp, &error); _get_using_ntpd (&can_use_ntp, &is_using_ntp, &error); if (error == NULL) { dbus_g_method_return (context, can_use_ntp, is_using_ntp); return TRUE; } else { dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } } static void _set_using_ntpdate (gboolean using_ntp, GError **error) { const gchar *cmd = NULL; GError *tmp_error = NULL; /* Debian uses an if-up.d script to sync network time when an interface comes up. This is a separate mechanism from ntpd altogether. */ #define NTPDATE_ENABLED "/etc/network/if-up.d/ntpdate" #define NTPDATE_DISABLED "/etc/network/if-up.d/ntpdate.disabled" if (using_ntp && g_file_test (NTPDATE_DISABLED, G_FILE_TEST_EXISTS)) cmd = "/bin/mv -f "NTPDATE_DISABLED" "NTPDATE_ENABLED; else if (!using_ntp && g_file_test (NTPDATE_ENABLED, G_FILE_TEST_EXISTS)) cmd = "/bin/mv -f "NTPDATE_ENABLED" "NTPDATE_DISABLED; else return; if (!g_spawn_command_line_sync (cmd, NULL, NULL, NULL, &tmp_error)) { if (error != NULL && *error == NULL) { *error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /bin/mv: %s", tmp_error->message); } g_error_free (tmp_error); return; } /* Kick start ntpdate to sync time immediately */ if (using_ntp && !g_spawn_command_line_sync ("/etc/network/if-up.d/ntpdate", NULL, NULL, NULL, &tmp_error)) { if (error != NULL && *error == NULL) { *error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /etc/network/if-up.d/ntpdate: %s", tmp_error->message); } g_error_free (tmp_error); return; } } static void _set_using_ntpd (gboolean using_ntp, GError **error) { GError *tmp_error = NULL; int exit_status; char *cmd; if (!g_file_test ("/usr/sbin/ntpd", G_FILE_TEST_EXISTS)) return; cmd = g_strconcat ("/usr/sbin/update-rc.d ntp ", using_ntp ? "enable" : "disable", NULL); if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &tmp_error)) { if (error != NULL && *error == NULL) { *error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, tmp_error->message); } g_error_free (tmp_error); g_free (cmd); return; } g_free (cmd); cmd = g_strconcat ("/usr/sbin/service ntp ", using_ntp ? "restart" : "stop", NULL);; if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &tmp_error)) { if (error != NULL && *error == NULL) { *error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, tmp_error->message); } g_error_free (tmp_error); g_free (cmd); return; } g_free (cmd); } gboolean _set_using_ntp_debian (DBusGMethodInvocation *context, gboolean using_ntp) { GError *error = NULL; /* In Debian, ntpdate and ntpd may be installed separately, so don't assume both are valid. */ _set_using_ntpdate (using_ntp, &error); _set_using_ntpd (using_ntp, &error); if (error == NULL) { dbus_g_method_return (context); return TRUE; } else { dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootcinnamon-settings-daemon-5.2.0/plugins/datetime/org.cinnamon.SettingsDaemon.DateTimeMechanism.service.incinnamon-settings-daemon-5.2.0/plugins/datetime/org.cinnamon.SettingsDaemon.DateTimeMechanism.servic0000664000175000017500000000016614144454032032674 0ustar fabiofabio[D-BUS Service] Name=org.cinnamon.SettingsDaemon.DateTimeMechanism Exec=@LIBEXECDIR@/csd-datetime-mechanism User=root cinnamon-settings-daemon-5.2.0/plugins/datetime/csd-datetime-mechanism.c0000664000175000017500000006445414144454032025307 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "system-timezone.h" #include "csd-datetime-mechanism.h" #include "csd-datetime-mechanism-glue.h" /* NTP helper functions for various distributions */ #include "csd-datetime-mechanism-fedora.h" #include "csd-datetime-mechanism-debian.h" #include "csd-datetime-mechanism-suse.h" static gboolean do_exit (gpointer user_data) { g_debug ("Exiting due to inactivity"); exit (1); return FALSE; } static void reset_killtimer (void) { static guint timer_id = 0; if (timer_id > 0) { g_source_remove (timer_id); timer_id = 0; } g_debug ("Setting killtimer to 30 seconds..."); timer_id = g_timeout_add_seconds (30, do_exit, NULL); } struct CsdDatetimeMechanismPrivate { DBusGConnection *system_bus_connection; DBusGProxy *system_bus_proxy; PolkitAuthority *auth; }; static void csd_datetime_mechanism_finalize (GObject *object); G_DEFINE_TYPE (CsdDatetimeMechanism, csd_datetime_mechanism, G_TYPE_OBJECT) #define CSD_DATETIME_MECHANISM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_DATETIME_TYPE_MECHANISM, CsdDatetimeMechanismPrivate)) GQuark csd_datetime_mechanism_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("csd_datetime_mechanism_error"); } return ret; } #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } GType csd_datetime_mechanism_error_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { ENUM_ENTRY (CSD_DATETIME_MECHANISM_ERROR_GENERAL, "GeneralError"), ENUM_ENTRY (CSD_DATETIME_MECHANISM_ERROR_NOT_PRIVILEGED, "NotPrivileged"), ENUM_ENTRY (CSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE, "InvalidTimezoneFile"), { 0, 0, 0 } }; g_assert (CSD_DATETIME_MECHANISM_NUM_ERRORS == G_N_ELEMENTS (values) - 1); etype = g_enum_register_static ("CsdDatetimeMechanismError", values); } return etype; } static GObject * csd_datetime_mechanism_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdDatetimeMechanism *mechanism; mechanism = CSD_DATETIME_MECHANISM (G_OBJECT_CLASS (csd_datetime_mechanism_parent_class)->constructor ( type, n_construct_properties, construct_properties)); return G_OBJECT (mechanism); } static void csd_datetime_mechanism_class_init (CsdDatetimeMechanismClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_datetime_mechanism_constructor; object_class->finalize = csd_datetime_mechanism_finalize; g_type_class_add_private (klass, sizeof (CsdDatetimeMechanismPrivate)); dbus_g_object_type_install_info (CSD_DATETIME_TYPE_MECHANISM, &dbus_glib_csd_datetime_mechanism_object_info); dbus_g_error_domain_register (CSD_DATETIME_MECHANISM_ERROR, NULL, CSD_DATETIME_MECHANISM_TYPE_ERROR); } static void csd_datetime_mechanism_init (CsdDatetimeMechanism *mechanism) { mechanism->priv = CSD_DATETIME_MECHANISM_GET_PRIVATE (mechanism); } static void csd_datetime_mechanism_finalize (GObject *object) { CsdDatetimeMechanism *mechanism; g_return_if_fail (object != NULL); g_return_if_fail (CSD_DATETIME_IS_MECHANISM (object)); mechanism = CSD_DATETIME_MECHANISM (object); g_return_if_fail (mechanism->priv != NULL); g_object_unref (mechanism->priv->system_bus_proxy); G_OBJECT_CLASS (csd_datetime_mechanism_parent_class)->finalize (object); } static gboolean register_mechanism (CsdDatetimeMechanism *mechanism) { GError *error = NULL; mechanism->priv->auth = polkit_authority_get_sync (NULL, &error); if (mechanism->priv->auth == NULL) { if (error != NULL) { g_critical ("error getting system bus: %s", error->message); g_error_free (error); } goto error; } mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (mechanism->priv->system_bus_connection == NULL) { if (error != NULL) { g_critical ("error getting system bus: %s", error->message); g_error_free (error); } goto error; } dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/", G_OBJECT (mechanism)); mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); reset_killtimer (); return TRUE; error: return FALSE; } CsdDatetimeMechanism * csd_datetime_mechanism_new (void) { GObject *object; gboolean res; object = g_object_new (CSD_DATETIME_TYPE_MECHANISM, NULL); res = register_mechanism (CSD_DATETIME_MECHANISM (object)); if (! res) { g_object_unref (object); return NULL; } return CSD_DATETIME_MECHANISM (object); } static gboolean _check_polkit_for_action (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { const char *action = "org.cinnamon.settingsdaemon.datetimemechanism.configure"; const char *sender; GError *error; PolkitSubject *subject; PolkitAuthorizationResult *result; error = NULL; /* Check that caller is privileged */ sender = dbus_g_method_get_sender (context); subject = polkit_system_bus_name_new (sender); result = polkit_authority_check_authorization_sync (mechanism->priv->auth, subject, action, NULL, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, NULL, &error); g_object_unref (subject); if (error) { dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } if (!polkit_authorization_result_get_is_authorized (result)) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_NOT_PRIVILEGED, "Not Authorized for action %s", action); dbus_g_method_return_error (context, error); g_error_free (error); g_object_unref (result); return FALSE; } g_object_unref (result); return TRUE; } static gboolean _sync_hwclock (DBusGMethodInvocation *context) { GError *error; error = NULL; if (g_file_test ("/sbin/hwclock", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE)) { int exit_status; if (!g_spawn_command_line_sync ("/sbin/hwclock --systohc", NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /sbin/hwclock: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } if (WEXITSTATUS (exit_status) != 0) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "/sbin/hwclock returned %d", exit_status); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } } return TRUE; } static gboolean _set_time (CsdDatetimeMechanism *mechanism, const struct timeval *tv, DBusGMethodInvocation *context) { GError *error; if (!_check_polkit_for_action (mechanism, context)) return FALSE; if (settimeofday (tv, NULL) != 0) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error calling settimeofday({%ld,%ld}): %s", (gint64) tv->tv_sec, (gint64) tv->tv_usec, strerror (errno)); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } if (!_sync_hwclock (context)) return FALSE; dbus_g_method_return (context); return TRUE; } static gboolean _set_date (CsdDatetimeMechanism *mechanism, guint day, guint month, guint year, DBusGMethodInvocation *context) { GDateTime *time; char *date_str, *time_str; char *date_cmd; int exit_status; GError *error; if (!_check_polkit_for_action (mechanism, context)) return FALSE; date_str = g_strdup_printf ("%02d/%02d/%d", month, day, year); error = NULL; time = g_date_time_new_now_local (); time_str = g_date_time_format (time, "%R:%S"); g_date_time_unref (time); date_cmd = g_strdup_printf ("/bin/date -s \"%s %s\" +\"%%D %%R:%%S\"", date_str, time_str); g_free (date_str); g_free (time_str); if (!g_spawn_command_line_sync (date_cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /bin/date: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (date_cmd); return FALSE; } g_free (date_cmd); if (WEXITSTATUS (exit_status) != 0) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "/bin/date returned %d", exit_status); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } if (!_sync_hwclock (context)) return FALSE; return TRUE; } /* exported methods */ gboolean csd_datetime_mechanism_set_time (CsdDatetimeMechanism *mechanism, gint64 seconds_since_epoch, DBusGMethodInvocation *context) { struct timeval tv; reset_killtimer (); g_debug ("SetTime(%" G_GINT64_FORMAT ") called", seconds_since_epoch); tv.tv_sec = (time_t) seconds_since_epoch; tv.tv_usec = 0; return _set_time (mechanism, &tv, context); } gboolean csd_datetime_mechanism_set_date (CsdDatetimeMechanism *mechanism, guint day, guint month, guint year, DBusGMethodInvocation *context) { reset_killtimer (); g_debug ("SetDate(%d, %d, %d) called", day, month, year); return _set_date (mechanism, day, month, year, context); } gboolean csd_datetime_mechanism_adjust_time (CsdDatetimeMechanism *mechanism, gint64 seconds_to_add, DBusGMethodInvocation *context) { struct timeval tv; reset_killtimer (); g_debug ("AdjustTime(%" G_GINT64_FORMAT " ) called", seconds_to_add); if (gettimeofday (&tv, NULL) != 0) { GError *error; error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error calling gettimeofday(): %s", strerror (errno)); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } tv.tv_sec += (time_t) seconds_to_add; return _set_time (mechanism, &tv, context); } static gboolean csd_datetime_check_tz_name (const char *tz, GError **error) { GFile *file; char *tz_path, *actual_path; gboolean retval; retval = TRUE; tz_path = g_build_filename (SYSTEM_ZONEINFODIR, tz, NULL); /* Get the actual resolved path */ file = g_file_new_for_path (tz_path); actual_path = g_file_get_path (file); g_object_unref (file); /* The tz name passed had relative paths in it */ if (g_strcmp0 (tz_path, actual_path) != 0) { g_set_error (error, CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE, "Timezone file '%s' was invalid.", tz); retval = FALSE; } g_free (tz_path); g_free (actual_path); return retval; } gboolean csd_datetime_mechanism_set_timezone (CsdDatetimeMechanism *mechanism, const char *tz, DBusGMethodInvocation *context) { GError *error; reset_killtimer (); g_debug ("SetTimezone('%s') called", tz); if (!_check_polkit_for_action (mechanism, context)) return FALSE; error = NULL; if (!csd_datetime_check_tz_name (tz, &error)) return FALSE; if (!system_timezone_set (tz, &error)) { GError *error2; int code; if (error->code == SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE) code = CSD_DATETIME_MECHANISM_ERROR_INVALID_TIMEZONE_FILE; else code = CSD_DATETIME_MECHANISM_ERROR_GENERAL; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, code, "%s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } dbus_g_method_return (context); return TRUE; } gboolean csd_datetime_mechanism_get_timezone (CsdDatetimeMechanism *mechism, DBusGMethodInvocation *context) { gchar *timezone; reset_killtimer (); timezone = system_timezone_find (); dbus_g_method_return (context, timezone); return TRUE; } gboolean csd_datetime_mechanism_get_hardware_clock_using_utc (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { char **lines; char *data; gsize len; GError *error; gboolean is_utc; error = NULL; if (!g_file_get_contents ("/etc/adjtime", &data, &len, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error reading /etc/adjtime file: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } lines = g_strsplit (data, "\n", 0); g_free (data); if (g_strv_length (lines) < 3) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Cannot parse /etc/adjtime"); dbus_g_method_return_error (context, error); g_error_free (error); g_strfreev (lines); return FALSE; } if (strcmp (lines[2], "UTC") == 0) { is_utc = TRUE; } else if (strcmp (lines[2], "LOCAL") == 0) { is_utc = FALSE; } else { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Expected UTC or LOCAL at line 3 of /etc/adjtime; found '%s'", lines[2]); dbus_g_method_return_error (context, error); g_error_free (error); g_strfreev (lines); return FALSE; } g_strfreev (lines); dbus_g_method_return (context, is_utc); return TRUE; } gboolean csd_datetime_mechanism_set_hardware_clock_using_utc (CsdDatetimeMechanism *mechanism, gboolean using_utc, DBusGMethodInvocation *context) { GError *error; error = NULL; if (!_check_polkit_for_action (mechanism, context)) return FALSE; if (g_file_test ("/sbin/hwclock", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_EXECUTABLE)) { int exit_status; char *cmd; cmd = g_strdup_printf ("/sbin/hwclock %s --systohc", using_utc ? "--utc" : "--localtime"); if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /sbin/hwclock: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); if (WEXITSTATUS (exit_status) != 0) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "/sbin/hwclock returned %d", exit_status); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } if (g_file_test ("/etc/redhat-release", G_FILE_TEST_EXISTS)) { /* Fedora */ if (!_update_etc_sysconfig_clock_fedora (context, "UTC=", using_utc ? "true" : "false")) return FALSE; } else if (g_file_test ("/etc/SuSE-release", G_FILE_TEST_EXISTS)) { /* SUSE variant */ if (!_update_etc_sysconfig_clock_suse (context, "HWCLOCK=", using_utc ? "-u" : "--localtime")) return FALSE; } } dbus_g_method_return (context); return TRUE; } gboolean csd_datetime_mechanism_get_using_ntp (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { GError *error = NULL; gboolean ret; if (g_file_test ("/etc/redhat-release", G_FILE_TEST_EXISTS)) /* Fedora */ ret = _get_using_ntp_fedora (context); else if (g_file_test ("/usr/sbin/update-rc.d", G_FILE_TEST_EXISTS)) /* Debian */ ret = _get_using_ntp_debian (context); else if (g_file_test ("/etc/SuSE-release", G_FILE_TEST_EXISTS)) /* SUSE variant */ ret = _get_using_ntp_suse (context); else { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error enabling NTP: OS variant not supported"); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } return ret; } gboolean csd_datetime_mechanism_set_using_ntp (CsdDatetimeMechanism *mechanism, gboolean using_ntp, DBusGMethodInvocation *context) { GError *error; gboolean ret; error = NULL; if (!_check_polkit_for_action (mechanism, context)) return FALSE; if (g_file_test ("/etc/redhat-release", G_FILE_TEST_EXISTS)) /* Fedora */ ret = _set_using_ntp_fedora (context, using_ntp); else if (g_file_test ("/usr/sbin/update-rc.d", G_FILE_TEST_EXISTS)) /* Debian */ ret = _set_using_ntp_debian (context, using_ntp); else if (g_file_test ("/etc/SuSE-release", G_FILE_TEST_EXISTS)) /* SUSE variant */ ret = _set_using_ntp_suse (context, using_ntp); else { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error enabling NTP: OS variant not supported"); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } return ret; } static void check_can_do (CsdDatetimeMechanism *mechanism, const char *action, DBusGMethodInvocation *context) { const char *sender; PolkitSubject *subject; PolkitAuthorizationResult *result; GError *error; /* Check that caller is privileged */ sender = dbus_g_method_get_sender (context); subject = polkit_system_bus_name_new (sender); error = NULL; result = polkit_authority_check_authorization_sync (mechanism->priv->auth, subject, action, NULL, 0, NULL, &error); g_object_unref (subject); if (error) { dbus_g_method_return_error (context, error); g_error_free (error); return; } if (polkit_authorization_result_get_is_authorized (result)) { dbus_g_method_return (context, 2); } else if (polkit_authorization_result_get_is_challenge (result)) { dbus_g_method_return (context, 1); } else { dbus_g_method_return (context, 0); } g_object_unref (result); } gboolean csd_datetime_mechanism_can_set_time (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { check_can_do (mechanism, "org.cinnamon.settingsdaemon.datetimemechanism.configure", context); return TRUE; } gboolean csd_datetime_mechanism_can_set_timezone (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { check_can_do (mechanism, "org.cinnamon.settingsdaemon.datetimemechanism.configure", context); return TRUE; } gboolean csd_datetime_mechanism_can_set_using_ntp (CsdDatetimeMechanism *mechanism, DBusGMethodInvocation *context) { check_can_do (mechanism, "org.cinnamon.settingsdaemon.datetimemechanism.configure", context); return TRUE; } cinnamon-settings-daemon-5.2.0/plugins/datetime/csd-datetime-mechanism-suse.h0000664000175000017500000000264714144454032026265 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * Copyright (C) 2011 Vincent Untz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include #include gboolean _get_using_ntp_suse (DBusGMethodInvocation *context); gboolean _set_using_ntp_suse (DBusGMethodInvocation *context, gboolean using_ntp); gboolean _update_etc_sysconfig_clock_suse (DBusGMethodInvocation *context, const char *key, const char *value); cinnamon-settings-daemon-5.2.0/plugins/datetime/csd-datetime-mechanism-suse.c0000664000175000017500000001574714144454032026265 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * Copyright (C) 2011 Vincent Untz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "csd-datetime-mechanism-suse.h" #include "csd-datetime-mechanism.h" gboolean _get_using_ntp_suse (DBusGMethodInvocation *context) { int exit_status; GError *error = NULL; gboolean can_use_ntp; gboolean is_using_ntp; if (g_file_test ("/etc/ntp.conf", G_FILE_TEST_EXISTS)) { can_use_ntp = TRUE; if (!g_spawn_command_line_sync ("/sbin/service ntp status", NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning /sbin/service: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } if (exit_status == 0) is_using_ntp = TRUE; else is_using_ntp = FALSE; } else { can_use_ntp = FALSE; is_using_ntp = FALSE; } dbus_g_method_return (context, can_use_ntp, is_using_ntp); return TRUE; } gboolean _set_using_ntp_suse (DBusGMethodInvocation *context, gboolean using_ntp) { GError *error; int exit_status; char *cmd; error = NULL; /* We omit --level 2345 so that systemd doesn't try to use the * SysV init scripts */ cmd = g_strconcat ("/sbin/chkconfig ntp ", using_ntp ? "on" : "off", NULL); if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); cmd = g_strconcat ("/sbin/service ntp ", using_ntp ? "restart" : "stop", NULL);; if (!g_spawn_command_line_sync (cmd, NULL, NULL, &exit_status, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error spawning '%s': %s", cmd, error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (cmd); return FALSE; } g_free (cmd); dbus_g_method_return (context); return TRUE; } gboolean _update_etc_sysconfig_clock_suse (DBusGMethodInvocation *context, const char *key, const char *value) { char **lines; int n; gboolean replaced; char *data; gsize len; GError *error; /* On SUSE variants, the /etc/sysconfig/clock file needs to be kept in sync */ if (!g_file_test ("/etc/sysconfig/clock", G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { error = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error reading /etc/sysconfig/clock file: %s", "No such file"); dbus_g_method_return_error (context, error); g_error_free (error); return FALSE; } error = NULL; if (!g_file_get_contents ("/etc/sysconfig/clock", &data, &len, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error reading /etc/sysconfig/clock file: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); return FALSE; } replaced = FALSE; lines = g_strsplit (data, "\n", 0); g_free (data); for (n = 0; lines[n] != NULL; n++) { if (g_str_has_prefix (lines[n], key)) { g_free (lines[n]); lines[n] = g_strdup_printf ("%s%s", key, value); replaced = TRUE; } } if (replaced) { GString *str; str = g_string_new (NULL); for (n = 0; lines[n] != NULL; n++) { g_string_append (str, lines[n]); if (lines[n + 1] != NULL) g_string_append_c (str, '\n'); } data = g_string_free (str, FALSE); len = strlen (data); if (!g_file_set_contents ("/etc/sysconfig/clock", data, len, &error)) { GError *error2; error2 = g_error_new (CSD_DATETIME_MECHANISM_ERROR, CSD_DATETIME_MECHANISM_ERROR_GENERAL, "Error updating /etc/sysconfig/clock: %s", error->message); g_error_free (error); dbus_g_method_return_error (context, error2); g_error_free (error2); g_free (data); return FALSE; } g_free (data); } g_strfreev (lines); return TRUE; } cinnamon-settings-daemon-5.2.0/plugins/datetime/csd-datetime-mechanism-main.c0000664000175000017500000001074314144454032026221 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "csd-datetime-mechanism.h" static DBusGProxy * get_bus_proxy (DBusGConnection *connection) { DBusGProxy *bus_proxy; bus_proxy = dbus_g_proxy_new_for_name (connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); return bus_proxy; } #define BUS_NAME "org.cinnamon.SettingsDaemon.DateTimeMechanism" static gboolean acquire_name_on_proxy (DBusGProxy *bus_proxy) { GError *error; guint result; gboolean res; gboolean ret; ret = FALSE; if (bus_proxy == NULL) { goto out; } error = NULL; res = dbus_g_proxy_call (bus_proxy, "RequestName", &error, G_TYPE_STRING, BUS_NAME, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &result, G_TYPE_INVALID); if (! res) { if (error != NULL) { g_warning ("Failed to acquire %s: %s", BUS_NAME, error->message); g_error_free (error); } else { g_warning ("Failed to acquire %s", BUS_NAME); } goto out; } if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { if (error != NULL) { g_warning ("Failed to acquire %s: %s", BUS_NAME, error->message); g_error_free (error); } else { g_warning ("Failed to acquire %s", BUS_NAME); } goto out; } ret = TRUE; out: return ret; } static DBusGConnection * get_system_bus (void) { GError *error; DBusGConnection *bus; error = NULL; bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (bus == NULL) { g_warning ("Couldn't connect to system bus: %s", error->message); g_error_free (error); } return bus; } int main (int argc, char **argv) { GMainLoop *loop; CsdDatetimeMechanism *mechanism; DBusGProxy *bus_proxy; DBusGConnection *connection; int ret; ret = 1; dbus_g_thread_init (); connection = get_system_bus (); if (connection == NULL) { goto out; } bus_proxy = get_bus_proxy (connection); if (bus_proxy == NULL) { g_warning ("Could not construct bus_proxy object; bailing out"); goto out; } if (!acquire_name_on_proxy (bus_proxy) ) { g_warning ("Could not acquire name; bailing out"); goto out; } mechanism = csd_datetime_mechanism_new (); if (mechanism == NULL) { goto out; } loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); g_object_unref (mechanism); g_main_loop_unref (loop); ret = 0; out: return ret; } cinnamon-settings-daemon-5.2.0/plugins/datetime/org.cinnamon.SettingsDaemon.DateTimeMechanism.conf0000664000175000017500000000117114144454032032323 0ustar fabiofabio cinnamon-settings-daemon-5.2.0/plugins/datetime/csd-datetime-mechanism.xml0000664000175000017500000001236514144454032025657 0ustar fabiofabio Whether the caller can set the timezone The return value is not a boolean, but an integer with the following meaning: 0 the caller cannot set the timezone 1 the caller will be challenged before being able to set the timezone 2 the caller is authorized to set the timezone Whether the caller can set the time The return value is not a boolean, but an integer with the following meaning: 0 the caller cannot set the time 1 the caller will be challenged before being able to set the time 2 the caller is authorized to set the time Whether the caller can set the "use NTP" setting The return value is not a boolean, but an integer with the following meaning: 0 the caller cannot change the "use NTP" setting 1 the caller will be challenged before being able to change "use NTP" setting 2 the caller is authorized to change the "use NTP" setting cinnamon-settings-daemon-5.2.0/plugins/datetime/test-system-timezone.c0000664000175000017500000000445314144454032025124 0ustar fabiofabio/* Test for system timezone handling * * Copyright (C) 2008-2010 Novell, Inc. * * Authors: Vincent Untz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. */ #include #include "system-timezone.h" static void timezone_print (void) { SystemTimezone *systz; systz = system_timezone_new (); g_print ("Current timezone: %s\n", system_timezone_get (systz)); g_object_unref (systz); } static int timezone_set (const char *new_tz) { GError *error; error = NULL; if (!system_timezone_set (new_tz, &error)) { g_printerr ("%s\n", error->message); g_error_free (error); return 1; } return 0; } int main (int argc, char **argv) { int retval; gboolean get = FALSE; char *tz_set = NULL; GError *error; GOptionContext *context; GOptionEntry options[] = { { "get", 'g', 0, G_OPTION_ARG_NONE, &get, "Get the current timezone", NULL }, { "set", 's', 0, G_OPTION_ARG_STRING, &tz_set, "Set the timezone to TIMEZONE", "TIMEZONE" }, { NULL, 0, 0, 0, NULL, NULL, NULL } }; retval = 0; context = g_option_context_new (""); g_option_context_add_main_entries (context, options, NULL); error = NULL; if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("%s\n", error->message); g_error_free (error); g_option_context_free (context); return 1; } g_option_context_free (context); if (get || (!tz_set)) timezone_print (); else if (tz_set) retval = timezone_set (tz_set); else g_assert_not_reached (); return retval; } cinnamon-settings-daemon-5.2.0/plugins/datetime/csd-datetime-mechanism-debian.h0000664000175000017500000000221714144454032026521 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 David Zeuthen * Copyright (C) 2011 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include #include gboolean _get_using_ntp_debian (DBusGMethodInvocation *context); gboolean _set_using_ntp_debian (DBusGMethodInvocation *context, gboolean using_ntp); cinnamon-settings-daemon-5.2.0/plugins/datetime/system-timezone.c0000664000175000017500000007141714144454032024153 0ustar fabiofabio/* System timezone handling * * Copyright (C) 2008 Novell, Inc. * * Authors: Vincent Untz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * Some code is based on previous code in clock-location.c and on code from * tz.c (shipped with version <= 2.22.0). Those files were under the same * license, with those authors and copyrights: * * clock-location.c: * ================ * No header, but most of the work was done (AFAIK) by * Federico Mena Quintero * Matthias Clasen * * tz.c: * ==== * Copyright (C) 2000-2001 Ximian, Inc. * Copyright (C) 2004 Sun Microsystems, Inc. * * Authors: Hans Petter Jansson * additional functions by Erwann Chenede * reworked by Vincent Untz * * Largely based on Michael Fulbright's work on Anaconda. */ /* FIXME: it'd be nice to filter out the timezones that we might get when * parsing config files that are not in zone.tab. Note that it's also wrong * in some cases: eg, in tzdata2008b, Asia/Calcutta got renamed to * Asia/Kolkata and the old name is not in zone.tab. */ #include #include #include #include #include #include "system-timezone.h" /* Files that we look at */ #define ETC_TIMEZONE "/etc/timezone" #define ETC_TIMEZONE_MAJ "/etc/TIMEZONE" #define ETC_RC_CONF "/etc/rc.conf" #define ETC_SYSCONFIG_CLOCK "/etc/sysconfig/clock" #define ETC_CONF_D_CLOCK "/etc/conf.d/clock" #define ETC_LOCALTIME "/etc/localtime" /* The first 4 characters in a timezone file, from tzfile.h */ #define TZ_MAGIC "TZif" static GObject *systz_singleton = NULL; G_DEFINE_TYPE (SystemTimezone, system_timezone, G_TYPE_OBJECT) typedef struct { char *tz; char *env_tz; } SystemTimezonePrivate; static GObject *system_timezone_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties); static void system_timezone_finalize (GObject *obj); #define PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezonePrivate)) SystemTimezone * system_timezone_new (void) { return g_object_new (SYSTEM_TIMEZONE_TYPE, NULL); } const char * system_timezone_get (SystemTimezone *systz) { SystemTimezonePrivate *priv; g_return_val_if_fail (IS_SYSTEM_TIMEZONE (systz), NULL); priv = PRIVATE (systz); return priv->tz; } const char * system_timezone_get_env (SystemTimezone *systz) { SystemTimezonePrivate *priv; g_return_val_if_fail (IS_SYSTEM_TIMEZONE (systz), NULL); priv = PRIVATE (systz); return priv->env_tz; } static void system_timezone_class_init (SystemTimezoneClass *class) { GObjectClass *g_obj_class = G_OBJECT_CLASS (class); g_obj_class->constructor = system_timezone_constructor; g_obj_class->finalize = system_timezone_finalize; g_type_class_add_private (class, sizeof (SystemTimezonePrivate)); } static void system_timezone_init (SystemTimezone *systz) { SystemTimezonePrivate *priv = PRIVATE (systz); priv->tz = NULL; priv->env_tz = NULL; } static GObject * system_timezone_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GObject *obj; SystemTimezonePrivate *priv; /* This is a singleton, we don't need to have it per-applet */ if (systz_singleton) return g_object_ref (systz_singleton); obj = G_OBJECT_CLASS (system_timezone_parent_class)->constructor ( type, n_construct_properties, construct_properties); priv = PRIVATE (obj); priv->tz = system_timezone_find (); priv->env_tz = g_strdup (g_getenv ("TZ")); systz_singleton = obj; return systz_singleton; } static void system_timezone_finalize (GObject *obj) { SystemTimezonePrivate *priv = PRIVATE (obj); if (priv->tz) { g_free (priv->tz); priv->tz = NULL; } if (priv->env_tz) { g_free (priv->env_tz); priv->env_tz = NULL; } G_OBJECT_CLASS (system_timezone_parent_class)->finalize (obj); g_assert (obj == systz_singleton); systz_singleton = NULL; } /* * Code to deal with the system timezone on all distros. * There's no dependency on the SystemTimezone GObject here. * * Here's what we know: * * + /etc/localtime contains the binary data of the timezone. * It can be a symlink to the actual data file, a hard link to the data * file, or just a copy. So we can determine the timezone with this * (reading the symlink, comparing inodes, or comparing content). * * + However, most distributions also have the timezone setting * configured somewhere else. This might be better to read it from there. * * Debian/Ubuntu/Gentoo (new): content of /etc/timezone * Fedora/Mandriva: the ZONE key in /etc/sysconfig/clock * openSUSE: the TIMEZONE key in /etc/sysconfig/clock * Solaris/OpenSolaris: the TZ key in /etc/TIMEZONE * Arch Linux: the TIMEZONE key in /etc/rc.conf * Gentoo (old): the ZONE key in /etc/conf.d/clock * * FIXME: reading the system-tools-backends, it seems there's this too: * Solaris: the TZ key in /etc/default/init * /etc/TIMEZONE seems to be a link to /etc/default/init * * First, some functions to handle those system config files. * */ /* This works for Debian and derivatives (including Ubuntu), and new Gentoo */ static char * system_timezone_read_etc_timezone (void) { FILE *etc_timezone; GString *reading; int c; etc_timezone = g_fopen (ETC_TIMEZONE, "r"); if (!etc_timezone) return NULL; reading = g_string_new (""); c = fgetc (etc_timezone); /* only get the first line, we'll validate the value later */ while (c != EOF && !g_ascii_isspace (c)) { reading = g_string_append_c (reading, c); c = fgetc (etc_timezone); } fclose (etc_timezone); if (reading->str && reading->str[0] != '\0') return g_string_free (reading, FALSE); else g_string_free (reading, TRUE); return NULL; } static gboolean system_timezone_write_etc_timezone (const char *tz, GError **error) { char *content; GError *our_error; gboolean retval; if (!g_file_test (ETC_TIMEZONE, G_FILE_TEST_IS_REGULAR)) return TRUE; content = g_strdup_printf ("%s\n", tz); our_error = NULL; retval = g_file_set_contents (ETC_TIMEZONE, content, -1, &our_error); g_free (content); if (!retval) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_GENERAL, ETC_TIMEZONE" cannot be overwritten: %s", our_error->message); g_error_free (our_error); } return retval; } /* Read a file that looks like a key-file (but there's no need for groups) * and get the last value for a specific key */ static char * system_timezone_read_key_file (const char *filename, const char *key) { GIOChannel *channel; char *key_eq; char *line; char *retval; if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) return NULL; channel = g_io_channel_new_file (filename, "r", NULL); if (!channel) return NULL; key_eq = g_strdup_printf ("%s=", key); retval = NULL; while (g_io_channel_read_line (channel, &line, NULL, NULL, NULL) == G_IO_STATUS_NORMAL) { if (g_str_has_prefix (line, key_eq)) { char *value; int len; value = line + strlen (key_eq); g_strstrip (value); len = strlen (value); if (value[0] == '\"') { if (value[len - 1] == '\"') { if (retval) g_free (retval); retval = g_strndup (value + 1, len - 2); } } else { if (retval) g_free (retval); retval = g_strdup (line + strlen (key_eq)); } g_strstrip (retval); } g_free (line); } g_free (key_eq); g_io_channel_unref (channel); return retval; } static gboolean system_timezone_write_key_file (const char *filename, const char *key, const char *value, GError **error) { GError *our_error; char *content; gsize len; char *key_eq; char **lines; gboolean replaced; gboolean retval; int n; if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) return TRUE; our_error = NULL; if (!g_file_get_contents (filename, &content, &len, &our_error)) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_GENERAL, "%s cannot be read: %s", filename, our_error->message); g_error_free (our_error); return FALSE; } lines = g_strsplit (content, "\n", 0); g_free (content); key_eq = g_strdup_printf ("%s=", key); replaced = FALSE; for (n = 0; lines[n] != NULL; n++) { if (g_str_has_prefix (lines[n], key_eq)) { char *old_value; gboolean use_quotes; old_value = lines[n] + strlen (key_eq); g_strstrip (old_value); use_quotes = old_value[0] == '\"'; g_free (lines[n]); if (use_quotes) lines[n] = g_strdup_printf ("%s\"%s\"", key_eq, value); else lines[n] = g_strdup_printf ("%s%s", key_eq, value); replaced = TRUE; } } g_free (key_eq); if (!replaced) { g_strfreev (lines); return TRUE; } content = g_strjoinv ("\n", lines); g_strfreev (lines); retval = g_file_set_contents (filename, content, -1, &our_error); g_free (content); if (!retval) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_GENERAL, "%s cannot be overwritten: %s", filename, our_error->message); g_error_free (our_error); } return retval; } /* This works for Solaris/OpenSolaris */ static char * system_timezone_read_etc_TIMEZONE (void) { return system_timezone_read_key_file (ETC_TIMEZONE_MAJ, "TZ"); } static gboolean system_timezone_write_etc_TIMEZONE (const char *tz, GError **error) { return system_timezone_write_key_file (ETC_TIMEZONE_MAJ, "TZ", tz, error); } /* This works for Fedora and Mandriva */ static char * system_timezone_read_etc_sysconfig_clock (void) { return system_timezone_read_key_file (ETC_SYSCONFIG_CLOCK, "ZONE"); } static gboolean system_timezone_write_etc_sysconfig_clock (const char *tz, GError **error) { return system_timezone_write_key_file (ETC_SYSCONFIG_CLOCK, "ZONE", tz, error); } /* This works for openSUSE */ static char * system_timezone_read_etc_sysconfig_clock_alt (void) { return system_timezone_read_key_file (ETC_SYSCONFIG_CLOCK, "TIMEZONE"); } static gboolean system_timezone_write_etc_sysconfig_clock_alt (const char *tz, GError **error) { return system_timezone_write_key_file (ETC_SYSCONFIG_CLOCK, "TIMEZONE", tz, error); } /* This works for old Gentoo */ static char * system_timezone_read_etc_conf_d_clock (void) { return system_timezone_read_key_file (ETC_CONF_D_CLOCK, "TIMEZONE"); } static gboolean system_timezone_write_etc_conf_d_clock (const char *tz, GError **error) { return system_timezone_write_key_file (ETC_CONF_D_CLOCK, "TIMEZONE", tz, error); } /* This works for Arch Linux */ static char * system_timezone_read_etc_rc_conf (void) { return system_timezone_read_key_file (ETC_RC_CONF, "TIMEZONE"); } static gboolean system_timezone_write_etc_rc_conf (const char *tz, GError **error) { return system_timezone_write_key_file (ETC_RC_CONF, "TIMEZONE", tz, error); } /* * * First, getting the timezone. * */ static char * system_timezone_strip_path_if_valid (const char *filename) { int skip; if (!filename || !g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/")) return NULL; /* Timezone data files also live under posix/ and right/ for some * reason. * FIXME: make sure accepting those files is valid. I think "posix" is * okay, not sure about "right" */ if (g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/posix/")) skip = strlen (SYSTEM_ZONEINFODIR"/posix/"); else if (g_str_has_prefix (filename, SYSTEM_ZONEINFODIR"/right/")) skip = strlen (SYSTEM_ZONEINFODIR"/right/"); else skip = strlen (SYSTEM_ZONEINFODIR"/"); return g_strdup (filename + skip); } /* Read the soft symlink from /etc/localtime */ static char * system_timezone_read_etc_localtime_softlink (void) { char *file; char *tz; if (!g_file_test (ETC_LOCALTIME, G_FILE_TEST_IS_SYMLINK)) return NULL; file = g_file_read_link (ETC_LOCALTIME, NULL); tz = system_timezone_strip_path_if_valid (file); g_free (file); return tz; } typedef gboolean (*CompareFiles) (struct stat *a_stat, struct stat *b_stat, const char *a_content, gsize a_content_len, const char *b_filename); static char * recursive_compare (struct stat *localtime_stat, const char *localtime_content, gsize localtime_content_len, char *file, CompareFiles compare_func) { struct stat file_stat; if (g_stat (file, &file_stat) != 0) return NULL; if (S_ISREG (file_stat.st_mode)) { if (compare_func (localtime_stat, &file_stat, localtime_content, localtime_content_len, file)) return system_timezone_strip_path_if_valid (file); else return NULL; } else if (S_ISDIR (file_stat.st_mode)) { GDir *dir = NULL; char *ret = NULL; const char *subfile = NULL; char *subpath = NULL; dir = g_dir_open (file, 0, NULL); if (dir == NULL) return NULL; while ((subfile = g_dir_read_name (dir)) != NULL) { subpath = g_build_filename (file, subfile, NULL); ret = recursive_compare (localtime_stat, localtime_content, localtime_content_len, subpath, compare_func); g_free (subpath); if (ret != NULL) break; } g_dir_close (dir); return ret; } return NULL; } static gboolean files_are_identical_inode (struct stat *a_stat, struct stat *b_stat, const char *a_content, gsize a_content_len, const char *b_filename) { return (a_stat->st_ino == b_stat->st_ino); } /* Determine if /etc/localtime is a hard link to some file, by looking at * the inodes */ static char * system_timezone_read_etc_localtime_hardlink (void) { struct stat stat_localtime; if (g_stat (ETC_LOCALTIME, &stat_localtime) != 0) return NULL; if (!S_ISREG (stat_localtime.st_mode)) return NULL; return recursive_compare (&stat_localtime, NULL, 0, SYSTEM_ZONEINFODIR, files_are_identical_inode); } static gboolean files_are_identical_content (struct stat *a_stat, struct stat *b_stat, const char *a_content, gsize a_content_len, const char *b_filename) { char *b_content = NULL; gsize b_content_len = -1; int cmp; if (a_stat->st_size != b_stat->st_size) return FALSE; if (!g_file_get_contents (b_filename, &b_content, &b_content_len, NULL)) return FALSE; if (a_content_len != b_content_len) { g_free (b_content); return FALSE; } cmp = memcmp (a_content, b_content, a_content_len); g_free (b_content); return (cmp == 0); } /* Determine if /etc/localtime is a copy of a timezone file */ static char * system_timezone_read_etc_localtime_content (void) { struct stat stat_localtime; char *localtime_content = NULL; gsize localtime_content_len = -1; char *retval; if (g_stat (ETC_LOCALTIME, &stat_localtime) != 0) return NULL; if (!S_ISREG (stat_localtime.st_mode)) return NULL; if (!g_file_get_contents (ETC_LOCALTIME, &localtime_content, &localtime_content_len, NULL)) return NULL; retval = recursive_compare (&stat_localtime, localtime_content, localtime_content_len, SYSTEM_ZONEINFODIR, files_are_identical_content); g_free (localtime_content); return retval; } typedef char * (*GetSystemTimezone) (void); /* The order of the functions here define the priority of the methods used * to find the timezone. First method has higher priority. */ static GetSystemTimezone get_system_timezone_methods[] = { /* cheap and "more correct" than data from a config file */ system_timezone_read_etc_localtime_softlink, /* reading various config files */ system_timezone_read_etc_timezone, system_timezone_read_etc_sysconfig_clock, system_timezone_read_etc_sysconfig_clock_alt, system_timezone_read_etc_TIMEZONE, system_timezone_read_etc_rc_conf, /* reading deprecated config files */ system_timezone_read_etc_conf_d_clock, /* reading /etc/timezone directly. Expensive since we have to stat * many files */ system_timezone_read_etc_localtime_hardlink, system_timezone_read_etc_localtime_content, NULL }; static gboolean system_timezone_is_valid (const char *tz) { const char *c; if (!tz) return FALSE; for (c = tz; *c != '\0'; c++) { if (!(g_ascii_isalnum (*c) || *c == '/' || *c == '-' || *c == '_')) return FALSE; } return TRUE; } char * system_timezone_find (void) { char *tz; int i; for (i = 0; get_system_timezone_methods[i] != NULL; i++) { tz = get_system_timezone_methods[i] (); if (system_timezone_is_valid (tz)) return tz; g_free (tz); } return g_strdup ("UTC"); } /* * * Now, setting the timezone. * */ static gboolean system_timezone_is_zone_file_valid (const char *zone_file, GError **error) { GError *our_error; GIOChannel *channel; char buffer[strlen (TZ_MAGIC)]; gsize read; /* First, check the zone_file is properly rooted */ if (!g_str_has_prefix (zone_file, SYSTEM_ZONEINFODIR"/")) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, "Timezone file needs to be under "SYSTEM_ZONEINFODIR); return FALSE; } /* Second, check it's a regular file that exists */ if (!g_file_test (zone_file, G_FILE_TEST_IS_REGULAR)) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, "No such timezone file %s", zone_file); return FALSE; } /* Third, check that it's a tzfile (see tzfile(5)). The file has a 4 * bytes header which is TZ_MAGIC. * * TODO: is there glibc API for this? */ our_error = NULL; channel = g_io_channel_new_file (zone_file, "r", &our_error); if (!our_error) g_io_channel_read_chars (channel, buffer, strlen (TZ_MAGIC), &read, &our_error); if (channel) g_io_channel_unref (channel); if (our_error) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, "Timezone file %s cannot be read: %s", zone_file, our_error->message); g_error_free (our_error); return FALSE; } if (read != strlen (TZ_MAGIC) || strncmp (buffer, TZ_MAGIC, strlen (TZ_MAGIC)) != 0) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, "%s is not a timezone file", zone_file); return FALSE; } return TRUE; } static gboolean system_timezone_set_etc_timezone (const char *zone_file, GError **error) { GError *our_error; char *content; gsize len; if (!system_timezone_is_zone_file_valid (zone_file, error)) return FALSE; /* If /etc/localtime is a symlink, write a symlink */ if (g_file_test (ETC_LOCALTIME, G_FILE_TEST_IS_SYMLINK)) { if (g_unlink (ETC_LOCALTIME) == 0 && symlink (zone_file, ETC_LOCALTIME) == 0) return TRUE; /* If we couldn't symlink the file, we'll just fallback on * copying it */ } /* Else copy the file to /etc/localtime. We explicitly avoid doing * hard links since they break with different partitions */ our_error = NULL; if (!g_file_get_contents (zone_file, &content, &len, &our_error)) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_GENERAL, "Timezone file %s cannot be read: %s", zone_file, our_error->message); g_error_free (our_error); return FALSE; } if (!g_file_set_contents (ETC_LOCALTIME, content, len, &our_error)) { g_set_error (error, SYSTEM_TIMEZONE_ERROR, SYSTEM_TIMEZONE_ERROR_GENERAL, ETC_LOCALTIME" cannot be overwritten: %s", our_error->message); g_error_free (our_error); g_free (content); return FALSE; } g_free (content); return TRUE; } typedef gboolean (*SetSystemTimezone) (const char *tz, GError **error); /* The order here does not matter too much: we'll try to change all files * that already have a timezone configured. It matters in case of error, * since the process will be stopped and the last methods won't be called. * So we use the same order as in get_system_timezone_methods */ static SetSystemTimezone set_system_timezone_methods[] = { /* writing various config files if they exist and have the * setting already present */ system_timezone_write_etc_timezone, system_timezone_write_etc_sysconfig_clock, system_timezone_write_etc_sysconfig_clock_alt, system_timezone_write_etc_TIMEZONE, system_timezone_write_etc_rc_conf, /* writing deprecated config files if they exist and have the * setting already present */ system_timezone_write_etc_conf_d_clock, NULL }; static gboolean system_timezone_update_config (const char *tz, GError **error) { int i; for (i = 0; set_system_timezone_methods[i] != NULL; i++) { if (!set_system_timezone_methods[i] (tz, error)) return FALSE; /* FIXME: maybe continue to change all config files if * possible? */ } return TRUE; } gboolean system_timezone_set (const char *tz, GError **error) { char *zone_file; gboolean retval; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); zone_file = g_build_filename (SYSTEM_ZONEINFODIR, tz, NULL); /* FIXME: is it right to return FALSE even when /etc/localtime was * changed but not the config files? */ retval = system_timezone_set_etc_timezone (zone_file, error) && system_timezone_update_config (tz, error); g_free (zone_file); return retval; } GQuark system_timezone_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("system-timezone-error"); } return ret; } cinnamon-settings-daemon-5.2.0/plugins/datetime/org.cinnamon.settingsdaemon.datetimemechanism.policy0000664000175000017500000000137614144454032033144 0ustar fabiofabio Cinnamon https://projects.linuxmint.com/cinnamon/ gnome-panel-clock Change system time and date settings To change time or date settings, you need to authenticate. no no auth_admin_keep cinnamon-settings-daemon-5.2.0/plugins/datetime/system-timezone.h0000664000175000017500000000504514144454032024152 0ustar fabiofabio/* System timezone handling * * Copyright (C) 2008 Novell, Inc. * * Authors: Vincent Untz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. */ #ifndef __SYSTEM_TIMEZONE_H__ #define __SYSTEM_TIMEZONE_H__ #include #include G_BEGIN_DECLS #ifdef HAVE_SOLARIS #define SYSTEM_ZONEINFODIR "/usr/share/lib/zoneinfo/tab" #else #define SYSTEM_ZONEINFODIR "/usr/share/zoneinfo" #endif #define SYSTEM_TIMEZONE_TYPE (system_timezone_get_type ()) #define SYSTEM_TIMEZONE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezone)) #define SYSTEM_TIMEZONE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), SYSTEM_TIMEZONE_TYPE, SystemTimezoneClass)) #define IS_SYSTEM_TIMEZONE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SYSTEM_TIMEZONE_TYPE)) #define IS_SYSTEM_TIMEZONE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), SYSTEM_TIMEZONE_TYPE)) #define SYSTEM_TIMEZONE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SYSTEM_TIMEZONE_TYPE, SystemTimezoneClass)) typedef struct { GObject g_object; } SystemTimezone; typedef struct { GObjectClass g_object_class; } SystemTimezoneClass; GType system_timezone_get_type (void); SystemTimezone *system_timezone_new (void); const char *system_timezone_get (SystemTimezone *systz); const char *system_timezone_get_env (SystemTimezone *systz); /* Functions to set the timezone. They won't be used by the applet, but * by a program with more privileges */ #define SYSTEM_TIMEZONE_ERROR system_timezone_error_quark () GQuark system_timezone_error_quark (void); typedef enum { SYSTEM_TIMEZONE_ERROR_GENERAL, SYSTEM_TIMEZONE_ERROR_INVALID_TIMEZONE_FILE, SYSTEM_TIMEZONE_NUM_ERRORS } SystemTimezoneError; char *system_timezone_find (void); gboolean system_timezone_set (const char *tz, GError **error); G_END_DECLS #endif /* __SYSTEM_TIMEZONE_H__ */ cinnamon-settings-daemon-5.2.0/plugins/screensaver-proxy/0000775000175000017500000000000014144454032022524 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/screensaver-proxy/meson.build0000664000175000017500000000161014144454032024664 0ustar fabiofabioplugin_name = 'screensaver-proxy' screensaver_proxy_sources = [ 'csd-screensaver-proxy-manager.c', 'main.c', ] screensaver_proxy_deps = [ common_dep, csd_dep, libnotify, ] executable( 'csd-screensaver-proxy', screensaver_proxy_sources, include_directories: [include_dirs, common_inc], dependencies: screensaver_proxy_deps, c_args: [ '-DPLUGIN_NAME="@0@"'.format(plugin_name), ], install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-screensaver-proxy') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-screensaver-proxy') endif configure_file( input: 'cinnamon-settings-daemon-screensaver-proxy.desktop.in', output: 'cinnamon-settings-daemon-screensaver-proxy.desktop', configuration: desktop_conf, install_dir: autostartdir, ) cinnamon-settings-daemon-5.2.0/plugins/screensaver-proxy/csd-screensaver-proxy-manager.h0000664000175000017500000000517214144454032030560 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2012 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CSD_SCREENSAVER_PROXY_MANAGER_H #define __CSD_SCREENSAVER_PROXY_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_SCREENSAVER_PROXY_MANAGER (csd_screensaver_proxy_manager_get_type ()) #define CSD_SCREENSAVER_PROXY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_SCREENSAVER_PROXY_MANAGER, CsdScreensaverProxyManager)) #define CSD_SCREENSAVER_PROXY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_SCREENSAVER_PROXY_MANAGER, CsdScreensaverProxyManagerClass)) #define CSD_IS_SCREENSAVER_PROXY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_SCREENSAVER_PROXY_MANAGER)) #define CSD_IS_SCREENSAVER_PROXY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_SCREENSAVER_PROXY_MANAGER)) #define CSD_SCREENSAVER_PROXY_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_SCREENSAVER_PROXY_MANAGER, CsdScreensaverProxyManagerClass)) typedef struct CsdScreensaverProxyManagerPrivate CsdScreensaverProxyManagerPrivate; typedef struct { GObject parent; CsdScreensaverProxyManagerPrivate *priv; } CsdScreensaverProxyManager; typedef struct { GObjectClass parent_class; } CsdScreensaverProxyManagerClass; GType csd_screensaver_proxy_manager_get_type (void); CsdScreensaverProxyManager *csd_screensaver_proxy_manager_new (void); gboolean csd_screensaver_proxy_manager_start (CsdScreensaverProxyManager *manager, GError **error); void csd_screensaver_proxy_manager_stop (CsdScreensaverProxyManager *manager); G_END_DECLS #endif /* __CSD_SCREENSAVER_PROXY_MANAGER_H */ cinnamon-settings-daemon-5.2.0/plugins/screensaver-proxy/main.c0000664000175000017500000000110014144454032023604 0ustar fabiofabio#define NEW csd_screensaver_proxy_manager_new #define START csd_screensaver_proxy_manager_start #define STOP csd_screensaver_proxy_manager_stop #define MANAGER CsdScreensaverProxyManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-screensaver-proxy-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-5.2.0/plugins/screensaver-proxy/csd-screensaver-proxy-manager.c0000664000175000017500000004704214144454032030555 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2012 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-session.h" #include "cinnamon-settings-profile.h" #include "csd-screensaver-proxy-manager.h" #define CSD_SCREENSAVER_PROXY_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_SCREENSAVER_PROXY_MANAGER, CsdScreensaverProxyManagerPrivate)) /* As available in: * https://projects.kde.org/projects/kde/kde-workspace/repository/revisions/master/entry/ksmserver/screenlocker/dbus/org.freedesktop.ScreenSaver.xml * and documented in: * https://projects.kde.org/projects/kde/kde-workspace/repository/revisions/master/entry/ksmserver/screenlocker/interface.h */ static const gchar introspection_xml[] = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; static const gchar introspection_xml2[] = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; #define CSD_SCREENSAVER_PROXY_DBUS_SERVICE "org.freedesktop.ScreenSaver" #define CSD_SCREENSAVER_PROXY_DBUS_PATH "/org/freedesktop/ScreenSaver" #define CSD_SCREENSAVER_PROXY_DBUS_PATH2 "/ScreenSaver" #define CSD_SCREENSAVER_PROXY_DBUS_INTERFACE "org.freedesktop.ScreenSaver" #define GSM_INHIBITOR_FLAG_IDLE 1 << 3 struct CsdScreensaverProxyManagerPrivate { GDBusProxy *session; GDBusConnection *connection; GCancellable *bus_cancellable; GDBusNodeInfo *introspection_data; GDBusNodeInfo *introspection_data2; guint name_id; GHashTable *watch_ht; /* key = sender, value = name watch id */ GHashTable *cookie_ht; /* key = cookie, value = sender */ }; static void csd_screensaver_proxy_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdScreensaverProxyManager, csd_screensaver_proxy_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; #define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager" #define GNOME_SESSION_DBUS_OBJECT "/org/gnome/SessionManager" #define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager" static GDBusProxy * cinnamon_settings_session_get_session_proxy (void) { static GDBusProxy *session_proxy; GError *error = NULL; if (session_proxy != NULL) { g_object_ref (session_proxy); } else { session_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_OBJECT, GNOME_SESSION_DBUS_INTERFACE, NULL, &error); if (error) { g_warning ("Failed to connect to the session manager: %s", error->message); g_error_free (error); } else { g_object_add_weak_pointer (G_OBJECT (session_proxy), (gpointer*)&session_proxy); } } return session_proxy; } static void name_vanished_cb (GDBusConnection *connection, const gchar *name, CsdScreensaverProxyManager *manager) { GHashTableIter iter; gpointer cookie_ptr; const char *sender; /* Look for all the cookies under that name, * and call uninhibit for them */ g_hash_table_iter_init (&iter, manager->priv->cookie_ht); while (g_hash_table_iter_next (&iter, &cookie_ptr, (gpointer *) &sender)) { if (g_strcmp0 (sender, name) == 0) { guint cookie = GPOINTER_TO_UINT (cookie_ptr); g_dbus_proxy_call_sync (manager->priv->session, "Uninhibit", g_variant_new ("(u)", cookie), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); g_debug ("Removing cookie %u for sender %s", cookie, sender); g_hash_table_iter_remove (&iter); } } g_hash_table_remove (manager->priv->watch_ht, sender); } static void handle_method_call (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { CsdScreensaverProxyManager *manager = CSD_SCREENSAVER_PROXY_MANAGER (user_data); /* Check session pointer as a proxy for whether the manager is in the start or stop state */ if (manager->priv->session == NULL) { return; } g_debug ("Calling method '%s.%s' for ScreenSaver Proxy", interface_name, method_name); if (g_strcmp0 (method_name, "Inhibit") == 0) { GVariant *ret; const char *app_id; const char *reason; guint cookie; g_variant_get (parameters, "(ss)", &app_id, &reason); ret = g_dbus_proxy_call_sync (manager->priv->session, "Inhibit", g_variant_new ("(susu)", app_id, 0, reason, GSM_INHIBITOR_FLAG_IDLE), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); g_variant_get (ret, "(u)", &cookie); g_hash_table_insert (manager->priv->cookie_ht, GUINT_TO_POINTER (cookie), g_strdup (sender)); if (g_hash_table_lookup (manager->priv->watch_ht, sender) == NULL) { guint watch_id; watch_id = g_bus_watch_name_on_connection (manager->priv->connection, sender, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, (GBusNameVanishedCallback) name_vanished_cb, manager, NULL); g_hash_table_insert (manager->priv->watch_ht, g_strdup (sender), GUINT_TO_POINTER (watch_id)); } g_dbus_method_invocation_return_value (invocation, ret); } else if (g_strcmp0 (method_name, "UnInhibit") == 0) { guint cookie; g_variant_get (parameters, "(u)", &cookie); g_dbus_proxy_call_sync (manager->priv->session, "Uninhibit", parameters, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "Throttle") == 0) { g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "UnThrottle") == 0) { g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "Lock") == 0) { goto unimplemented; } else if (g_strcmp0 (method_name, "SimulateUserActivity") == 0) { goto unimplemented; } else if (g_strcmp0 (method_name, "GetActive") == 0) { goto unimplemented; } else if (g_strcmp0 (method_name, "GetActiveTime") == 0) { goto unimplemented; } else if (g_strcmp0 (method_name, "GetSessionIdleTime") == 0) { goto unimplemented; } else if (g_strcmp0 (method_name, "SetActive") == 0) { goto unimplemented; } return; unimplemented: g_dbus_method_invocation_return_dbus_error (invocation, "org.freedesktop.DBus.Error.NotSupported", "This method is not implemented"); } static const GDBusInterfaceVTable interface_vtable = { handle_method_call, NULL, /* GetProperty */ NULL, /* SetProperty */ }; static void on_bus_gotten (GObject *source_object, GAsyncResult *res, CsdScreensaverProxyManager *manager) { GDBusConnection *connection; GDBusInterfaceInfo **infos; GError *error = NULL; if (manager->priv->bus_cancellable == NULL || g_cancellable_is_cancelled (manager->priv->bus_cancellable)) { g_warning ("Operation has been cancelled, so not retrieving session bus"); return; } connection = g_bus_get_finish (res, &error); if (connection == NULL) { g_warning ("Could not get session bus: %s", error->message); g_error_free (error); return; } manager->priv->connection = connection; infos = manager->priv->introspection_data->interfaces; g_dbus_connection_register_object (connection, CSD_SCREENSAVER_PROXY_DBUS_PATH, infos[0], &interface_vtable, manager, NULL, NULL); infos = manager->priv->introspection_data2->interfaces; g_dbus_connection_register_object (connection, CSD_SCREENSAVER_PROXY_DBUS_PATH2, infos[0], &interface_vtable, manager, NULL, NULL); manager->priv->name_id = g_bus_own_name_on_connection (manager->priv->connection, CSD_SCREENSAVER_PROXY_DBUS_SERVICE, G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL); } static void register_manager_dbus (CsdScreensaverProxyManager *manager) { manager->priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); manager->priv->introspection_data2 = g_dbus_node_info_new_for_xml (introspection_xml2, NULL); manager->priv->bus_cancellable = g_cancellable_new (); g_assert (manager->priv->introspection_data != NULL); g_assert (manager->priv->introspection_data2 != NULL); g_bus_get (G_BUS_TYPE_SESSION, manager->priv->bus_cancellable, (GAsyncReadyCallback) on_bus_gotten, manager); } gboolean csd_screensaver_proxy_manager_start (CsdScreensaverProxyManager *manager, GError **error) { g_debug ("Starting screensaver-proxy manager"); cinnamon_settings_profile_start (NULL); manager->priv->session = cinnamon_settings_session_get_session_proxy (); manager->priv->watch_ht = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_bus_unwatch_name); manager->priv->cookie_ht = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_free); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_screensaver_proxy_manager_stop (CsdScreensaverProxyManager *manager) { g_debug ("Stopping screensaver_proxy manager"); if (manager->priv->session != NULL) { g_object_unref (manager->priv->session); manager->priv->session = NULL; } if (manager->priv->watch_ht != NULL) { g_hash_table_destroy (manager->priv->watch_ht); manager->priv->watch_ht = NULL; } if (manager->priv->cookie_ht != NULL) { g_hash_table_destroy (manager->priv->cookie_ht); manager->priv->cookie_ht = NULL; } } static void csd_screensaver_proxy_manager_class_init (CsdScreensaverProxyManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_screensaver_proxy_manager_finalize; g_type_class_add_private (klass, sizeof (CsdScreensaverProxyManagerPrivate)); } static void csd_screensaver_proxy_manager_init (CsdScreensaverProxyManager *manager) { manager->priv = CSD_SCREENSAVER_PROXY_MANAGER_GET_PRIVATE (manager); } static void csd_screensaver_proxy_manager_finalize (GObject *object) { CsdScreensaverProxyManager *manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_SCREENSAVER_PROXY_MANAGER (object)); manager = CSD_SCREENSAVER_PROXY_MANAGER (object); g_return_if_fail (manager->priv != NULL); if (manager->priv->name_id != 0) { g_bus_unown_name (manager->priv->name_id); manager->priv->name_id = 0; } if (manager->priv->connection != NULL) { g_object_unref (manager->priv->connection); manager->priv->connection = NULL; } if (manager->priv->bus_cancellable != NULL) { g_object_unref (manager->priv->bus_cancellable); manager->priv->bus_cancellable = NULL; } if (manager->priv->introspection_data != NULL) { g_dbus_node_info_unref (manager->priv->introspection_data); manager->priv->introspection_data = NULL; } if (manager->priv->introspection_data2 != NULL) { g_dbus_node_info_unref (manager->priv->introspection_data2); manager->priv->introspection_data2 = NULL; } G_OBJECT_CLASS (csd_screensaver_proxy_manager_parent_class)->finalize (object); } CsdScreensaverProxyManager * csd_screensaver_proxy_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_SCREENSAVER_PROXY_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); register_manager_dbus (manager_object); } return CSD_SCREENSAVER_PROXY_MANAGER (manager_object); } ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootcinnamon-settings-daemon-5.2.0/plugins/screensaver-proxy/cinnamon-settings-daemon-screensaver-proxy.desktop.incinnamon-settings-daemon-5.2.0/plugins/screensaver-proxy/cinnamon-settings-daemon-screensaver-proxy.0000664000175000017500000000036214144454032033124 0ustar fabiofabio[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - screensaver-proxy Exec=csd-screensaver-proxy OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-5.2.0/plugins/common/0000775000175000017500000000000014144454032020315 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/common/csd-power-helper.h0000664000175000017500000000217414144454032023652 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2012 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. */ #ifndef __CSD_POWER_HELPER_H #define __CSD_POWER_HELPER_H #include G_BEGIN_DECLS void csd_power_suspend (gboolean try_hybrid, gboolean suspend_then_hibernate); void csd_power_hibernate (void); void csd_power_poweroff (void); G_END_DECLS #endif /* __CSD_POWER_HELPER_H */ cinnamon-settings-daemon-5.2.0/plugins/common/csd-power-helper.c0000664000175000017500000002745414144454032023655 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2012 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include #include "config.h" #include "csd-power-helper.h" #define LOGIND_DBUS_NAME "org.freedesktop.login1" #define LOGIND_DBUS_PATH "/org/freedesktop/login1" #define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager" #define CONSOLEKIT_DBUS_NAME "org.freedesktop.ConsoleKit" #define CONSOLEKIT_DBUS_PATH_MANAGER "/org/freedesktop/ConsoleKit/Manager" #define CONSOLEKIT_DBUS_INTERFACE_MANAGER "org.freedesktop.ConsoleKit.Manager" #ifdef HAVE_LOGIND static gboolean use_logind (void) { static gboolean should_use_logind = FALSE; static gsize once_init_value = 0; if (g_once_init_enter (&once_init_value)) { should_use_logind = access("/run/systemd/seats/", F_OK) == 0; // sd_booted () g_once_init_leave (&once_init_value, 1); } return should_use_logind; } #else /* HAVE_LOGIND */ static gboolean use_logind (void) { return FALSE; } #endif /* HAVE_LOGIND */ static void logind_stop (void) { GDBusConnection *bus; bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); g_dbus_connection_call (bus, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, "PowerOff", g_variant_new ("(b)", FALSE), NULL, 0, G_MAXINT, NULL, NULL, NULL); g_object_unref (bus); } static gboolean can_power_action (gchar *method_name) { GDBusConnection *bus; GVariant *res; gchar *rv; gboolean can_action; GError *error = NULL; bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); res = g_dbus_connection_call_sync (bus, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, method_name, NULL, G_VARIANT_TYPE_TUPLE, 0, G_MAXINT, NULL, &error); g_object_unref (bus); if (error) { g_warning ("Calling %s failed: %s", method_name, error->message); g_clear_error (&error); return FALSE; } g_variant_get (res, "(s)", &rv); g_variant_unref (res); can_action = g_strcmp0 (rv, "yes") == 0 || g_strcmp0 (rv, "challenge") == 0; if (!can_action) { g_warning ("logind does not support method %s", method_name); } g_free (rv); return can_action; } static void logind_suspend (gboolean suspend_then_hibernate) { gchar *method_name = "Suspend"; if (suspend_then_hibernate && can_power_action("CanHibernate")) { method_name = "SuspendThenHibernate"; } GDBusConnection *bus; bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); g_dbus_connection_call (bus, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, method_name, g_variant_new ("(b)", TRUE), NULL, 0, G_MAXINT, NULL, NULL, NULL); g_object_unref (bus); } static void logind_hybrid_suspend (void) { GDBusConnection *bus; bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); g_dbus_connection_call (bus, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, "HybridSleep", g_variant_new ("(b)", TRUE), NULL, 0, G_MAXINT, NULL, NULL, NULL); g_object_unref (bus); } static void logind_hibernate (void) { GDBusConnection *bus; bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); g_dbus_connection_call (bus, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, "Hibernate", g_variant_new ("(b)", TRUE), NULL, 0, G_MAXINT, NULL, NULL, NULL); g_object_unref (bus); } static void consolekit_stop_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GVariant *result; GError *error = NULL; result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (result == NULL) { g_warning ("couldn't stop using ConsoleKit: %s", error->message); g_error_free (error); } else { g_variant_unref (result); } } static void consolekit_stop (void) { GError *error = NULL; GDBusProxy *proxy; /* power down the machine in a safe way */ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CONSOLEKIT_DBUS_NAME, CONSOLEKIT_DBUS_PATH_MANAGER, CONSOLEKIT_DBUS_INTERFACE_MANAGER, NULL, &error); if (proxy == NULL) { g_warning ("cannot connect to ConsoleKit: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, "Stop", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, consolekit_stop_cb, NULL); g_object_unref (proxy); } static void consolekit_sleep_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GVariant *result; GError *error = NULL; result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (result == NULL) { g_warning ("couldn't sleep using ConsoleKit: %s", error->message); g_error_free (error); } else { g_variant_unref (result); } } static void consolekit_suspend (gboolean suspend_then_hibernate) { GError *error = NULL; GDBusProxy *proxy; gchar *method_name = "Suspend"; if (suspend_then_hibernate && can_power_action("CanHibernate")) { method_name = "SuspendThenHibernate"; } proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CONSOLEKIT_DBUS_NAME, CONSOLEKIT_DBUS_PATH_MANAGER, CONSOLEKIT_DBUS_INTERFACE_MANAGER, NULL, &error); if (proxy == NULL) { g_warning ("cannot connect to ConsoleKit: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, method_name, g_variant_new("(b)", TRUE), G_DBUS_CALL_FLAGS_NONE, -1, NULL, consolekit_sleep_cb, NULL); g_object_unref (proxy); } static void consolekit_hibernate (void) { GError *error = NULL; GDBusProxy *proxy; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CONSOLEKIT_DBUS_NAME, CONSOLEKIT_DBUS_PATH_MANAGER, CONSOLEKIT_DBUS_INTERFACE_MANAGER, NULL, &error); if (proxy == NULL) { g_warning ("cannot connect to ConsoleKit: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, "Hibernate", g_variant_new("(b)", TRUE), G_DBUS_CALL_FLAGS_NONE, -1, NULL, consolekit_sleep_cb, NULL); g_object_unref (proxy); } static void consolekit_hybrid_suspend (void) { GError *error = NULL; GDBusProxy *proxy; proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CONSOLEKIT_DBUS_NAME, CONSOLEKIT_DBUS_PATH_MANAGER, CONSOLEKIT_DBUS_INTERFACE_MANAGER, NULL, &error); if (proxy == NULL) { g_warning ("cannot connect to ConsoleKit: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, "HybridSleep", g_variant_new("(b)", TRUE), G_DBUS_CALL_FLAGS_NONE, -1, NULL, consolekit_sleep_cb, NULL); g_object_unref (proxy); } void csd_power_suspend (gboolean try_hybrid, gboolean suspend_then_hibernate) { if (use_logind ()) { if (try_hybrid && can_power_action ("CanHybridSleep")) { logind_hybrid_suspend (); } else { logind_suspend (suspend_then_hibernate); } } else { if (try_hybrid && can_power_action ("CanHybridSleep")) { consolekit_hybrid_suspend (); } else { consolekit_suspend (suspend_then_hibernate); } } } void csd_power_poweroff (void) { if (use_logind ()) { logind_stop (); } else { consolekit_stop (); } } void csd_power_hibernate (void) { if (use_logind ()) { logind_hibernate (); } else { consolekit_hibernate (); } } cinnamon-settings-daemon-5.2.0/plugins/common/meson.build0000664000175000017500000000175414144454032022466 0ustar fabiofabiocommon_sources = [ 'csd-keygrab.c', 'csd-input-helper.c', 'csd-power-helper.c', ] common_deps = [ config_h, gtk, x11, xi, ] common_inc = include_directories('.') common_lib = static_library( 'common_lib', common_sources, include_directories: [include_dirs, common_inc], dependencies: common_deps, ) common_dep = declare_dependency( include_directories: include_dirs, link_with: common_lib, dependencies: common_deps, ) helper_sources = [ 'test-input-helper.c', common_sources, ] executable( 'csd-input-helper', helper_sources, dependencies: common_dep, install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-input-helper') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-input-helper') endif install_data( 'input-device-example.sh', install_dir: join_paths(datadir, '@0@-@1@'.format(pkgname, api_version)), ) cinnamon-settings-daemon-5.2.0/plugins/common/csd-keygrab.h0000664000175000017500000000373414144454032022670 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Jens Granseuer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. */ #ifndef __CSD_COMMON_KEYGRAB_H #define __CSD_COMMON_KEYGRAB_H G_BEGIN_DECLS #include #include #include typedef struct { guint keysym; guint state; guint *keycodes; } Key; typedef enum { CSD_KEYGRAB_NORMAL = 0, CSD_KEYGRAB_ALLOW_UNMODIFIED = 1 << 0, CSD_KEYGRAB_SYNCHRONOUS = 1 << 1 } CsdKeygrabFlags; void grab_key_unsafe (Key *key, CsdKeygrabFlags flags, GSList *screens); void ungrab_key_unsafe (Key *key, GSList *screens); gboolean match_xi2_key (Key *key, XIDeviceEvent *event); gboolean key_uses_keycode (const Key *key, guint keycode); Key * parse_key (const char *str); void free_key (Key *key); void grab_button (int deviceid, gboolean grab, GSList *screens); G_END_DECLS #endif /* __CSD_COMMON_KEYGRAB_H */ cinnamon-settings-daemon-5.2.0/plugins/common/daemon-skeleton.h0000664000175000017500000001634514144454032023564 0ustar fabiofabio/** * Create a test app for your plugin quickly. * * #define NEW csd_media_keys_manager_new * #define START csd_media_keys_manager_start * #define MANAGER CsdMediaKeysManager * #include "csd-media-keys-manager.h" * * #include "daemon-skeleton.h" */ #include "config.h" #include #include #include #include #ifndef PLUGIN_NAME #error Include PLUGIN_CFLAGS in the daemon s CFLAGS #endif /* !PLUGIN_NAME */ #define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager" #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager" #define GNOME_SESSION_CLIENT_PRIVATE_NAME "org.gnome.SessionManager.ClientPrivate" static MANAGER *manager = NULL; static int timeout = -1; static gboolean verbose = FALSE; static GOptionEntry entries[] = { { "exit-time", 0, 0, G_OPTION_ARG_INT, &timeout, "Exit after n seconds time", NULL }, { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose", NULL }, {NULL} }; static void respond_to_end_session (GDBusProxy *proxy) { /* we must answer with "EndSessionResponse" */ g_dbus_proxy_call (proxy, "EndSessionResponse", g_variant_new ("(bs)", TRUE, ""), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); } static void client_proxy_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, gpointer user_data) { if (g_strcmp0 (signal_name, "QueryEndSession") == 0) { g_debug ("Got QueryEndSession signal"); respond_to_end_session (proxy); } else if (g_strcmp0 (signal_name, "EndSession") == 0) { g_debug ("Got EndSession signal"); respond_to_end_session (proxy); } else if (g_strcmp0 (signal_name, "Stop") == 0) { g_debug ("Got Stop signal"); /* Ideally, we would call gtk_main_quit (); here. Instead, do nothing. cinnamon-session-manager doesn't wait in this STOP PHASE. so we're not delaying the logout/shutdown sequence. Also, if another process is lagging and delaying previous phases, we don't want to lose CSD in the background. We want CSD plugins to run until the very very end of the session. */ } } static void on_client_registered (GObject *source_object, GAsyncResult *res, gpointer user_data) { GVariant *variant; GDBusProxy *client_proxy; GError *error = NULL; gchar *object_path = NULL; variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (!variant) { if (error != NULL) { g_warning ("Unable to register client: %s", error->message); g_error_free (error); } return; } g_variant_get (variant, "(o)", &object_path); g_debug ("Registered client at path %s", object_path); client_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, 0, NULL, GNOME_SESSION_DBUS_NAME, object_path, GNOME_SESSION_CLIENT_PRIVATE_NAME, NULL, &error); if (!client_proxy) { if (error != NULL) { g_warning ("Unable to get the session client proxy: %s", error->message); g_error_free (error); } return; } g_signal_connect (client_proxy, "g-signal", G_CALLBACK (client_proxy_signal_cb), NULL); g_free (object_path); g_variant_unref (variant); } static void register_with_cinnamon_session (void) { const char *startup_id; GError *error = NULL; GDBusProxy *proxy; GDBusConnection *bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); if (!bus) { g_debug ("Could not connect to the dbus session bus"); return; } proxy = g_dbus_proxy_new_sync (bus, G_DBUS_PROXY_FLAGS_NONE, NULL, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_PATH, GNOME_SESSION_DBUS_NAME, NULL, &error); g_object_unref (bus); if (proxy == NULL) { if (error != NULL) { g_debug ("Could not connect to the Session manager: %s", error->message); g_error_free (error); } return; } startup_id = g_getenv ("DESKTOP_AUTOSTART_ID"); g_dbus_proxy_call (proxy, "RegisterClient", g_variant_new ("(ss)", PLUGIN_NAME, startup_id ? startup_id : ""), G_DBUS_CALL_FLAGS_NONE, -1, NULL, (GAsyncReadyCallback) on_client_registered, NULL); } int main (int argc, char **argv) { GError *error; gboolean started; bindtextdomain (GETTEXT_PACKAGE, CINNAMON_SETTINGS_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); /* Work around https://bugzilla.gnome.org/show_bug.cgi?id=674885 */ g_type_ensure (G_TYPE_DBUS_CONNECTION); g_type_ensure (G_TYPE_DBUS_PROXY); gdk_set_allowed_backends ("x11"); notify_init ("cinnamon-settings-daemon"); if (FORCE_GDK_SCALE) { g_setenv ("GDK_SCALE", "1", TRUE); } error = NULL; if (! gtk_init_with_args (&argc, &argv, PLUGIN_NAME, entries, NULL, &error)) { if (error != NULL) { fprintf (stderr, "%s\n", error->message); g_error_free (error); } exit (1); } if (FORCE_GDK_SCALE) { g_unsetenv ("GDK_SCALE"); } if (verbose) g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); if (timeout > 0) { guint id; id = g_timeout_add_seconds (timeout, (GSourceFunc) gtk_main_quit, NULL); g_source_set_name_by_id (id, "[cinnamon-settings-daemon] gtk_main_quit"); } manager = NEW (); error = NULL; if (REGISTER_BEFORE_STARTING) { register_with_cinnamon_session (); started = START (manager, &error); } else { started = START (manager, &error); register_with_cinnamon_session (); } if (!started) { if (error != NULL) { fprintf (stderr, "[cinnamon-settings-daemon-%s] Failed to start: %s\n", PLUGIN_NAME, error->message); g_error_free (error); } exit (1); } gtk_main (); STOP (manager); g_object_unref (manager); return 0; } cinnamon-settings-daemon-5.2.0/plugins/common/csd-input-helper.c0000664000175000017500000004354514144454032023657 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include "csd-input-helper.h" #define INPUT_DEVICES_SCHEMA "org.cinnamon.settings-daemon.peripherals.input-devices" #define KEY_HOTPLUG_COMMAND "hotplug-command" typedef gboolean (* InfoIdentifyFunc) (XDeviceInfo *device_info); typedef gboolean (* DeviceIdentifyFunc) (XDevice *xdevice); gboolean device_set_property (XDevice *xdevice, const char *device_name, PropertyHelper *property) { int rc; unsigned long i; Atom prop; Atom realtype; int realformat; unsigned long nitems, bytes_after; unsigned char *data; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), property->name, False); if (!prop) return FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, property->nitems, False, AnyPropertyType, &realtype, &realformat, &nitems, &bytes_after, &data); if (rc != Success || realtype != (Atom)property->type || realformat != property->format || nitems < (unsigned long)property->nitems) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); g_warning ("Error reading property \"%s\" for \"%s\"", property->name, device_name); return FALSE; } for (i = 0; i < nitems; i++) { switch (property->format) { case 8: data[i] = property->data.c[i]; break; case 32: ((long*)data)[i] = property->data.i[i]; break; default: g_warning("device_set_property: default case"); break; } } XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, realtype, realformat, PropModeReplace, data, nitems); XFree (data); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) { g_warning ("Error in setting \"%s\" for \"%s\"", property->name, device_name); return FALSE; } return TRUE; } static gboolean supports_xinput_devices_with_opcode (int *opcode) { gint op_code, event, error; gboolean retval; retval = XQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "XInputExtension", &op_code, &event, &error); if (opcode) *opcode = op_code; return retval; } gboolean supports_xinput_devices (void) { return supports_xinput_devices_with_opcode (NULL); } gboolean supports_xtest (void) { gint op_code, event, error; gboolean retval; retval = XQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "XTEST", &op_code, &event, &error); return retval; } gboolean supports_xinput2_devices (int *opcode) { int major, minor; if (supports_xinput_devices_with_opcode (opcode) == FALSE) return FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); major = 2; #ifdef XI_23 minor = 3; #else minor = 0; #endif if (XIQueryVersion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &major, &minor) != Success) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); #ifndef XI_23 /* try for 2.2, maybe gtk has already announced 2.2 support */ gdk_x11_display_error_trap_push (gdk_display_get_default ()); major = 2; minor = 2; if (XIQueryVersion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &major, &minor) != Success) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); return FALSE; } #else return FALSE; #endif } gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); if ((major * 1000 + minor) < (2000)) return FALSE; return TRUE; } gboolean device_is_touchpad (XDevice *xdevice) { Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char *data; const char *names[] = { "libinput Tapping Enabled", /* we don't check on the type being XI_TOUCHPAD here, * but having a "Synaptics Off" property should be enough */ "Synaptics Off", NULL, }; const char **name = names; do { prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), *name, True); if (prop) { gdk_x11_display_error_trap_push (gdk_display_get_default ()); if ((XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data) == Success) && (realtype != None)) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); XFree (data); return TRUE; } gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); } name++; } while (*name); return FALSE; } gboolean device_info_is_touchpad (XDeviceInfo *device_info) { return (device_info->type == XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_TOUCHPAD, False)); } gboolean device_info_is_touchscreen (XDeviceInfo *device_info) { return (device_info->type == XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_TOUCHSCREEN, False)); } gboolean device_info_is_tablet (XDeviceInfo *device_info) { /* Note that this doesn't match Wacom tablets */ return (device_info->type == XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_TABLET, False)); } gboolean device_info_is_mouse (XDeviceInfo *device_info) { return (device_info->type == XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_MOUSE, False)); } gboolean device_info_is_trackball (XDeviceInfo *device_info) { gboolean retval; retval = (device_info->type == XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XI_TRACKBALL, False)); if (retval == FALSE && device_info->name != NULL) { char *lowercase; lowercase = g_ascii_strdown (device_info->name, -1); retval = strstr (lowercase, "trackball") != NULL; g_free (lowercase); } return retval; } static gboolean device_type_is_present (InfoIdentifyFunc info_func, DeviceIdentifyFunc device_func) { XDeviceInfo *device_info; gint n_devices,i; gboolean retval; if (supports_xinput_devices () == FALSE) return TRUE; retval = FALSE; device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return FALSE; for (i = 0; i < n_devices; i++) { XDevice *device; /* Check with the device info first */ retval = (info_func) (&device_info[i]); if (retval == FALSE) continue; /* If we only have an info func, we're done checking */ if (device_func == NULL) break; gdk_x11_display_error_trap_push (gdk_display_get_default ()); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) || (device == NULL)) continue; retval = (device_func) (device); if (retval) { xdevice_close (device); break; } xdevice_close (device); } XFreeDeviceList (device_info); return retval; } gboolean touchscreen_is_present (void) { return device_type_is_present (device_info_is_touchscreen, NULL); } gboolean touchpad_is_present (void) { return device_type_is_present (device_info_is_touchpad, device_is_touchpad); } gboolean mouse_is_present (void) { return device_type_is_present (device_info_is_mouse, NULL); } gboolean trackball_is_present (void) { return device_type_is_present (device_info_is_trackball, NULL); } char * xdevice_get_device_node (int deviceid) { Atom prop; Atom act_type; int act_format; unsigned long nitems, bytes_after; unsigned char *data; char *ret; gdk_display_sync (gdk_display_get_default ()); prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Device Node", False); if (!prop) return NULL; gdk_x11_display_error_trap_push (gdk_display_get_default ()); if (!XIGetProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceid, prop, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) == Success) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); return NULL; } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) goto out; if (nitems == 0) goto out; if (act_type != XA_STRING) goto out; /* Unknown string format */ if (act_format != 8) goto out; ret = g_strdup ((char *) data); XFree (data); return ret; out: XFree (data); return NULL; } #define TOOL_ID_FORMAT_SIZE 32 static int get_id_for_index (guchar *data, guint idx) { guchar *ptr; int id; ptr = data; ptr += TOOL_ID_FORMAT_SIZE / 8 * idx; id = *((int32_t*)ptr); id = id & 0xfffff; return id; } #define STYLUS_DEVICE_ID 0x02 #define ERASER_DEVICE_ID 0x0A int xdevice_get_last_tool_id (int deviceid) { Atom prop; Atom act_type; int act_format; unsigned long nitems, bytes_after; unsigned char *data; int id; id = -1; gdk_display_sync (gdk_display_get_default ()); prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), WACOM_SERIAL_IDS_PROP, False); if (!prop) return -1; data = NULL; gdk_x11_display_error_trap_push (gdk_display_get_default ()); if (XIGetProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceid, prop, 0, 1000, False, AnyPropertyType, &act_type, &act_format, &nitems, &bytes_after, &data) != Success) { gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); goto out; } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) goto out; if (nitems != 4 && nitems != 5) goto out; if (act_type != XA_INTEGER) goto out; if (act_format != TOOL_ID_FORMAT_SIZE) goto out; /* item 0 = tablet ID * item 1 = old device serial number (== last tool in proximity) * item 2 = old hardware serial number (including tool ID) * item 3 = current serial number (0 if no tool in proximity) * item 4 = current tool ID (since Feb 2012) * * Get the current tool ID first, if available, then the old one */ id = 0x0; if (nitems == 5) id = get_id_for_index (data, 4); if (id == 0x0) id = get_id_for_index (data, 2); /* That means that no tool was set down yet */ if (id == STYLUS_DEVICE_ID || id == ERASER_DEVICE_ID) id = 0x0; out: if (data != NULL) XFree (data); return id; } gboolean set_device_enabled (int device_id, gboolean enabled) { Atom prop; guchar value; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Device Enabled", False); if (!prop) return FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); value = enabled ? 1 : 0; XIChangeProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_id, prop, XA_INTEGER, 8, PropModeReplace, &value, 1); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) return FALSE; return TRUE; } static const char * custom_command_to_string (CustomCommand command) { switch (command) { case COMMAND_DEVICE_ADDED: return "added"; case COMMAND_DEVICE_REMOVED: return "removed"; case COMMAND_DEVICE_PRESENT: return "present"; default: g_assert_not_reached (); } } /* Run a custom command on device presence events. Parameters passed into * the custom command are: * command -t [added|removed|present] -i * Type 'added' and 'removed' signal 'device added' and 'device removed', * respectively. Type 'present' signals 'device present at * cinnamon-settings-daemon init'. * * The script is expected to run synchronously, and an exit value * of "1" means that no other settings will be applied to this * particular device. * * More options may be added in the future. * * This function returns TRUE if we should not apply any more settings * to the device. */ gboolean run_custom_command (GdkDevice *device, CustomCommand command) { GSettings *settings; char *cmd; char *argv[7]; int exit_status; gboolean rc; int id; settings = g_settings_new (INPUT_DEVICES_SCHEMA); cmd = g_settings_get_string (settings, KEY_HOTPLUG_COMMAND); g_object_unref (settings); if (!cmd || cmd[0] == '\0') { g_free (cmd); return FALSE; } /* Easter egg! */ g_object_get (device, "device-id", &id, NULL); argv[0] = cmd; argv[1] = (char *)"-t"; argv[2] = (char *) custom_command_to_string (command); argv[3] = (char *)"-i"; argv[4] = g_strdup_printf ("%d", id); argv[5] = g_strdup_printf ("%s", gdk_device_get_name (device)); argv[6] = NULL; rc = g_spawn_sync (g_get_home_dir (), argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, &exit_status, NULL); if (rc == FALSE) g_warning ("Couldn't execute command '%s', verify that this is a valid command.", cmd); g_free (argv[0]); g_free (argv[4]); g_free (argv[5]); return (exit_status == 0); } GList * get_disabled_devices (GdkDeviceManager *manager) { XDeviceInfo *device_info; gint n_devices; gint i; GList *ret; ret = NULL; device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return ret; for (i = 0; i < n_devices; i++) { GdkDevice *device; /* Ignore core devices */ if (device_info[i].use == IsXKeyboard || device_info[i].use == IsXPointer) continue; /* Check whether the device is actually available */ device = gdk_x11_device_manager_lookup (manager, device_info[i].id); if (device != NULL) continue; ret = g_list_prepend (ret, GINT_TO_POINTER (device_info[i].id)); } XFreeDeviceList (device_info); return ret; } void xdevice_close (XDevice *xdevice) { gdk_x11_display_error_trap_push (gdk_display_get_default ()); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice); gdk_x11_display_error_trap_pop_ignored(gdk_display_get_default ()); } cinnamon-settings-daemon-5.2.0/plugins/common/input-device-example.sh0000664000175000017500000000301414144454032024674 0ustar fabiofabio#!/bin/sh # # This script is an example hotplug script for use with the various # input devices plugins. # # The script is called with the arguments: # -t [added|present|removed] # added ... device was just plugged in # present.. device was present at cinnamon-settings-daemon startup # removed.. device was just removed # -i # device ID being the XInput device ID # The name of the device # # The script should return 0 if the device is to be # ignored from future configuration. # # Set the script to be used with: # gsettings set org.cinnamon.settings-daemon.peripherals.input-devices hotplug-command /path/to/script/input-devices.sh # args=`getopt "t:i:" $*` set -- $args while [ $# -gt 0 ] do case $1 in -t) shift; type="$1" ;; -i) shift; id="$1" ;; --) shift; device="$@" break; ;; *) echo "Unknown option $1"; exit 1 ;; esac shift done retval=0 case $type in added) echo "Device '$device' (ID=$id) was added" ;; present) echo "Device '$device' (ID=$id) was already present at startup" ;; removed) echo "Device '$device' (ID=$id) was removed" ;; *) echo "Unknown operation" retval=1 ;; esac # All further processing will be disabled if $retval == 0 exit $retval cinnamon-settings-daemon-5.2.0/plugins/common/test-input-helper.c0000664000175000017500000000707014144454032024056 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2011 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include "csd-input-helper.h" static void print_disabled_devices (void) { GList *devices, *l; GdkDeviceManager *manager; manager = gdk_display_get_device_manager (gdk_display_get_default ()); devices = get_disabled_devices (manager); g_print ("Disabled devices:\t\t\t"); if (devices == NULL) { g_print ("no\n"); return; } for (l = devices; l != NULL; l = l->next) { g_print ("%d ", GPOINTER_TO_INT (l->data)); } g_list_free (devices); g_print ("\n"); } int main (int argc, char **argv) { gboolean supports_xinput; gboolean has_touchpad, has_touchscreen; XDeviceInfo *device_info; gint n_devices, opcode, i; gtk_init (&argc, &argv); supports_xinput = supports_xinput_devices (); if (supports_xinput) { g_print ("Supports XInput:\t\t\tyes\n"); } else { g_print ("Supports XInput:\t\t\tno\n"); return 0; } supports_xinput = supports_xinput2_devices (&opcode); if (supports_xinput) { g_print ("Supports XInput2:\t\t\tyes (opcode: %d)\n", opcode); } else { g_print ("Supports XInput2:\t\t\tno\n"); return 0; } has_touchpad = touchpad_is_present (); g_print ("Has touchpad:\t\t\t\t%s\n", has_touchpad ? "yes" : "no"); has_touchscreen = touchscreen_is_present (); g_print ("Has touchscreen:\t\t\t%s\n", has_touchscreen ? "yes" : "no"); device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) { g_warning ("Has no input devices"); return 1; } print_disabled_devices (); for (i = 0; i < n_devices; i++) { XDevice *device; if (device_info_is_touchscreen (&device_info[i])) { g_print ("Device %d is touchscreen:\t\t%s\n", (int) device_info[i].id, "yes"); continue; } gdk_x11_display_error_trap_push (gdk_display_get_default ()); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) || (device == NULL)) continue; if (device_is_touchpad (device)) g_print ("Device %d is touchpad:\t\t%s\n", (int) device_info[i].id, "yes"); else { int tool_id; tool_id = xdevice_get_last_tool_id (device_info[i].id); if (tool_id >= 0x0) g_print ("Device %d is touchpad/touchscreen:\t%s (tool ID: 0x%x)\n", (int) device_info[i].id, "no", tool_id); else g_print ("Device %d is touchpad/touchscreen:\t%s\n", (int) device_info[i].id, "no"); } xdevice_close (device); } XFreeDeviceList (device_info); return 0; } cinnamon-settings-daemon-5.2.0/plugins/common/csd-keygrab.c0000664000175000017500000003264714144454032022670 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2001-2003 Bastien Nocera * Copyright (C) 2006-2007 William Jon McCann * Copyright (C) 2008 Jens Granseuer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include "csd-keygrab.h" /* these are the mods whose combinations are ignored by the keygrabbing code */ static GdkModifierType csd_ignored_mods = 0; /* these are the ones we actually use for global keys, we always only check * for these set */ static GdkModifierType csd_used_mods = 0; /* Taken from a comment in XF86keysym.h */ #define XF86KEYS_RANGE_MIN 0x10080001 #define XF86KEYS_RANGE_MAX 0x1008FFFF #define FKEYS_RANGE_MIN GDK_KEY_F1 #define FKEYS_RANGE_MAX GDK_KEY_R15 #define IN_RANGE(x, min, max) (x >= min && x <= max) static void setup_modifiers (void) { if (csd_used_mods == 0 || csd_ignored_mods == 0) { GdkModifierType dynmods; /* default modifiers */ csd_ignored_mods = \ 0x2000 /*Xkb modifier*/ | GDK_LOCK_MASK | GDK_HYPER_MASK; csd_used_mods = \ GDK_SHIFT_MASK | GDK_CONTROL_MASK |\ GDK_MOD1_MASK | GDK_MOD2_MASK | GDK_MOD3_MASK | GDK_MOD4_MASK |\ GDK_MOD5_MASK | GDK_SUPER_MASK | GDK_META_MASK; /* NumLock can be assigned to varying keys so we need to * resolve and ignore it specially */ dynmods = XkbKeysymToModifiers (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), GDK_KEY_Num_Lock); csd_ignored_mods |= dynmods; csd_used_mods &= ~dynmods; } } static void grab_key_real (guint keycode, GdkWindow *root, gboolean grab, gboolean synchronous, XIGrabModifiers *mods, int num_mods) { XIEventMask evmask; unsigned char mask[(XI_LASTEVENT + 7)/8]; memset (mask, 0, sizeof (mask)); XISetMask (mask, XI_KeyPress); XISetMask (mask, XI_KeyRelease); evmask.deviceid = XIAllMasterDevices; evmask.mask_len = sizeof (mask); evmask.mask = mask; if (grab) { XIGrabKeycode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XIAllMasterDevices, keycode, GDK_WINDOW_XID (root), GrabModeAsync, synchronous ? GrabModeSync : GrabModeAsync, False, &evmask, num_mods, mods); } else { XIUngrabKeycode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XIAllMasterDevices, keycode, GDK_WINDOW_XID (root), num_mods, mods); } } /* Grab the key. In order to ignore CSD_IGNORED_MODS we need to grab * all combinations of the ignored modifiers and those actually used * for the binding (if any). * * inspired by all_combinations from gnome-panel/gnome-panel/global-keys.c * * This may generate X errors. The correct way to use this is like: * * gdk_x11_display_error_trap_push (gdk_display_get_default ()); * * grab_key_unsafe (key, grab, screens); * * gdk_flush (); * if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) * g_warning ("Grab failed, another application may already have access to key '%u'", * key->keycode); * * This is not done in the function itself, to allow doing multiple grab_key * operations with one flush only. */ #define N_BITS 32 static void grab_key_internal (Key *key, gboolean grab, CsdKeygrabFlags flags, GSList *screens) { int indexes[N_BITS]; /* indexes of bits we need to flip */ int i; int bit; int bits_set_cnt; int uppervalue; guint mask, modifiers; GArray *all_mods; GSList *l; setup_modifiers (); mask = csd_ignored_mods & ~key->state & GDK_MODIFIER_MASK; /* XGrabKey requires real modifiers, not virtual ones */ modifiers = key->state; gdk_keymap_map_virtual_modifiers (gdk_keymap_get_default (), &modifiers); modifiers &= ~(GDK_META_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK); /* If key doesn't have a usable modifier, we don't want * to grab it, since the user might lose a useful key. * * The exception is the XFree86 keys and the Function keys * (which are useful to grab without a modifier). */ if (!(flags & CSD_KEYGRAB_ALLOW_UNMODIFIED) && (modifiers & csd_used_mods) == 0 && !IN_RANGE(key->keysym, XF86KEYS_RANGE_MIN, XF86KEYS_RANGE_MAX) && !IN_RANGE(key->keysym, FKEYS_RANGE_MIN, FKEYS_RANGE_MAX) && key->keysym != GDK_KEY_Pause && key->keysym != GDK_KEY_Print && key->keysym != GDK_KEY_Scroll_Lock && key->keysym != GDK_KEY_Break && key->keysym != GDK_KEY_Menu) { GString *keycodes; keycodes = g_string_new (""); if (key->keycodes != NULL) { guint *c; for (c = key->keycodes; *c; ++c) { g_string_printf (keycodes, " %u", *c); } } g_warning ("Key 0x%x (keycodes: %s) with state 0x%x (resolved to 0x%x) " " has no usable modifiers (usable modifiers are 0x%x)", key->keysym, keycodes->str, key->state, modifiers, csd_used_mods); g_string_free (keycodes, TRUE); return; } bit = 0; /* store the indexes of all set bits in mask in the array */ for (i = 0; mask; ++i, mask >>= 1) { if (mask & 0x1) { indexes[bit++] = i; } } bits_set_cnt = bit; all_mods = g_array_new (FALSE, TRUE, sizeof(XIGrabModifiers)); uppervalue = 1 << bits_set_cnt; /* store all possible modifier combinations for our mask into all_mods */ for (i = 0; i < uppervalue; ++i) { int j; int result = 0; XIGrabModifiers *mod; /* map bits in the counter to those in the mask */ for (j = 0; j < bits_set_cnt; ++j) { if (i & (1 << j)) { result |= (1 << indexes[j]); } } /* Grow the array by one, to fit our new XIGrabModifiers item */ g_array_set_size (all_mods, all_mods->len + 1); mod = &g_array_index (all_mods, XIGrabModifiers, all_mods->len - 1); mod->modifiers = result | modifiers; } /* Capture the actual keycodes with the modifier array */ for (l = screens; l; l = l->next) { GdkScreen *screen = l->data; guint *code; for (code = key->keycodes; *code; ++code) { grab_key_real (*code, gdk_screen_get_root_window (screen), grab, flags & CSD_KEYGRAB_SYNCHRONOUS, (XIGrabModifiers *) all_mods->data, all_mods->len); } } g_array_free (all_mods, TRUE); } void grab_key_unsafe (Key *key, CsdKeygrabFlags flags, GSList *screens) { grab_key_internal (key, TRUE, flags, screens); } void ungrab_key_unsafe (Key *key, GSList *screens) { grab_key_internal (key, FALSE, 0, screens); } static gboolean have_xkb (Display *dpy) { static int have_xkb = -1; if (have_xkb == -1) { int opcode, error_base, major, minor, xkb_event_base; have_xkb = XkbQueryExtension (dpy, &opcode, &xkb_event_base, &error_base, &major, &minor) && XkbUseExtension (dpy, &major, &minor); } return have_xkb; } gboolean key_uses_keycode (const Key *key, guint keycode) { if (key->keycodes != NULL) { guint *c; for (c = key->keycodes; *c; ++c) { if (*c == keycode) return TRUE; } } return FALSE; } /* Adapted from _gdk_x11_device_xi2_translate_state() * in gtk+/gdk/x11/gdkdevice-xi2.c */ static guint device_xi2_translate_state (XIModifierState *mods_state, XIGroupState *group_state) { guint state; gint group; state = (guint) mods_state->base | mods_state->latched | mods_state->locked; group = group_state->base | group_state->latched | group_state->locked; /* FIXME: do we need the XKB complications for this ? */ group = CLAMP(group, 0, 3); state |= group << 13; return state; } gboolean match_xi2_key (Key *key, XIDeviceEvent *event) { guint keyval; GdkModifierType consumed; gint group; guint keycode, state; if (key == NULL) return FALSE; setup_modifiers (); state = device_xi2_translate_state (&event->mods, &event->group); if (have_xkb (event->display)) group = XkbGroupForCoreState (state); else group = (state & GDK_KEY_Mode_switch) ? 1 : 0; keycode = event->detail; /* Check if we find a keysym that matches our current state */ if (gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (), keycode, state, group, &keyval, NULL, NULL, &consumed)) { guint lower, upper; guint mask; /* HACK: we don't want to use SysRq as a keybinding, so we avoid * its translation from Alt+Print. */ if (keyval == GDK_KEY_Sys_Req && (state & GDK_MOD1_MASK) != 0) { consumed = 0; keyval = GDK_KEY_Print; } /* The Key structure contains virtual modifiers, whereas * the XEvent will be using the real modifier, so translate those */ mask = key->state; gdk_keymap_map_virtual_modifiers (gdk_keymap_get_default (), &mask); mask &= ~(GDK_META_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK); gdk_keyval_convert_case (keyval, &lower, &upper); /* If we are checking against the lower version of the * keysym, we might need the Shift state for matching, * so remove it from the consumed modifiers */ if (lower == key->keysym) consumed &= ~GDK_SHIFT_MASK; return ((lower == key->keysym || upper == key->keysym) && (state & ~consumed & csd_used_mods) == mask); } /* The key we passed doesn't have a keysym, so try with just the keycode */ return (key != NULL && key->state == (state & csd_used_mods) && key_uses_keycode (key, keycode)); } Key * parse_key (const char *str) { Key *key; if (str == NULL || *str == '\0' || g_str_equal (str, "disabled")) { return NULL; } key = g_new0 (Key, 1); gtk_accelerator_parse_with_keycode (str, &key->keysym, &key->keycodes, &key->state); if (key->keysym == 0 && key->keycodes == NULL && key->state == 0) { g_free (key); return NULL; } return key; } void free_key (Key *key) { if (key == NULL) return; g_free (key->keycodes); g_free (key); } static void grab_button_real (int deviceid, gboolean grab, GdkWindow *root) { XIGrabModifiers mods; mods.modifiers = XIAnyModifier; if (grab) { XIEventMask evmask; unsigned char mask[(XI_LASTEVENT + 7)/8]; memset (mask, 0, sizeof (mask)); XISetMask (mask, XI_ButtonRelease); XISetMask (mask, XI_ButtonPress); evmask.deviceid = deviceid; evmask.mask_len = sizeof (mask); evmask.mask = mask; XIGrabButton (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceid, XIAnyButton, GDK_WINDOW_XID (root), None, GrabModeAsync, GrabModeAsync, False, &evmask, 1, &mods); } else { XIUngrabButton (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), deviceid, XIAnyButton, GDK_WINDOW_XID (root), 1, &mods); } } void grab_button (int deviceid, gboolean grab, GSList *screens) { GSList *l; for (l = screens; l; l = l->next) { GdkScreen *screen = l->data; grab_button_real (deviceid, grab, gdk_screen_get_root_window (screen)); } } cinnamon-settings-daemon-5.2.0/plugins/common/csd-input-helper.h0000664000175000017500000000652414144454032023660 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. */ #ifndef __CSD_INPUT_HELPER_H #define __CSD_INPUT_HELPER_H G_BEGIN_DECLS #include #include #include #define WACOM_SERIAL_IDS_PROP "Wacom Serial IDs" typedef enum { COMMAND_DEVICE_ADDED, COMMAND_DEVICE_REMOVED, COMMAND_DEVICE_PRESENT } CustomCommand; /* Generic property setting code. Fill up the struct property with the property * data and pass it into device_set_property together with the device to be * changed. Note: doesn't cater for non-zero offsets yet, but we don't have * any settings that require that. */ typedef struct { const char *name; /* property name */ gint nitems; /* number of items in data */ gint format; /* CARD8 or CARD32 sized-items */ gint type; /* Atom representing data type */ union { const gchar *c; /* 8 bit data */ const gint *i; /* 32 bit data */ } data; } PropertyHelper; gboolean supports_xinput_devices (void); gboolean supports_xinput2_devices (int *opcode); gboolean supports_xtest (void); gboolean set_device_enabled (int device_id, gboolean enabled); gboolean device_is_touchpad (XDevice *xdevice); gboolean device_info_is_touchpad (XDeviceInfo *device_info); gboolean device_info_is_touchscreen (XDeviceInfo *device_info); gboolean device_info_is_tablet (XDeviceInfo *device_info); gboolean device_info_is_mouse (XDeviceInfo *device_info); gboolean device_info_is_trackball (XDeviceInfo *device_info); gboolean touchpad_is_present (void); gboolean touchscreen_is_present (void); gboolean mouse_is_present (void); gboolean trackball_is_present (void); gboolean device_set_property (XDevice *xdevice, const char *device_name, PropertyHelper *property); gboolean run_custom_command (GdkDevice *device, CustomCommand command); GList * get_disabled_devices (GdkDeviceManager *manager); char * xdevice_get_device_node (int deviceid); int xdevice_get_last_tool_id (int deviceid); void xdevice_close (XDevice *xdevice); G_END_DECLS #endif /* __CSD_INPUT_HELPER_H */ cinnamon-settings-daemon-5.2.0/plugins/sound/0000775000175000017500000000000014144454032020155 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/sound/meson.build0000664000175000017500000000147014144454032022321 0ustar fabiofabioplugin_name = 'sound' sound_sources = [ 'csd-sound-manager.c', 'main.c', ] sound_deps = [ canberra, common_dep, csd_dep, gudev, libnotify, pulse_glib, pulse, ] executable( 'csd-sound', sound_sources, include_directories: [include_dirs, common_inc], dependencies: sound_deps, c_args: [ '-DPLUGIN_NAME="@0@"'.format(plugin_name), ], install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-sound') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-sound') endif configure_file( input: 'cinnamon-settings-daemon-sound.desktop.in', output: 'cinnamon-settings-daemon-sound.desktop', configuration: desktop_conf, install_dir: autostartdir, ) cinnamon-settings-daemon-5.2.0/plugins/sound/csd-sound-manager.c0000664000175000017500000005120314144454032023631 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Lennart Poettering * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "csd-sound-manager.h" #include "cinnamon-settings-profile.h" #define CSD_SOUND_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_SOUND_MANAGER, CsdSoundManagerPrivate)) #define SOUND_HANDLER_DBUS_PATH "/org/cinnamon/SettingsDaemon/Sound" #define SOUND_HANDLER_DBUS_NAME "org.cinnamon.SettingsDaemon.Sound" #define PLAY_ONCE_FLAG 8675309 static const gchar introspection_xml[] = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; struct CsdSoundManagerPrivate { GSettings *settings; guint name_id; GList *monitors; guint timeout; GDBusNodeInfo *idata; ca_context *ca; GCancellable *bus_cancellable; GDBusConnection *connection; /* DBus users pass an ID with the sound string * We can use this as a flag also to denote a sound * that we only ever want played once (i.e. initial desktop * welcome sound) */ GList *onetime_sounds; }; static void csd_sound_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdSoundManager, csd_sound_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static gboolean should_play (CsdSoundManager *manager, guint id, const gchar *str) { if (id != PLAY_ONCE_FLAG) return TRUE; GList *l; gboolean already_ran = FALSE; for (l = manager->priv->onetime_sounds; l; l = l->next) { if (g_strcmp0 (l->data, str) == 0) { already_ran = TRUE; break; } } if (!already_ran) { manager->priv->onetime_sounds = g_list_prepend (manager->priv->onetime_sounds, g_strdup (str)); } return !already_ran; } static void handle_sound_request (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { CsdSoundManager *manager = (CsdSoundManager *) user_data; g_debug ("Calling method '%s' for sound", method_name); if (g_strcmp0 (method_name, "PlaySound") == 0) { const char *sound_name; guint id; g_variant_get (parameters, "(u&s)", &id, &sound_name); if (should_play (manager, id, sound_name)) { ca_context_play (manager->priv->ca, id == PLAY_ONCE_FLAG ? 0 : id, CA_PROP_EVENT_ID, sound_name, CA_PROP_CANBERRA_CACHE_CONTROL, id == PLAY_ONCE_FLAG ? "never" : "volatile", NULL); } g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "PlaySoundWithChannel") == 0) { const char *sound_name; const char *channel_name; guint id; g_variant_get (parameters, "(u&s&s)", &id, &sound_name, &channel_name); if (should_play (manager, id, sound_name)) { ca_context_play (manager->priv->ca, id == PLAY_ONCE_FLAG ? 0 : id, CA_PROP_EVENT_ID, sound_name, CA_PROP_MEDIA_ROLE, "test", CA_PROP_CANBERRA_FORCE_CHANNEL, channel_name, NULL); } g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "PlaySoundFile") == 0) { const char *sound_file; guint id; g_variant_get (parameters, "(u&s)", &id, &sound_file); if (should_play (manager, id, sound_file)) { ca_context_play (manager->priv->ca, id == PLAY_ONCE_FLAG ? 0 : id, CA_PROP_MEDIA_FILENAME, sound_file, CA_PROP_CANBERRA_CACHE_CONTROL, id == PLAY_ONCE_FLAG ? "never" : "volatile", NULL); } g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "PlaySoundFileVolume") == 0) { const char *sound_file; guint id; const char *volume; g_variant_get (parameters, "(u&s&s)", &id, &sound_file, &volume); if (should_play (manager, id, sound_file)) { ca_context_play (manager->priv->ca, id == PLAY_ONCE_FLAG ? 0 : id, CA_PROP_MEDIA_FILENAME, sound_file, CA_PROP_CANBERRA_VOLUME, volume, CA_PROP_CANBERRA_CACHE_CONTROL, id == PLAY_ONCE_FLAG ? "never" : "volatile", NULL); } g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "CancelSound") == 0) { guint id; g_variant_get (parameters, "(u)", &id); ca_context_cancel (manager->priv->ca, id); g_dbus_method_invocation_return_value (invocation, NULL); } } static const GDBusInterfaceVTable interface_vtable = { handle_sound_request, NULL, /* Get Property */ NULL, /* Set Property */ }; static void sample_info_cb (pa_context *c, const pa_sample_info *i, int eol, void *userdata) { pa_operation *o; if (!i) return; g_debug ("Found sample %s", i->name); /* We only flush those samples which have an XDG sound name * attached, because only those originate from themeing */ if (!(pa_proplist_gets (i->proplist, PA_PROP_EVENT_ID))) return; g_debug ("Dropping sample %s from cache", i->name); if (!(o = pa_context_remove_sample (c, i->name, NULL, NULL))) { g_debug ("pa_context_remove_sample (): %s", pa_strerror (pa_context_errno (c))); return; } pa_operation_unref (o); /* We won't wait until the operation is actually executed to * speed things up a bit.*/ } static void flush_cache (void) { pa_mainloop *ml = NULL; pa_context *c = NULL; pa_proplist *pl = NULL; pa_operation *o = NULL; g_debug ("Flushing sample cache"); if (!(ml = pa_mainloop_new ())) { g_debug ("Failed to allocate pa_mainloop"); goto fail; } if (!(pl = pa_proplist_new ())) { g_debug ("Failed to allocate pa_proplist"); goto fail; } pa_proplist_sets (pl, PA_PROP_APPLICATION_NAME, PACKAGE_NAME); pa_proplist_sets (pl, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION); pa_proplist_sets (pl, PA_PROP_APPLICATION_ID, "org.cinnamon.SettingsDaemon.Sound"); if (!(c = pa_context_new_with_proplist (pa_mainloop_get_api (ml), PACKAGE_NAME, pl))) { g_debug ("Failed to allocate pa_context"); goto fail; } pa_proplist_free (pl); pl = NULL; if (pa_context_connect (c, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) { g_debug ("pa_context_connect(): %s", pa_strerror (pa_context_errno (c))); goto fail; } /* Wait until the connection is established */ while (pa_context_get_state (c) != PA_CONTEXT_READY) { if (!PA_CONTEXT_IS_GOOD (pa_context_get_state (c))) { g_debug ("Connection failed: %s", pa_strerror (pa_context_errno (c))); goto fail; } if (pa_mainloop_iterate (ml, TRUE, NULL) < 0) { g_debug ("pa_mainloop_iterate() failed"); goto fail; } } /* Enumerate all cached samples */ if (!(o = pa_context_get_sample_info_list (c, sample_info_cb, NULL))) { g_debug ("pa_context_get_sample_info_list(): %s", pa_strerror (pa_context_errno (c))); goto fail; } /* Wait until our operation is finished and there's nothing * more queued to send to the server */ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING || pa_context_is_pending (c)) { if (!PA_CONTEXT_IS_GOOD (pa_context_get_state (c))) { g_debug ("Connection failed: %s", pa_strerror (pa_context_errno (c))); goto fail; } if (pa_mainloop_iterate (ml, TRUE, NULL) < 0) { g_debug ("pa_mainloop_iterate() failed"); goto fail; } } g_debug ("Sample cache flushed"); fail: if (o) { pa_operation_cancel (o); pa_operation_unref (o); } if (c) { pa_context_disconnect (c); pa_context_unref (c); } if (pl) pa_proplist_free (pl); if (ml) pa_mainloop_free (ml); } static gboolean flush_cb (CsdSoundManager *manager) { flush_cache (); manager->priv->timeout = 0; return FALSE; } static void trigger_flush (CsdSoundManager *manager) { if (manager->priv->timeout) { g_source_remove (manager->priv->timeout); manager->priv->timeout = 0; } /* We delay the flushing a bit so that we can coalesce * multiple changes into a single cache flush */ manager->priv->timeout = g_timeout_add (500, (GSourceFunc) flush_cb, manager); } static void settings_changed_cb (GSettings *settings, const char *key, CsdSoundManager *manager) { trigger_flush (manager); } static void register_config_callback (CsdSoundManager *manager) { manager->priv->settings = g_settings_new ("org.cinnamon.desktop.sound"); g_signal_connect (G_OBJECT (manager->priv->settings), "changed", G_CALLBACK (settings_changed_cb), manager); } static void file_monitor_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event, CsdSoundManager *manager) { g_debug ("Theme dir changed"); trigger_flush (manager); } static gboolean register_directory_callback (CsdSoundManager *manager, const char *path, GError **error) { GFile *f; GFileMonitor *m; gboolean succ = FALSE; g_debug ("Registering directory monitor for %s", path); f = g_file_new_for_path (path); m = g_file_monitor_directory (f, 0, NULL, error); if (m != NULL) { g_signal_connect (m, "changed", G_CALLBACK (file_monitor_changed_cb), manager); manager->priv->monitors = g_list_prepend (manager->priv->monitors, m); succ = TRUE; } g_object_unref (f); return succ; } static void on_bus_gotten (GObject *source_object, GAsyncResult *res, CsdSoundManager *manager) { GDBusConnection *connection; GError *error = NULL; if (manager->priv->bus_cancellable == NULL || g_cancellable_is_cancelled (manager->priv->bus_cancellable)) { g_warning ("Operation has been cancelled, so not retrieving session bus"); return; } connection = g_bus_get_finish (res, &error); if (connection == NULL) { g_warning ("Could not get session bus: %s", error->message); g_error_free (error); return; } manager->priv->connection = connection; g_dbus_connection_register_object (connection, SOUND_HANDLER_DBUS_PATH, manager->priv->idata->interfaces[0], &interface_vtable, manager, NULL, NULL); manager->priv->name_id = g_bus_own_name_on_connection (connection, SOUND_HANDLER_DBUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL); } gboolean csd_sound_manager_start (CsdSoundManager *manager, GError **error) { char *p, **ps, **k; const char *env, *dd; g_debug ("Starting sound manager"); cinnamon_settings_profile_start (NULL); /* We listen for change of the selected theme ... */ register_config_callback (manager); /* ... and we listen to changes of the theme base directories * in $HOME ...*/ if ((env = g_getenv ("XDG_DATA_HOME")) && *env == '/') p = g_build_filename (env, "sounds", NULL); else if (((env = g_getenv ("HOME")) && *env == '/') || (env = g_get_home_dir ())) p = g_build_filename (env, ".local", "share", "sounds", NULL); else p = NULL; if (p) { register_directory_callback (manager, p, NULL); g_free (p); } /* ... and globally. */ if (!(dd = g_getenv ("XDG_DATA_DIRS")) || *dd == 0) dd = "/usr/local/share:/usr/share"; ps = g_strsplit (dd, ":", 0); for (k = ps; *k; ++k) register_directory_callback (manager, *k, NULL); g_strfreev (ps); manager->priv->onetime_sounds = NULL; /* Sound events */ ca_context_create (&manager->priv->ca); ca_context_set_driver (manager->priv->ca, "pulse"); ca_context_change_props (manager->priv->ca, 0, CA_PROP_APPLICATION_ID, "org.Cinnamon.Sound", NULL); manager->priv->idata = g_dbus_node_info_new_for_xml (introspection_xml, NULL); manager->priv->bus_cancellable = g_cancellable_new (); g_assert (manager->priv->idata != NULL); g_bus_get (G_BUS_TYPE_SESSION, manager->priv->bus_cancellable, (GAsyncReadyCallback) on_bus_gotten, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_sound_manager_stop (CsdSoundManager *manager) { g_debug ("Stopping sound manager"); if (manager->priv->settings != NULL) { g_object_unref (manager->priv->settings); manager->priv->settings = NULL; } if (manager->priv->timeout) { g_source_remove (manager->priv->timeout); manager->priv->timeout = 0; } if (manager->priv->bus_cancellable != NULL) { g_cancellable_cancel (manager->priv->bus_cancellable); g_object_unref (manager->priv->bus_cancellable); manager->priv->bus_cancellable = NULL; } if (manager->priv->idata) { g_dbus_node_info_unref (manager->priv->idata); manager->priv->idata = NULL; } if (manager->priv->ca) { ca_context_destroy (manager->priv->ca); manager->priv->ca = NULL; } if (manager->priv->connection != NULL) { g_object_unref (manager->priv->connection); manager->priv->connection = NULL; } if (manager->priv->onetime_sounds != NULL) { g_list_free_full (manager->priv->onetime_sounds, g_free); manager->priv->onetime_sounds = NULL; } while (manager->priv->monitors) { g_file_monitor_cancel (G_FILE_MONITOR (manager->priv->monitors->data)); g_object_unref (manager->priv->monitors->data); manager->priv->monitors = g_list_delete_link (manager->priv->monitors, manager->priv->monitors); } } static void csd_sound_manager_dispose (GObject *object) { CsdSoundManager *manager; manager = CSD_SOUND_MANAGER (object); csd_sound_manager_stop (manager); G_OBJECT_CLASS (csd_sound_manager_parent_class)->dispose (object); } static void csd_sound_manager_class_init (CsdSoundManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = csd_sound_manager_dispose; object_class->finalize = csd_sound_manager_finalize; g_type_class_add_private (klass, sizeof (CsdSoundManagerPrivate)); } static void csd_sound_manager_init (CsdSoundManager *manager) { manager->priv = CSD_SOUND_MANAGER_GET_PRIVATE (manager); } static void csd_sound_manager_finalize (GObject *object) { CsdSoundManager *sound_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_SOUND_MANAGER (object)); sound_manager = CSD_SOUND_MANAGER (object); g_return_if_fail (sound_manager->priv); if (sound_manager->priv->name_id != 0) g_bus_unown_name (sound_manager->priv->name_id); G_OBJECT_CLASS (csd_sound_manager_parent_class)->finalize (object); } CsdSoundManager * csd_sound_manager_new (void) { if (manager_object) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_SOUND_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_SOUND_MANAGER (manager_object); } cinnamon-settings-daemon-5.2.0/plugins/sound/main.c0000664000175000017500000000100514144454032021241 0ustar fabiofabio#define NEW csd_sound_manager_new #define START csd_sound_manager_start #define STOP csd_sound_manager_stop #define MANAGER CsdSoundManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-sound-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-5.2.0/plugins/sound/csd-sound-manager.h0000664000175000017500000000412314144454032023635 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Lennart Poettering * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CSD_SOUND_MANAGER_H #define __CSD_SOUND_MANAGER_H #include #include G_BEGIN_DECLS #define CSD_TYPE_SOUND_MANAGER (csd_sound_manager_get_type ()) #define CSD_SOUND_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_SOUND_MANAGER, CsdSoundManager)) #define CSD_SOUND_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CSD_TYPE_SOUND_MANAGER, CsdSoundManagerClass)) #define CSD_IS_SOUND_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_SOUND_MANAGER)) #define CSD_IS_SOUND_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_SOUND_MANAGER)) #define CSD_SOUND_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_SOUND_MANAGER, CsdSoundManagerClass)) typedef struct CsdSoundManagerPrivate CsdSoundManagerPrivate; typedef struct { GObject parent; CsdSoundManagerPrivate *priv; } CsdSoundManager; typedef struct { GObjectClass parent_class; } CsdSoundManagerClass; GType csd_sound_manager_get_type (void) G_GNUC_CONST; CsdSoundManager *csd_sound_manager_new (void); gboolean csd_sound_manager_start (CsdSoundManager *manager, GError **error); void csd_sound_manager_stop (CsdSoundManager *manager); G_END_DECLS #endif /* __CSD_SOUND_MANAGER_H */ cinnamon-settings-daemon-5.2.0/plugins/sound/cinnamon-settings-daemon-sound.desktop.in0000664000175000017500000000033214144454032030202 0ustar fabiofabio[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - sound Exec=csd-sound OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-5.2.0/plugins/automount/0000775000175000017500000000000014144454032021060 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/automount/cinnamon-settings-daemon-automount.desktop.in0000664000175000017500000000034214144454032032011 0ustar fabiofabio[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - automount Exec=csd-automount OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-5.2.0/plugins/automount/meson.build0000664000175000017500000000236214144454032023225 0ustar fabiofabioplugin_name = 'automount' automount_sources = [ 'csd-automount-manager.c', 'csd-autorun.c', 'main.c', ] automount_deps = [ common_dep, csd_dep, libnotify, ] executable( 'csd-automount', automount_sources, include_directories: [include_dirs, common_inc], dependencies: automount_deps, c_args: [ '-DPLUGIN_NAME="@0@"'.format(plugin_name), ], install_rpath: join_paths(prefix, apilibdir), install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-automount') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-automount') endif test_automount_dialog_sources = [ 'test-automount-dialog.c', 'csd-autorun.c', ] executable( 'test-automount-dialog', test_automount_dialog_sources, dependencies: automount_deps, install: false, ) configure_file( input: 'cinnamon-settings-daemon-automount.desktop.in', output: 'cinnamon-settings-daemon-automount.desktop', configuration: desktop_conf, install_dir: autostartdir, ) configure_file( input: 'csd-automount.desktop.in', output: 'csd-automount.desktop', configuration: desktop_conf, install_dir: desktopdir, ) cinnamon-settings-daemon-5.2.0/plugins/automount/main.c0000664000175000017500000000103214144454032022144 0ustar fabiofabio#define NEW csd_automount_manager_new #define START csd_automount_manager_start #define STOP csd_automount_manager_stop #define MANAGER CsdAutomountManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE FALSE #include "csd-automount-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-5.2.0/plugins/automount/csd-automount.desktop.in0000664000175000017500000000104714144454032025664 0ustar fabiofabio[Desktop Entry] Type=Application Name=Files Name[am]=ፋይሎች Name[bg]=Файлове Name[ca]=Arxius Name[cs]=Soubory Name[da]=Filer Name[de]=Dateien Name[es]=Archivos Name[eu]=Fitxategiak Name[fr]=Fichiers Name[hr]=Nemo Name[hu]=Fájlok Name[ko]=파일 Name[lt]=Failai Name[nl]=Bestanden Name[pl]=Pliki Name[pt]=Ficheiros Name[pt_BR]=Arquivos Name[pt_PT]=Ficheiros Name[ru]=Файлы Name[sv]=Filer Name[tr]=Dosyalar Name[uk]=Файли Name[zh_CN]=文件 Name[zh_HK]=檔案 Icon=folder Exec=csd-automount OnlyShowIn=X-Cinnamon; NoDisplay=true cinnamon-settings-daemon-5.2.0/plugins/automount/csd-automount-manager.h0000664000175000017500000000461614144454032025452 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA * * Author: Tomas Bzatek */ #ifndef __CSD_AUTOMOUNT_MANAGER_H #define __CSD_AUTOMOUNT_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_AUTOMOUNT_MANAGER (csd_automount_manager_get_type ()) #define CSD_AUTOMOUNT_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_AUTOMOUNT_MANAGER, CsdAutomountManager)) #define CSD_AUTOMOUNT_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_AUTOMOUNT_MANAGER, CsdAutomountManagerClass)) #define CSD_IS_AUTOMOUNT_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_AUTOMOUNT_MANAGER)) #define CSD_IS_AUTOMOUNT_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_AUTOMOUNT_MANAGER)) #define CSD_AUTOMOUNT_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_AUTOMOUNT_MANAGER, CsdAutomountManagerClass)) typedef struct CsdAutomountManagerPrivate CsdAutomountManagerPrivate; typedef struct { GObject parent; CsdAutomountManagerPrivate *priv; } CsdAutomountManager; typedef struct { GObjectClass parent_class; } CsdAutomountManagerClass; GType csd_automount_manager_get_type (void); CsdAutomountManager * csd_automount_manager_new (void); gboolean csd_automount_manager_start (CsdAutomountManager *manager, GError **error); void csd_automount_manager_stop (CsdAutomountManager *manager); G_END_DECLS #endif /* __CSD_AUTOMOUNT_MANAGER_H */ cinnamon-settings-daemon-5.2.0/plugins/automount/csd-automount-manager.c0000664000175000017500000004270314144454032025444 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA * * Author: Tomas Bzatek */ #include "config.h" #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "cinnamon-settings-session.h" #include "csd-automount-manager.h" #include "csd-autorun.h" #define CSD_AUTOMOUNT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_AUTOMOUNT_MANAGER, CsdAutomountManagerPrivate)) struct CsdAutomountManagerPrivate { GSettings *settings; GSettings *settings_screensaver; GVolumeMonitor *volume_monitor; unsigned int automount_idle_id; CinnamonSettingsSession *session; gboolean session_is_active; gboolean screensaver_active; guint ss_watch_id; GDBusProxy *ss_proxy; GList *volume_queue; }; G_DEFINE_TYPE (CsdAutomountManager, csd_automount_manager, G_TYPE_OBJECT) static GtkDialog * show_error_dialog (const char *primary_text, const char *secondary_text) { GtkWidget *dialog; dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", ""); g_object_set (dialog, "text", primary_text, "secondary-text", secondary_text, NULL); gtk_widget_show (GTK_WIDGET (dialog)); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); return GTK_DIALOG (dialog); } static void startup_volume_mount_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { g_volume_mount_finish (G_VOLUME (source_object), res, NULL); } static void automount_all_volumes (CsdAutomountManager *manager) { GList *volumes, *l; GMount *mount; GVolume *volume; if (g_settings_get_boolean (manager->priv->settings, "automount")) { /* automount all mountable volumes at start-up */ volumes = g_volume_monitor_get_volumes (manager->priv->volume_monitor); for (l = volumes; l != NULL; l = l->next) { volume = l->data; if (!g_volume_should_automount (volume) || !g_volume_can_mount (volume)) { continue; } mount = g_volume_get_mount (volume); if (mount != NULL) { g_object_unref (mount); continue; } /* pass NULL as GMountOperation to avoid user interaction */ g_volume_mount (volume, 0, NULL, NULL, startup_volume_mount_cb, NULL); } g_list_free_full (volumes, g_object_unref); } } static gboolean automount_all_volumes_idle_cb (gpointer data) { CsdAutomountManager *manager = CSD_AUTOMOUNT_MANAGER (data); automount_all_volumes (manager); manager->priv->automount_idle_id = 0; return FALSE; } static void volume_mount_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GMountOperation *mount_op = user_data; GError *error; char *primary; char *name; error = NULL; csd_allow_autorun_for_volume_finish (G_VOLUME (source_object)); if (!g_volume_mount_finish (G_VOLUME (source_object), res, &error)) { if (error->code != G_IO_ERROR_FAILED_HANDLED && error->code != G_IO_ERROR_ALREADY_MOUNTED) { name = g_volume_get_name (G_VOLUME (source_object)); primary = g_strdup_printf (_("Unable to mount %s"), name); g_free (name); show_error_dialog (primary, error->message); g_free (primary); } g_error_free (error); } g_object_unref (mount_op); } static void do_mount_volume (GVolume *volume) { GMountOperation *mount_op; mount_op = gtk_mount_operation_new (NULL); g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION); csd_allow_autorun_for_volume (volume); g_volume_mount (volume, 0, mount_op, NULL, volume_mount_cb, mount_op); } static void check_volume_queue (CsdAutomountManager *manager) { GList *l; GVolume *volume; if (manager->priv->screensaver_active) return; l = manager->priv->volume_queue; while (l != NULL) { volume = l->data; do_mount_volume (volume); manager->priv->volume_queue = g_list_remove (manager->priv->volume_queue, volume); g_object_unref (volume); l = l->next; } manager->priv->volume_queue = NULL; } static void check_screen_lock_and_mount (CsdAutomountManager *manager, GVolume *volume) { if (!manager->priv->session_is_active) return; if (manager->priv->screensaver_active) { /* queue the volume, to mount it after the screensaver state changed */ g_debug ("Queuing volume %p", volume); manager->priv->volume_queue = g_list_prepend (manager->priv->volume_queue, g_object_ref (volume)); } else { /* mount it immediately */ do_mount_volume (volume); } } static void volume_removed_callback (GVolumeMonitor *monitor, GVolume *volume, CsdAutomountManager *manager) { g_debug ("Volume %p removed, removing from the queue", volume); /* clear it from the queue, if present */ manager->priv->volume_queue = g_list_remove (manager->priv->volume_queue, volume); } static void volume_added_callback (GVolumeMonitor *monitor, GVolume *volume, CsdAutomountManager *manager) { if (g_settings_get_boolean (manager->priv->settings, "automount") && g_volume_should_automount (volume) && g_volume_can_mount (volume)) { check_screen_lock_and_mount (manager, volume); } else { /* Allow csd_autorun() to run. When the mount is later * added programmatically (i.e. for a blank CD), * csd_autorun() will be called by mount_added_callback(). */ csd_allow_autorun_for_volume (volume); csd_allow_autorun_for_volume_finish (volume); } } static void autorun_show_window (GMount *mount, gpointer user_data) { GFile *location; char *uri; GError *error; char *primary; char *name; location = g_mount_get_root (mount); uri = g_file_get_uri (location); error = NULL; /* use default folder handler */ g_debug("Opening %s", uri); if (g_str_has_prefix (uri, "afc://")) { // AFC (Apple File Conduit, which runs on iPhone and other Apple devices) doesn't always work well // Observed on an iOS 4 device it would work the first time the device was connected, and then indefinitely hang after that // Even a simple 'ls /run/user/$USER/gvfs' would hang forever // It is unacceptable for CSD to hang, so we're treating AFC differently (asynchronously) g_debug("AFC protocol detected, opening asynchronously!"); char * command = g_strdup_printf("timeout 10s xdg-open %s", uri); g_debug("Executing command '%s'", command); system(command); g_debug("Command was executed, moving on.."); g_free(command); } else { if (! gtk_show_uri (NULL, uri, GDK_CURRENT_TIME, &error)) { name = g_mount_get_name (mount); primary = g_strdup_printf (_("Unable to open a folder for %s"), name); g_free (name); show_error_dialog (primary, error->message); g_free (primary); g_error_free (error); } } g_free (uri); g_object_unref (location); } static void mount_added_callback (GVolumeMonitor *monitor, GMount *mount, CsdAutomountManager *manager) { /* don't autorun if the session is not active */ if (!manager->priv->session_is_active) { return; } csd_autorun (mount, manager->priv->settings, autorun_show_window, manager); } static void session_state_changed (CinnamonSettingsSession *session, GParamSpec *pspec, gpointer user_data) { CsdAutomountManager *manager = user_data; CsdAutomountManagerPrivate *p = manager->priv; if (cinnamon_settings_session_get_state (session) == CINNAMON_SETTINGS_SESSION_STATE_ACTIVE) { p->session_is_active = TRUE; } else { p->session_is_active = FALSE; } if (!p->session_is_active) { if (p->volume_queue != NULL) { g_list_free_full (p->volume_queue, g_object_unref); p->volume_queue = NULL; } } } static void do_initialize_session (CsdAutomountManager *manager) { manager->priv->session = cinnamon_settings_session_new (); g_signal_connect (manager->priv->session, "notify::state", G_CALLBACK (session_state_changed), manager); session_state_changed (manager->priv->session, NULL, manager); } #define SCREENSAVER_NAME "org.cinnamon.ScreenSaver" #define SCREENSAVER_PATH "/org/cinnamon/ScreenSaver" #define SCREENSAVER_INTERFACE "org.cinnamon.ScreenSaver" static void screensaver_signal_callback (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { CsdAutomountManager *manager = user_data; if (g_strcmp0 (signal_name, "ActiveChanged") == 0) { g_variant_get (parameters, "(b)", &manager->priv->screensaver_active); g_debug ("Screensaver active changed to %d", manager->priv->screensaver_active); check_volume_queue (manager); } } static void screensaver_get_active_ready_cb (GObject *source, GAsyncResult *res, gpointer user_data) { CsdAutomountManager *manager = user_data; GDBusProxy *proxy = manager->priv->ss_proxy; GVariant *result; GError *error = NULL; result = g_dbus_proxy_call_finish (proxy, res, &error); if (error != NULL) { g_warning ("Can't call GetActive() on the ScreenSaver object: %s", error->message); g_error_free (error); return; } g_variant_get (result, "(b)", &manager->priv->screensaver_active); g_variant_unref (result); g_debug ("Screensaver GetActive() returned %d", manager->priv->screensaver_active); } static void screensaver_proxy_ready_cb (GObject *source, GAsyncResult *res, gpointer user_data) { CsdAutomountManager *manager = user_data; GError *error = NULL; GDBusProxy *ss_proxy; ss_proxy = g_dbus_proxy_new_finish (res, &error); if (error != NULL) { g_warning ("Can't get proxy for the ScreenSaver object: %s", error->message); g_error_free (error); return; } g_debug ("ScreenSaver proxy ready"); manager->priv->ss_proxy = ss_proxy; g_signal_connect (ss_proxy, "g-signal", G_CALLBACK (screensaver_signal_callback), manager); g_dbus_proxy_call (ss_proxy, "GetActive", NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, NULL, screensaver_get_active_ready_cb, manager); } static void screensaver_appeared_callback (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) { CsdAutomountManager *manager = user_data; g_debug ("ScreenSaver name appeared"); manager->priv->screensaver_active = FALSE; g_dbus_proxy_new (connection, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, name, SCREENSAVER_PATH, SCREENSAVER_INTERFACE, NULL, screensaver_proxy_ready_cb, manager); } static void screensaver_vanished_callback (GDBusConnection *connection, const gchar *name, gpointer user_data) { CsdAutomountManager *manager = user_data; g_debug ("ScreenSaver name vanished"); manager->priv->screensaver_active = FALSE; if (manager->priv->ss_proxy != NULL) { g_object_unref (manager->priv->ss_proxy); manager->priv->ss_proxy = NULL; } /* in this case force a clear of the volume queue, without * mounting them. */ if (manager->priv->volume_queue != NULL) { g_list_free_full (manager->priv->volume_queue, g_object_unref); manager->priv->volume_queue = NULL; } } static void do_initialize_screensaver (CsdAutomountManager *manager) { CsdAutomountManagerPrivate *p = manager->priv; p->ss_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, SCREENSAVER_NAME, G_BUS_NAME_WATCHER_FLAGS_NONE, screensaver_appeared_callback, screensaver_vanished_callback, manager, NULL); } static void setup_automounter (CsdAutomountManager *manager) { do_initialize_session (manager); gchar *custom_saver = g_settings_get_string (manager->priv->settings_screensaver, "custom-screensaver-command"); /* if we fail to get the gsettings entry, or if the user did not select * a custom screen saver, default to cinnamon-screensaver */ if (NULL == custom_saver || g_strcmp0 (custom_saver, "") == 0) do_initialize_screensaver (manager); g_free (custom_saver); manager->priv->volume_monitor = g_volume_monitor_get (); g_signal_connect_object (manager->priv->volume_monitor, "mount-added", G_CALLBACK (mount_added_callback), manager, 0); g_signal_connect_object (manager->priv->volume_monitor, "volume-added", G_CALLBACK (volume_added_callback), manager, 0); g_signal_connect_object (manager->priv->volume_monitor, "volume-removed", G_CALLBACK (volume_removed_callback), manager, 0); manager->priv->automount_idle_id = g_idle_add_full (G_PRIORITY_LOW, automount_all_volumes_idle_cb, manager, NULL); } gboolean csd_automount_manager_start (CsdAutomountManager *manager, GError **error) { g_debug ("Starting automounting manager"); cinnamon_settings_profile_start (NULL); manager->priv->settings = g_settings_new ("org.cinnamon.desktop.media-handling"); manager->priv->settings_screensaver = g_settings_new ("org.cinnamon.desktop.screensaver"); setup_automounter (manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_automount_manager_stop (CsdAutomountManager *manager) { CsdAutomountManagerPrivate *p = manager->priv; g_debug ("Stopping automounting manager"); if (p->session != NULL) { g_object_unref (p->session); p->session = NULL; } if (p->volume_monitor != NULL) { g_object_unref (p->volume_monitor); p->volume_monitor = NULL; } if (p->settings != NULL) { g_object_unref (p->settings); p->settings = NULL; } if (p->settings_screensaver != NULL) { g_object_unref (p->settings_screensaver); p->settings_screensaver = NULL; } if (p->ss_proxy != NULL) { g_object_unref (p->ss_proxy); p->ss_proxy = NULL; } g_bus_unwatch_name (p->ss_watch_id); if (p->volume_queue != NULL) { g_list_free_full (p->volume_queue, g_object_unref); p->volume_queue = NULL; } if (p->automount_idle_id != 0) { g_source_remove (p->automount_idle_id); p->automount_idle_id = 0; } } static void csd_automount_manager_class_init (CsdAutomountManagerClass *klass) { g_type_class_add_private (klass, sizeof (CsdAutomountManagerPrivate)); } static void csd_automount_manager_init (CsdAutomountManager *manager) { manager->priv = CSD_AUTOMOUNT_MANAGER_GET_PRIVATE (manager); } CsdAutomountManager * csd_automount_manager_new (void) { return CSD_AUTOMOUNT_MANAGER (g_object_new (CSD_TYPE_AUTOMOUNT_MANAGER, NULL)); } cinnamon-settings-daemon-5.2.0/plugins/automount/csd-autorun.c0000664000175000017500000007175214144454032023504 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* * csd-automount.c: helpers for automounting hotplugged volumes * * Copyright (C) 2008, 2010 Red Hat, Inc. * * Nautilus is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA * * Authors: David Zeuthen * Cosimo Cecchi */ #include #include #include #include #include #include #include #include #include "csd-autorun.h" static gboolean should_autorun_mount (GMount *mount); #define CUSTOM_ITEM_ASK "csd-item-ask" #define CUSTOM_ITEM_DO_NOTHING "csd-item-do-nothing" #define CUSTOM_ITEM_OPEN_FOLDER "csd-item-open-folder" typedef struct { GtkWidget *dialog; GMount *mount; gboolean should_eject; gboolean selected_ignore; gboolean selected_open_folder; GAppInfo *selected_app; gboolean remember; char *x_content_type; CsdAutorunOpenWindow open_window_func; gpointer user_data; } AutorunDialogData; static int csd_autorun_g_strv_find (char **strv, const char *find_me) { guint index; g_return_val_if_fail (find_me != NULL, -1); for (index = 0; strv[index] != NULL; ++index) { if (strcmp (strv[index], find_me) == 0) { return index; } } return -1; } #define ICON_SIZE_STANDARD 48 static gint get_icon_size_for_stock_size (GtkIconSize size) { gint w, h; if (gtk_icon_size_lookup (size, &w, &h)) { return MAX (w, h); } return ICON_SIZE_STANDARD; } static GdkPixbuf * render_icon (GIcon *icon, gint icon_size) { GdkPixbuf *pixbuf; GtkIconInfo *info; pixbuf = NULL; if (G_IS_THEMED_ICON (icon)) { gchar const * const *names; info = gtk_icon_theme_lookup_by_gicon (gtk_icon_theme_get_default (), icon, icon_size, 0); if (info) { pixbuf = gtk_icon_info_load_icon (info, NULL); g_object_unref (info); } if (pixbuf == NULL) { names = g_themed_icon_get_names (G_THEMED_ICON (icon)); pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), *names, icon_size, 0, NULL); } } else if (G_IS_FILE_ICON (icon)) { GFile *icon_file; gchar *path; icon_file = g_file_icon_get_file (G_FILE_ICON (icon)); path = g_file_get_path (icon_file); pixbuf = gdk_pixbuf_new_from_file_at_size (path, icon_size, icon_size, NULL); g_free (path); g_object_unref (G_OBJECT (icon_file)); } return pixbuf; } static void csd_autorun_get_preferences (const char *x_content_type, gboolean *pref_start_app, gboolean *pref_ignore, gboolean *pref_open_folder) { GSettings *settings; char **x_content_start_app; char **x_content_ignore; char **x_content_open_folder; g_return_if_fail (pref_start_app != NULL); g_return_if_fail (pref_ignore != NULL); g_return_if_fail (pref_open_folder != NULL); settings = g_settings_new ("org.cinnamon.desktop.media-handling"); *pref_start_app = FALSE; *pref_ignore = FALSE; *pref_open_folder = FALSE; x_content_start_app = g_settings_get_strv (settings, "autorun-x-content-start-app"); x_content_ignore = g_settings_get_strv (settings, "autorun-x-content-ignore"); x_content_open_folder = g_settings_get_strv (settings, "autorun-x-content-open-folder"); if (x_content_start_app != NULL) { *pref_start_app = csd_autorun_g_strv_find (x_content_start_app, x_content_type) != -1; } if (x_content_ignore != NULL) { *pref_ignore = csd_autorun_g_strv_find (x_content_ignore, x_content_type) != -1; } if (x_content_open_folder != NULL) { *pref_open_folder = csd_autorun_g_strv_find (x_content_open_folder, x_content_type) != -1; } g_strfreev (x_content_ignore); g_strfreev (x_content_start_app); g_strfreev (x_content_open_folder); g_object_unref (settings); } static char ** remove_elem_from_str_array (char **v, const char *s) { GPtrArray *array; guint idx; array = g_ptr_array_new (); for (idx = 0; v[idx] != NULL; idx++) { if (g_strcmp0 (v[idx], s) == 0) { continue; } g_ptr_array_add (array, v[idx]); } g_ptr_array_add (array, NULL); g_free (v); return (char **) g_ptr_array_free (array, FALSE); } static char ** add_elem_to_str_array (char **v, const char *s) { GPtrArray *array; guint idx; array = g_ptr_array_new (); for (idx = 0; v[idx] != NULL; idx++) { g_ptr_array_add (array, v[idx]); } g_ptr_array_add (array, g_strdup (s)); g_ptr_array_add (array, NULL); g_free (v); return (char **) g_ptr_array_free (array, FALSE); } static void csd_autorun_set_preferences (const char *x_content_type, gboolean pref_start_app, gboolean pref_ignore, gboolean pref_open_folder) { GSettings *settings; char **x_content_start_app; char **x_content_ignore; char **x_content_open_folder; g_assert (x_content_type != NULL); settings = g_settings_new ("org.cinnamon.desktop.media-handling"); x_content_start_app = g_settings_get_strv (settings, "autorun-x-content-start-app"); x_content_ignore = g_settings_get_strv (settings, "autorun-x-content-ignore"); x_content_open_folder = g_settings_get_strv (settings, "autorun-x-content-open-folder"); x_content_start_app = remove_elem_from_str_array (x_content_start_app, x_content_type); if (pref_start_app) { x_content_start_app = add_elem_to_str_array (x_content_start_app, x_content_type); } g_settings_set_strv (settings, "autorun-x-content-start-app", (const gchar * const*) x_content_start_app); x_content_ignore = remove_elem_from_str_array (x_content_ignore, x_content_type); if (pref_ignore) { x_content_ignore = add_elem_to_str_array (x_content_ignore, x_content_type); } g_settings_set_strv (settings, "autorun-x-content-ignore", (const gchar * const*) x_content_ignore); x_content_open_folder = remove_elem_from_str_array (x_content_open_folder, x_content_type); if (pref_open_folder) { x_content_open_folder = add_elem_to_str_array (x_content_open_folder, x_content_type); } g_settings_set_strv (settings, "autorun-x-content-open-folder", (const gchar * const*) x_content_open_folder); g_strfreev (x_content_open_folder); g_strfreev (x_content_ignore); g_strfreev (x_content_start_app); g_object_unref (settings); } static void custom_item_activated_cb (GtkAppChooserButton *button, const gchar *item, gpointer user_data) { gchar *content_type; AutorunDialogData *data = user_data; content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (button)); if (g_strcmp0 (item, CUSTOM_ITEM_ASK) == 0) { csd_autorun_set_preferences (content_type, FALSE, FALSE, FALSE); data->selected_open_folder = FALSE; data->selected_ignore = FALSE; } else if (g_strcmp0 (item, CUSTOM_ITEM_OPEN_FOLDER) == 0) { csd_autorun_set_preferences (content_type, FALSE, FALSE, TRUE); data->selected_open_folder = TRUE; data->selected_ignore = FALSE; } else if (g_strcmp0 (item, CUSTOM_ITEM_DO_NOTHING) == 0) { csd_autorun_set_preferences (content_type, FALSE, TRUE, FALSE); data->selected_open_folder = FALSE; data->selected_ignore = TRUE; } g_free (content_type); } static void combo_box_changed_cb (GtkComboBox *combo_box, gpointer user_data) { GAppInfo *info; AutorunDialogData *data = user_data; info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box)); if (info == NULL) return; if (data->selected_app != NULL) { g_object_unref (data->selected_app); data->selected_app = NULL; } data->selected_app = info; } static void prepare_combo_box (GtkWidget *combo_box, AutorunDialogData *data) { GtkAppChooserButton *app_chooser = GTK_APP_CHOOSER_BUTTON (combo_box); GIcon *icon; gboolean pref_ask; gboolean pref_start_app; gboolean pref_ignore; gboolean pref_open_folder; GAppInfo *info; gchar *content_type; content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (app_chooser)); gtk_app_chooser_button_set_show_default_item (GTK_APP_CHOOSER_BUTTON (combo_box), TRUE); /* fetch preferences for this content type */ csd_autorun_get_preferences (content_type, &pref_start_app, &pref_ignore, &pref_open_folder); pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder; info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (combo_box)); /* append the separator only if we have >= 1 apps in the chooser */ if (info != NULL) { gtk_app_chooser_button_append_separator (app_chooser); g_object_unref (info); } icon = g_themed_icon_new ("dialog-question"); gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_ASK, _("Ask what to do"), icon); g_object_unref (icon); icon = g_themed_icon_new ("window-close"); gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING, _("Do Nothing"), icon); g_object_unref (icon); icon = g_themed_icon_new ("folder-open"); gtk_app_chooser_button_append_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER, _("Open Folder"), icon); g_object_unref (icon); gtk_app_chooser_button_set_show_dialog_item (app_chooser, TRUE); if (pref_ask) { gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_ASK); } else if (pref_ignore) { gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_DO_NOTHING); } else if (pref_open_folder) { gtk_app_chooser_button_set_active_custom_item (app_chooser, CUSTOM_ITEM_OPEN_FOLDER); } g_signal_connect (app_chooser, "changed", G_CALLBACK (combo_box_changed_cb), data); g_signal_connect (app_chooser, "custom-item-activated", G_CALLBACK (custom_item_activated_cb), data); g_free (content_type); } static gboolean is_shift_pressed (void) { gboolean ret; XkbStateRec state; Bool status; ret = FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); status = XkbGetState (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbUseCoreKbd, &state); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); if (status == Success) { ret = state.mods & ShiftMask; } return ret; } enum { AUTORUN_DIALOG_RESPONSE_EJECT = 0 }; static void csd_autorun_launch_for_mount (GMount *mount, GAppInfo *app_info) { GFile *root; GdkAppLaunchContext *launch_context; GError *error; gboolean result; GList *list; gchar *uri_scheme; gchar *uri; root = g_mount_get_root (mount); list = g_list_append (NULL, root); launch_context = gdk_app_launch_context_new (); error = NULL; result = g_app_info_launch (app_info, list, G_APP_LAUNCH_CONTEXT (launch_context), &error); g_object_unref (launch_context); if (!result) { if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_SUPPORTED) { uri = g_file_get_uri (root); uri_scheme = g_uri_parse_scheme (uri); /* FIXME: Present user a dialog to choose another app when the last one failed to handle a file */ g_warning ("Cannot open location: %s\n", error->message); g_free (uri_scheme); g_free (uri); } else { g_warning ("Cannot open app: %s\n", error->message); } g_error_free (error); } g_list_free (list); g_object_unref (root); } static void autorun_dialog_mount_unmounted (GMount *mount, AutorunDialogData *data); static void autorun_dialog_destroy (AutorunDialogData *data) { g_signal_handlers_disconnect_by_func (G_OBJECT (data->mount), G_CALLBACK (autorun_dialog_mount_unmounted), data); gtk_widget_destroy (GTK_WIDGET (data->dialog)); if (data->selected_app != NULL) { g_object_unref (data->selected_app); } g_object_unref (data->mount); g_free (data->x_content_type); g_free (data); } static void autorun_dialog_mount_unmounted (GMount *mount, AutorunDialogData *data) { /* remove the dialog if the media is unmounted */ autorun_dialog_destroy (data); } static void unmount_mount_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error; char *primary; gboolean unmounted; gboolean should_eject; GtkWidget *dialog; should_eject = user_data != NULL; error = NULL; if (should_eject) { unmounted = g_mount_eject_with_operation_finish (G_MOUNT (source_object), res, &error); } else { unmounted = g_mount_unmount_with_operation_finish (G_MOUNT (source_object), res, &error); } if (! unmounted) { if (error->code != G_IO_ERROR_FAILED_HANDLED) { if (should_eject) { primary = g_strdup_printf (_("Unable to eject %p"), source_object); } else { primary = g_strdup_printf (_("Unable to unmount %p"), source_object); } dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", primary); gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", error->message); gtk_widget_show (GTK_WIDGET (dialog)); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); g_free (primary); } } if (error != NULL) { g_error_free (error); } } static void do_unmount (GMount *mount, gboolean should_eject, GtkWindow *window) { GMountOperation *mount_op; mount_op = gtk_mount_operation_new (window); if (should_eject) { g_mount_eject_with_operation (mount, 0, mount_op, NULL, unmount_mount_callback, (gpointer) 1); } else { g_mount_unmount_with_operation (mount, 0, mount_op, NULL, unmount_mount_callback, (gpointer) 0); } g_object_unref (mount_op); } static void autorun_dialog_response (GtkDialog *dialog, gint response, AutorunDialogData *data) { switch (response) { case AUTORUN_DIALOG_RESPONSE_EJECT: do_unmount (data->mount, data->should_eject, GTK_WINDOW (dialog)); break; case GTK_RESPONSE_NONE: /* window was closed */ break; case GTK_RESPONSE_CANCEL: break; case GTK_RESPONSE_OK: /* do the selected action */ if (data->remember) { /* make sure we don't ask again */ csd_autorun_set_preferences (data->x_content_type, TRUE, data->selected_ignore, data->selected_open_folder); if (!data->selected_ignore && !data->selected_open_folder && data->selected_app != NULL) { g_app_info_set_as_default_for_type (data->selected_app, data->x_content_type, NULL); } } else { /* make sure we do ask again */ csd_autorun_set_preferences (data->x_content_type, FALSE, FALSE, FALSE); } if (!data->selected_ignore && !data->selected_open_folder && data->selected_app != NULL) { csd_autorun_launch_for_mount (data->mount, data->selected_app); } else if (!data->selected_ignore && data->selected_open_folder) { if (data->open_window_func != NULL) data->open_window_func (data->mount, data->user_data); } break; } autorun_dialog_destroy (data); } static void autorun_always_toggled (GtkToggleButton *togglebutton, AutorunDialogData *data) { data->remember = gtk_toggle_button_get_active (togglebutton); } static gboolean combo_box_enter_ok (GtkWidget *togglebutton, GdkEventKey *event, GtkDialog *dialog) { if (event->keyval == GDK_KEY_KP_Enter || event->keyval == GDK_KEY_Return) { gtk_dialog_response (dialog, GTK_RESPONSE_OK); return TRUE; } return FALSE; } /* returns TRUE if a folder window should be opened */ static gboolean do_autorun_for_content_type (GMount *mount, const char *x_content_type, CsdAutorunOpenWindow open_window_func, gpointer user_data) { AutorunDialogData *data; GtkWidget *dialog; GtkWidget *hbox; GtkWidget *vbox; GtkWidget *label; GtkWidget *combo_box; GtkWidget *always_check_button; GtkWidget *eject_button; GtkWidget *image; char *markup; char *content_description; char *mount_name; GIcon *icon; GdkPixbuf *pixbuf; int icon_size; gboolean user_forced_dialog; gboolean pref_ask; gboolean pref_start_app; gboolean pref_ignore; gboolean pref_open_folder; char *media_greeting; gboolean ret; ret = FALSE; mount_name = NULL; if (g_content_type_is_a (x_content_type, "x-content/win32-software")) { /* don't pop up the dialog anyway if the content type says * windows software. */ goto out; } user_forced_dialog = is_shift_pressed (); csd_autorun_get_preferences (x_content_type, &pref_start_app, &pref_ignore, &pref_open_folder); pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder; if (user_forced_dialog) { goto show_dialog; } if (!pref_ask && !pref_ignore && !pref_open_folder) { GAppInfo *app_info; app_info = g_app_info_get_default_for_type (x_content_type, FALSE); if (app_info != NULL) { csd_autorun_launch_for_mount (mount, app_info); } goto out; } if (pref_open_folder) { ret = TRUE; goto out; } if (pref_ignore) { goto out; } show_dialog: mount_name = g_mount_get_name (mount); dialog = gtk_dialog_new (); gtk_window_set_default_size (GTK_WINDOW (dialog), 450, -1); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), hbox, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (hbox), 12); icon = g_mount_get_icon (mount); icon_size = get_icon_size_for_stock_size (GTK_ICON_SIZE_DIALOG); image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG); pixbuf = render_icon (icon, icon_size); gtk_widget_set_halign (image, GTK_ALIGN_CENTER); gtk_widget_set_valign (image, GTK_ALIGN_START); gtk_box_pack_start (GTK_BOX (hbox), image, TRUE, TRUE, 0); /* also use the icon on the dialog */ gtk_window_set_title (GTK_WINDOW (dialog), mount_name); gtk_window_set_icon (GTK_WINDOW (dialog), pixbuf); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); g_object_unref (icon); if (pixbuf) { g_object_unref (pixbuf); } vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); label = gtk_label_new (NULL); /* Customize greeting for well-known x-content types */ if (strcmp (x_content_type, "x-content/audio-cdda") == 0) { media_greeting = _("You have just inserted an Audio CD."); } else if (strcmp (x_content_type, "x-content/audio-dvd") == 0) { media_greeting = _("You have just inserted an Audio DVD."); } else if (strcmp (x_content_type, "x-content/video-dvd") == 0) { media_greeting = _("You have just inserted a Video DVD."); } else if (strcmp (x_content_type, "x-content/video-vcd") == 0) { media_greeting = _("You have just inserted a Video CD."); } else if (strcmp (x_content_type, "x-content/video-svcd") == 0) { media_greeting = _("You have just inserted a Super Video CD."); } else if (strcmp (x_content_type, "x-content/blank-cd") == 0) { media_greeting = _("You have just inserted a blank CD."); } else if (strcmp (x_content_type, "x-content/blank-dvd") == 0) { media_greeting = _("You have just inserted a blank DVD."); } else if (strcmp (x_content_type, "x-content/blank-cd") == 0) { media_greeting = _("You have just inserted a blank Blu-Ray disc."); } else if (strcmp (x_content_type, "x-content/blank-cd") == 0) { media_greeting = _("You have just inserted a blank HD DVD."); } else if (strcmp (x_content_type, "x-content/image-photocd") == 0) { media_greeting = _("You have just inserted a Photo CD."); } else if (strcmp (x_content_type, "x-content/image-picturecd") == 0) { media_greeting = _("You have just inserted a Picture CD."); } else if (strcmp (x_content_type, "x-content/image-dcf") == 0) { media_greeting = _("You have just inserted a medium with digital photos."); } else if (strcmp (x_content_type, "x-content/audio-player") == 0) { media_greeting = _("You have just inserted a digital audio player."); } else if (g_content_type_is_a (x_content_type, "x-content/software")) { media_greeting = _("You have just inserted a medium with software intended to be automatically started."); } else { /* fallback to generic greeting */ media_greeting = _("You have just inserted a medium."); } markup = g_strdup_printf ("%s %s", media_greeting, _("Choose what application to launch.")); gtk_label_set_markup (GTK_LABEL (label), markup); g_free (markup); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_label_set_yalign (GTK_LABEL (label), 0.5); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); label = gtk_label_new (NULL); content_description = g_content_type_get_description (x_content_type); markup = g_strdup_printf (_("Select how to open \"%s\" and whether to perform this action in the future for other media of type \"%s\"."), mount_name, content_description); g_free (content_description); gtk_label_set_markup (GTK_LABEL (label), markup); g_free (markup); gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_xalign (GTK_LABEL (label), 0.0); gtk_label_set_yalign (GTK_LABEL (label), 0.5); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); data = g_new0 (AutorunDialogData, 1); data->dialog = dialog; data->mount = g_object_ref (mount); data->remember = !pref_ask; data->selected_ignore = pref_ignore; data->x_content_type = g_strdup (x_content_type); data->selected_app = g_app_info_get_default_for_type (x_content_type, FALSE); data->open_window_func = open_window_func; data->user_data = user_data; combo_box = gtk_app_chooser_button_new (x_content_type); prepare_combo_box (combo_box, data); g_signal_connect (G_OBJECT (combo_box), "key-press-event", G_CALLBACK (combo_box_enter_ok), dialog); gtk_box_pack_start (GTK_BOX (vbox), combo_box, TRUE, TRUE, 0); always_check_button = gtk_check_button_new_with_mnemonic (_("_Always perform this action")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (always_check_button), data->remember); g_signal_connect (G_OBJECT (always_check_button), "toggled", G_CALLBACK (autorun_always_toggled), data); gtk_box_pack_start (GTK_BOX (vbox), always_check_button, TRUE, TRUE, 0); gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Ok"), GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); if (g_mount_can_eject (mount)) { eject_button = gtk_button_new_with_mnemonic (_("_Eject")); data->should_eject = TRUE; } else { eject_button = gtk_button_new_with_mnemonic (_("_Unmount")); data->should_eject = FALSE; } gtk_dialog_add_action_widget (GTK_DIALOG (dialog), eject_button, AUTORUN_DIALOG_RESPONSE_EJECT); gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dialog))), eject_button, TRUE); /* show the dialog */ gtk_widget_show_all (dialog); g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (autorun_dialog_response), data); g_signal_connect (G_OBJECT (data->mount), "unmounted", G_CALLBACK (autorun_dialog_mount_unmounted), data); out: g_free (mount_name); return ret; } typedef struct { GMount *mount; CsdAutorunOpenWindow open_window_func; gpointer user_data; GSettings *settings; } AutorunData; static void autorun_guessed_content_type_callback (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error; char **guessed_content_type; AutorunData *data = user_data; gboolean open_folder; open_folder = FALSE; error = NULL; guessed_content_type = g_mount_guess_content_type_finish (G_MOUNT (source_object), res, &error); g_object_set_data_full (source_object, "csd-content-type-cache", g_strdupv (guessed_content_type), (GDestroyNotify)g_strfreev); if (error != NULL) { g_warning ("Unable to guess content type for mount: %s", error->message); g_error_free (error); } else { if (guessed_content_type != NULL && g_strv_length (guessed_content_type) > 0) { int n; for (n = 0; guessed_content_type[n] != NULL; n++) { if (do_autorun_for_content_type (data->mount, guessed_content_type[n], data->open_window_func, data->user_data)) { open_folder = TRUE; } } g_strfreev (guessed_content_type); } else { if (g_settings_get_boolean (data->settings, "automount-open")) { open_folder = TRUE; } } } /* only open the folder once.. */ if (open_folder && data->open_window_func != NULL) { data->open_window_func (data->mount, data->user_data); } g_object_unref (data->mount); g_object_unref (data->settings); g_free (data); } void csd_autorun (GMount *mount, GSettings *settings, CsdAutorunOpenWindow open_window_func, gpointer user_data) { AutorunData *data; if (!should_autorun_mount (mount) || g_settings_get_boolean (settings, "autorun-never")) { return; } data = g_new0 (AutorunData, 1); data->mount = g_object_ref (mount); data->open_window_func = open_window_func; data->user_data = user_data; data->settings = g_object_ref (settings); g_mount_guess_content_type (mount, FALSE, NULL, autorun_guessed_content_type_callback, data); } static gboolean remove_allow_volume (gpointer data) { GVolume *volume = data; g_object_set_data (G_OBJECT (volume), "csd-allow-autorun", NULL); return FALSE; } void csd_allow_autorun_for_volume (GVolume *volume) { g_object_set_data (G_OBJECT (volume), "csd-allow-autorun", GINT_TO_POINTER (1)); } #define INHIBIT_AUTORUN_SECONDS 10 void csd_allow_autorun_for_volume_finish (GVolume *volume) { if (g_object_get_data (G_OBJECT (volume), "csd-allow-autorun") != NULL) { g_timeout_add_seconds_full (0, INHIBIT_AUTORUN_SECONDS, remove_allow_volume, g_object_ref (volume), g_object_unref); } } static gboolean should_skip_native_mount_root (GFile *root) { char *path; gboolean should_skip; /* skip any mounts in hidden directory hierarchies */ path = g_file_get_path (root); should_skip = strstr (path, "/.") != NULL; g_free (path); return should_skip; } static gboolean should_autorun_mount (GMount *mount) { GFile *root; GVolume *enclosing_volume; gboolean ignore_autorun; ignore_autorun = TRUE; enclosing_volume = g_mount_get_volume (mount); if (enclosing_volume != NULL) { if (g_object_get_data (G_OBJECT (enclosing_volume), "csd-allow-autorun") != NULL) { ignore_autorun = FALSE; g_object_set_data (G_OBJECT (enclosing_volume), "csd-allow-autorun", NULL); } } if (ignore_autorun) { if (enclosing_volume != NULL) { g_object_unref (enclosing_volume); } return FALSE; } root = g_mount_get_root (mount); /* only do autorun on local files or files where g_volume_should_automount() returns TRUE */ ignore_autorun = TRUE; if ((g_file_is_native (root) && !should_skip_native_mount_root (root)) || (enclosing_volume != NULL && g_volume_should_automount (enclosing_volume))) { ignore_autorun = FALSE; } if (enclosing_volume != NULL) { g_object_unref (enclosing_volume); } g_object_unref (root); return !ignore_autorun; } void csd_autorun_for_content_type (GMount *mount, const gchar *content_type, CsdAutorunOpenWindow callback, gpointer user_data) { do_autorun_for_content_type (mount, content_type, callback, user_data); } cinnamon-settings-daemon-5.2.0/plugins/automount/test-automount-dialog.c0000664000175000017500000000415414144454032025475 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * save-session.c - Small program to talk to session manager. Copyright (C) 1998 Tom Tromey Copyright (C) 2008 Red Hat, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. */ #include #include #include #include #include #include #include #include "csd-autorun.h" static void autorun_show_window (GMount *mount, gpointer user_data) { gtk_main_quit (); } int main (int argc, char *argv[]) { GVolumeMonitor *monitor; GError *error; GList *mounts; error = NULL; if (! gtk_init_with_args (&argc, &argv, NULL, NULL, NULL, &error)) { g_warning ("Unable to start: %s", error->message); g_error_free (error); exit (1); } if (argc != 2) { g_print ("Need one argument as content type\n"); exit (1); } monitor = g_volume_monitor_get (); mounts = g_volume_monitor_get_mounts (monitor); if (mounts) { GMount *mount = G_MOUNT (mounts->data); csd_autorun_for_content_type (mount, argv[1], (CsdAutorunOpenWindow) autorun_show_window, NULL); } gtk_main (); gtk_main_quit (); return 0; } cinnamon-settings-daemon-5.2.0/plugins/automount/csd-autorun.h0000664000175000017500000000360514144454032023501 0ustar fabiofabio/* * csd-automount.h:helpers for automounting hotplugged volumes * * Copyright (C) 2008 Red Hat, Inc. * * Nautilus is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA * * Authors: David Zeuthen * Cosimo Cecchi */ /* TODO: * * - unmount all the media we've automounted on shutdown * - finish x-content / * types * - finalize the semi-spec * - add probing/sniffing code * - implement missing features * - "Open Folder when mounted" * - Autorun spec (e.g. $ROOT/.autostart) * */ #ifndef __CSD_AUTORUN_H__ #define __CSD_AUTORUN_H__ #include #include typedef void (*CsdAutorunOpenWindow) (GMount *mount, gpointer user_data); void csd_autorun (GMount *mount, GSettings *settings, CsdAutorunOpenWindow open_window_func, gpointer user_data); void csd_autorun_for_content_type (GMount *mount, const gchar *content_type, CsdAutorunOpenWindow callback, gpointer user_data); void csd_allow_autorun_for_volume (GVolume *volume); void csd_allow_autorun_for_volume_finish (GVolume *volume); #endif /* __CSD_AUTORUN_H__ */ cinnamon-settings-daemon-5.2.0/plugins/orientation/0000775000175000017500000000000014144454032021360 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/orientation/meson.build0000664000175000017500000000153414144454032023525 0ustar fabiofabioplugin_name = 'orientation' orientation_sources = [ 'csd-orientation-manager.c', 'main.c', ] orientation_deps = [ cinnamon_desktop, common_dep, csd_dep, libnotify, ] executable( 'csd-orientation', orientation_sources, include_directories: [include_dirs, common_inc], dependencies: orientation_deps, c_args: [ '-DPLUGIN_NAME="@0@"'.format(plugin_name), ], install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-orientation') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-orientation') endif configure_file( input: 'cinnamon-settings-daemon-orientation.desktop.in', output: 'cinnamon-settings-daemon-orientation.desktop', configuration: desktop_conf, install_dir: autostartdir, ) cinnamon-settings-daemon-5.2.0/plugins/orientation/main.c0000664000175000017500000000104314144454032022446 0ustar fabiofabio#define NEW csd_orientation_manager_new #define START csd_orientation_manager_start #define STOP csd_orientation_manager_stop #define MANAGER CsdOrientationManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-orientation-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-5.2.0/plugins/orientation/csd-orientation-manager.c0000664000175000017500000004176014144454032026246 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2010,2011 Red Hat, Inc. * * Author: Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include "csd-input-helper.h" #include "cinnamon-settings-profile.h" #include "csd-orientation-manager.h" typedef enum { ORIENTATION_UNDEFINED, ORIENTATION_NORMAL, ORIENTATION_BOTTOM_UP, ORIENTATION_LEFT_UP, ORIENTATION_RIGHT_UP } OrientationUp; #define CSD_ORIENTATION_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_ORIENTATION_MANAGER, CsdOrientationManagerPrivate)) struct CsdOrientationManagerPrivate { /* Accelerometer */ guint watch_id; GDBusProxy *iio_proxy; gboolean has_accel; OrientationUp prev_orientation; /* DBus */ GDBusProxy *xrandr_proxy; GCancellable *cancellable; /* Notifications */ GSettings *settings; gboolean orientation_lock; }; #define CONF_SCHEMA "org.cinnamon.settings-daemon.peripherals.touchscreen" #define ORIENTATION_LOCK_KEY "orientation-lock" static void csd_orientation_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdOrientationManager, csd_orientation_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; #define MPU_THRESHOLD 12000 #define MPU_POLL_INTERVAL 1 static gboolean is_mpu6050 = FALSE; static char *mpu6050_accel_x = NULL; static char *mpu6050_accel_y = NULL; static gboolean mpu_timer(CsdOrientationManager *manager); static void csd_orientation_manager_class_init (CsdOrientationManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_orientation_manager_finalize; g_type_class_add_private (klass, sizeof (CsdOrientationManagerPrivate)); } static void csd_orientation_manager_init (CsdOrientationManager *manager) { manager->priv = CSD_ORIENTATION_MANAGER_GET_PRIVATE (manager); manager->priv->prev_orientation = ORIENTATION_UNDEFINED; } static GnomeRRRotation orientation_to_rotation (OrientationUp orientation) { switch (orientation) { case ORIENTATION_NORMAL: return GNOME_RR_ROTATION_0; case ORIENTATION_BOTTOM_UP: return GNOME_RR_ROTATION_180; case ORIENTATION_LEFT_UP: return GNOME_RR_ROTATION_90; case ORIENTATION_RIGHT_UP: return GNOME_RR_ROTATION_270; default: g_assert_not_reached (); } } static OrientationUp orientation_from_string (const char *orientation) { if (g_strcmp0 (orientation, "normal") == 0) return ORIENTATION_NORMAL; if (g_strcmp0 (orientation, "bottom-up") == 0) return ORIENTATION_BOTTOM_UP; if (g_strcmp0 (orientation, "left-up") == 0) return ORIENTATION_LEFT_UP; if (g_strcmp0 (orientation, "right-up") == 0) return ORIENTATION_RIGHT_UP; return ORIENTATION_UNDEFINED; } static const char * orientation_to_string (OrientationUp o) { switch (o) { case ORIENTATION_UNDEFINED: return "undefined"; case ORIENTATION_NORMAL: return "normal"; case ORIENTATION_BOTTOM_UP: return "bottom-up"; case ORIENTATION_LEFT_UP: return "left-up"; case ORIENTATION_RIGHT_UP: return "right-up"; default: g_assert_not_reached (); } } static OrientationUp get_orientation_from_device (CsdOrientationManager *manager) { GVariant *v; OrientationUp o; v = g_dbus_proxy_get_cached_property (manager->priv->iio_proxy, "AccelerometerOrientation"); if (v == NULL) { g_debug ("Couldn't find orientation for accelerometer"); return ORIENTATION_UNDEFINED; } g_debug ("Found orientation '%s' for accelerometer", g_variant_get_string (v, NULL)); o = orientation_from_string (g_variant_get_string (v, NULL)); g_variant_unref (v); return o; } static void on_xrandr_action_call_finished (GObject *source_object, GAsyncResult *res, CsdOrientationManager *manager) { GError *error = NULL; GVariant *variant; variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); g_clear_object (&manager->priv->cancellable); if (variant == NULL) { g_warning ("Unable to call 'RotateTo': %s", error->message); g_error_free (error); } else { g_variant_unref (variant); } } static void do_xrandr_action (CsdOrientationManager *manager, GnomeRRRotation rotation) { CsdOrientationManagerPrivate *priv = manager->priv; GTimeVal tv; gint64 timestamp; if (priv->xrandr_proxy == NULL) { g_warning ("No existing D-Bus connection trying to handle XRANDR keys"); return; } if (priv->cancellable != NULL) { g_debug ("xrandr action already in flight"); return; } g_get_current_time (&tv); timestamp = tv.tv_sec * 1000 + tv.tv_usec / 1000; priv->cancellable = g_cancellable_new (); g_dbus_proxy_call (priv->xrandr_proxy, "RotateTo", g_variant_new ("(ix)", rotation, timestamp), G_DBUS_CALL_FLAGS_NONE, -1, priv->cancellable, (GAsyncReadyCallback) on_xrandr_action_call_finished, manager); } static void do_rotation (CsdOrientationManager *manager) { GnomeRRRotation rotation; if (manager->priv->orientation_lock) { g_debug ("Orientation changed, but we are locked"); return; } if (manager->priv->prev_orientation == ORIENTATION_UNDEFINED) { g_debug ("Not trying to rotate, orientation is undefined"); return; } rotation = orientation_to_rotation (manager->priv->prev_orientation); do_xrandr_action (manager, rotation); } static void orientation_lock_changed_cb (GSettings *settings, gchar *key, CsdOrientationManager *manager) { gboolean new; new = g_settings_get_boolean (settings, ORIENTATION_LOCK_KEY); if (new == manager->priv->orientation_lock) return; manager->priv->orientation_lock = new; if (new == FALSE) { if (is_mpu6050) { g_timeout_add_seconds(MPU_POLL_INTERVAL, (GSourceFunc) mpu_timer, manager); } /* Handle the rotations that could have occurred while * we were locked */ do_rotation (manager); } } static void properties_changed (GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, gpointer user_data) { CsdOrientationManager *manager = user_data; CsdOrientationManagerPrivate *p = manager->priv; GVariant *v; GVariantDict dict; if (manager->priv->xrandr_proxy == NULL) return; if (changed_properties) g_variant_dict_init (&dict, changed_properties); if (changed_properties == NULL || g_variant_dict_contains (&dict, "HasAccelerometer")) { v = g_dbus_proxy_get_cached_property (p->iio_proxy, "HasAccelerometer"); if (v == NULL) { g_debug ("Couldn't fetch HasAccelerometer property"); return; } p->has_accel = g_variant_get_boolean (v); if (!p->has_accel) p->prev_orientation = ORIENTATION_UNDEFINED; g_variant_unref (v); } if (changed_properties == NULL || g_variant_dict_contains (&dict, "AccelerometerOrientation")) { if (p->has_accel) { OrientationUp orientation; orientation = get_orientation_from_device (manager); if (orientation != p->prev_orientation) { p->prev_orientation = orientation; g_debug ("Orientation changed to '%s', switching screen rotation", orientation_to_string (p->prev_orientation)); do_rotation (manager); } } } } static void xrandr_ready_cb (GObject *source_object, GAsyncResult *res, CsdOrientationManager *manager) { CsdOrientationManagerPrivate *p = manager->priv; GError *error = NULL; manager->priv->xrandr_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->xrandr_proxy == NULL) { g_warning ("Failed to get proxy for XRandR operations: %s", error->message); g_error_free (error); } if (p->iio_proxy == NULL) return; properties_changed (manager->priv->iio_proxy, NULL, NULL, manager); } static int read_sysfs_attr_as_int(const char *filename) { int i, c; char buf[40]; int fd = open(filename, O_RDONLY); if (fd < 0) return 0; c = read(fd, buf, 40); if (c < 0) return 0; close(fd); sscanf(buf, "%d", &i); return i; } static gboolean mpu_timer(CsdOrientationManager *manager) { int x, y; static gboolean first = TRUE; OrientationUp orientation = manager->priv->prev_orientation; if (manager->priv->xrandr_proxy == NULL) return TRUE; x = read_sysfs_attr_as_int(mpu6050_accel_x); y = read_sysfs_attr_as_int(mpu6050_accel_y); if (x > MPU_THRESHOLD) orientation = ORIENTATION_NORMAL; if (x < -MPU_THRESHOLD) orientation = ORIENTATION_BOTTOM_UP; if (y > MPU_THRESHOLD) orientation = ORIENTATION_RIGHT_UP; if (y < -MPU_THRESHOLD) orientation = ORIENTATION_LEFT_UP; if (orientation != manager->priv->prev_orientation || first) { first = FALSE; manager->priv->prev_orientation = orientation; g_debug ("Orientation changed to '%s', switching screen rotation", orientation_to_string (manager->priv->prev_orientation)); do_rotation (manager); } return !manager->priv->orientation_lock; } static void iio_sensor_appeared_cb (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) { CsdOrientationManager *manager = user_data; CsdOrientationManagerPrivate *p = manager->priv; GError *error = NULL; p->iio_proxy = g_dbus_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE, NULL, "net.hadess.SensorProxy", "/net/hadess/SensorProxy", "net.hadess.SensorProxy", NULL, &error); if (p->iio_proxy == NULL) { g_warning ("Failed to access net.hadess.SensorProxy after it appeared"); return; } g_dbus_proxy_call_sync (p->iio_proxy, "ClaimAccelerometer", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); g_signal_connect (G_OBJECT (manager->priv->iio_proxy), "g-properties-changed", G_CALLBACK (properties_changed), manager); properties_changed (manager->priv->iio_proxy, NULL, NULL, manager); } static void iio_sensor_vanished_cb (GDBusConnection *connection, const gchar *name, gpointer user_data) { CsdOrientationManager *manager = user_data; g_clear_object (&manager->priv->iio_proxy); manager->priv->has_accel = FALSE; manager->priv->prev_orientation = ORIENTATION_UNDEFINED; } gboolean csd_orientation_manager_start (CsdOrientationManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); manager->priv->settings = g_settings_new (CONF_SCHEMA); g_signal_connect (G_OBJECT (manager->priv->settings), "changed::" ORIENTATION_LOCK_KEY, G_CALLBACK (orientation_lock_changed_cb), manager); manager->priv->orientation_lock = g_settings_get_boolean (manager->priv->settings, ORIENTATION_LOCK_KEY); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.cinnamon.SettingsDaemon.XRANDR_2", "/org/cinnamon/SettingsDaemon/XRANDR", "org.cinnamon.SettingsDaemon.XRANDR_2", NULL, (GAsyncReadyCallback) xrandr_ready_cb, manager); manager->priv->watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM, "net.hadess.SensorProxy", G_BUS_NAME_WATCHER_FLAGS_NONE, iio_sensor_appeared_cb, iio_sensor_vanished_cb, manager, NULL); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_orientation_manager_stop (CsdOrientationManager *manager) { CsdOrientationManagerPrivate *p = manager->priv; g_debug ("Stopping orientation manager"); if (p->watch_id > 0) { g_bus_unwatch_name (p->watch_id); p->watch_id = 0; } if (p->iio_proxy) { g_dbus_proxy_call_sync (p->iio_proxy, "ReleaseAccelerometer", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); g_clear_object (&p->iio_proxy); } g_clear_object (&p->xrandr_proxy); g_clear_object (&p->settings); p->has_accel = FALSE; if (p->cancellable) { g_cancellable_cancel (p->cancellable); g_clear_object (&p->cancellable); } } static void csd_orientation_manager_finalize (GObject *object) { CsdOrientationManager *orientation_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_ORIENTATION_MANAGER (object)); orientation_manager = CSD_ORIENTATION_MANAGER (object); g_return_if_fail (orientation_manager->priv != NULL); csd_orientation_manager_stop (orientation_manager); G_OBJECT_CLASS (csd_orientation_manager_parent_class)->finalize (object); } CsdOrientationManager * csd_orientation_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_ORIENTATION_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_ORIENTATION_MANAGER (manager_object); } cinnamon-settings-daemon-5.2.0/plugins/orientation/csd-orientation-manager.h0000664000175000017500000000472314144454032026251 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2010 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CSD_ORIENTATION_MANAGER_H #define __CSD_ORIENTATION_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_ORIENTATION_MANAGER (csd_orientation_manager_get_type ()) #define CSD_ORIENTATION_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_ORIENTATION_MANAGER, CsdOrientationManager)) #define CSD_ORIENTATION_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_ORIENTATION_MANAGER, CsdOrientationManagerClass)) #define CSD_IS_ORIENTATION_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_ORIENTATION_MANAGER)) #define CSD_IS_ORIENTATION_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_ORIENTATION_MANAGER)) #define CSD_ORIENTATION_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_ORIENTATION_MANAGER, CsdOrientationManagerClass)) typedef struct CsdOrientationManagerPrivate CsdOrientationManagerPrivate; typedef struct { GObject parent; CsdOrientationManagerPrivate *priv; } CsdOrientationManager; typedef struct { GObjectClass parent_class; } CsdOrientationManagerClass; GType csd_orientation_manager_get_type (void); CsdOrientationManager * csd_orientation_manager_new (void); gboolean csd_orientation_manager_start (CsdOrientationManager *manager, GError **error); void csd_orientation_manager_stop (CsdOrientationManager *manager); G_END_DECLS #endif /* __CSD_ORIENTATION_MANAGER_H */ cinnamon-settings-daemon-5.2.0/plugins/orientation/cinnamon-settings-daemon-orientation.desktop.in0000664000175000017500000000034614144454032032615 0ustar fabiofabio[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - orientation Exec=csd-orientation OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-5.2.0/plugins/xsettings/0000775000175000017500000000000014144454032021055 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/xsettings/fontconfig-monitor.h0000664000175000017500000000254414144454032025054 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Author: Behdad Esfahbod, Red Hat, Inc. */ #ifndef __FONTCONFIG_MONITOR_H #define __FONTCONFIG_MONITOR_H #include G_BEGIN_DECLS void fontconfig_cache_init (void); gboolean fontconfig_cache_update (void); typedef struct _fontconfig_monitor_handle fontconfig_monitor_handle_t; fontconfig_monitor_handle_t * fontconfig_monitor_start (GFunc notify_callback, gpointer notify_data); void fontconfig_monitor_stop (fontconfig_monitor_handle_t *handle); G_END_DECLS #endif /* __FONTCONFIG_MONITOR_H */ cinnamon-settings-daemon-5.2.0/plugins/xsettings/csd-xsettings-manager.h0000664000175000017500000000514714144454032025444 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CINNAMON_XSETTINGS_MANAGER_H #define __CINNAMON_XSETTINGS_MANAGER_H #include G_BEGIN_DECLS #define CINNAMON_TYPE_XSETTINGS_MANAGER (cinnamon_xsettings_manager_get_type ()) #define CINNAMON_XSETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CINNAMON_TYPE_XSETTINGS_MANAGER, CinnamonSettingsXSettingsManager)) #define CINNAMON_XSETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CINNAMON_TYPE_XSETTINGS_MANAGER, CinnamonSettingsXSettingsManagerClass)) #define CINNAMON_IS_XSETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CINNAMON_TYPE_XSETTINGS_MANAGER)) #define CINNAMON_IS_XSETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CINNAMON_TYPE_XSETTINGS_MANAGER)) #define CINNAMON_XSETTINGS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CINNAMON_TYPE_XSETTINGS_MANAGER, CinnamonSettingsXSettingsManagerClass)) typedef struct CinnamonSettingsXSettingsManagerPrivate CinnamonSettingsXSettingsManagerPrivate; typedef struct { GObject parent; CinnamonSettingsXSettingsManagerPrivate *priv; } CinnamonSettingsXSettingsManager; typedef struct { GObjectClass parent_class; } CinnamonSettingsXSettingsManagerClass; GType cinnamon_xsettings_manager_get_type (void); CinnamonSettingsXSettingsManager * cinnamon_xsettings_manager_new (void); gboolean cinnamon_xsettings_manager_start (CinnamonSettingsXSettingsManager *manager, GError **error); void cinnamon_xsettings_manager_stop (CinnamonSettingsXSettingsManager *manager); G_END_DECLS #endif /* __CINNAMON_XSETTINGS_MANAGER_H */ cinnamon-settings-daemon-5.2.0/plugins/xsettings/xsettings-common.c0000664000175000017500000000561414144454032024545 0ustar fabiofabio/* * Copyright © 2001 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Owen Taylor, Red Hat, Inc. */ #include #include "string.h" #include "stdlib.h" #include #include /* For CARD32 */ #include "xsettings-common.h" XSettingsSetting * xsettings_setting_new (const gchar *name) { XSettingsSetting *result; result = g_slice_new0 (XSettingsSetting); result->name = g_strdup (name); return result; } static gboolean xsettings_variant_equal0 (GVariant *a, GVariant *b) { if (a == b) return TRUE; if (!a || !b) return FALSE; return g_variant_equal (a, b); } GVariant * xsettings_setting_get (XSettingsSetting *setting) { gint i; for (i = G_N_ELEMENTS (setting->value) - 1; 0 <= i; i--) if (setting->value[i]) return setting->value[i]; return NULL; } void xsettings_setting_set (XSettingsSetting *setting, gint tier, GVariant *value, guint32 serial) { GVariant *old_value; old_value = xsettings_setting_get (setting); if (old_value) g_variant_ref (old_value); if (setting->value[tier]) g_variant_unref (setting->value[tier]); setting->value[tier] = value ? g_variant_ref_sink (value) : NULL; if (!xsettings_variant_equal0 (old_value, xsettings_setting_get (setting))) setting->last_change_serial = serial; if (old_value) g_variant_unref (old_value); } void xsettings_setting_free (XSettingsSetting *setting) { gint i; for (i = 0; i < G_N_ELEMENTS (setting->value); i++) if (setting->value[i]) g_variant_unref (setting->value[i]); g_free (setting->name); g_slice_free (XSettingsSetting, setting); } char xsettings_byte_order (void) { CARD32 myint = 0x01020304; return (*(char *)&myint == 1) ? MSBFirst : LSBFirst; } cinnamon-settings-daemon-5.2.0/plugins/xsettings/xsettings-common.h0000664000175000017500000000442714144454032024553 0ustar fabiofabio/* * Copyright © 2001 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Owen Taylor, Red Hat, Inc. */ #ifndef XSETTINGS_COMMON_H #define XSETTINGS_COMMON_H #include #define XSETTINGS_N_TIERS 2 typedef struct _XSettingsColor XSettingsColor; typedef struct _XSettingsSetting XSettingsSetting; /* Types of settings possible. Enum values correspond to * protocol values. */ typedef enum { XSETTINGS_TYPE_INT = 0, XSETTINGS_TYPE_STRING = 1, XSETTINGS_TYPE_COLOR = 2 } XSettingsType; struct _XSettingsColor { unsigned short red, green, blue, alpha; }; struct _XSettingsSetting { char *name; GVariant *value[XSETTINGS_N_TIERS]; unsigned long last_change_serial; }; XSettingsSetting *xsettings_setting_new (const gchar *name); GVariant * xsettings_setting_get (XSettingsSetting *setting); void xsettings_setting_set (XSettingsSetting *setting, gint tier, GVariant *value, guint32 serial); void xsettings_setting_free (XSettingsSetting *setting); char xsettings_byte_order (void); #endif /* XSETTINGS_COMMON_H */ cinnamon-settings-daemon-5.2.0/plugins/xsettings/meson.build0000664000175000017500000000301214144454032023213 0ustar fabiofabioplugin_name = 'xsettings' xsettings_common_sources = [ 'csd-xsettings-gtk.c', ] xsettings_sources = [ 'csd-xsettings-manager.c', 'xsettings-common.c', 'xsettings-manager.c', 'fontconfig-monitor.c', 'main.c', xsettings_common_sources, ] test_xsettings_sources = [ 'test-gtk-modules.c', xsettings_common_sources, ] xsettings_deps = [ cinnamon_desktop, common_dep, csd_dep, fontconfig, libnotify, ] executable( 'csd-xsettings', xsettings_sources, include_directories: [include_dirs, common_inc, include_enums], dependencies: xsettings_deps, c_args: [ '-DPLUGIN_NAME="@0@"'.format(plugin_name), '-DGTK_MODULES_DIRECTORY="@0@/@1@/cinnamon-settings-daemon-@2@/gtk-modules/"'.format(prefix, libdir, api_version), ], install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-xsettings') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-xsettings') endif executable( 'test-gtk-modules', test_xsettings_sources, include_directories: [include_dirs, common_inc], dependencies: xsettings_deps, c_args: [ '-DGTK_MODULES_DIRECTORY="@0@/@1@/cinnamon-settings-daemon-@2@/gtk-modules/"'.format(prefix, libdir, api_version), ], ) configure_file( input: 'cinnamon-settings-daemon-xsettings.desktop.in', output: 'cinnamon-settings-daemon-xsettings.desktop', configuration: desktop_conf, install_dir: autostartdir, ) cinnamon-settings-daemon-5.2.0/plugins/xsettings/cinnamon-settings-daemon-xsettings.desktop.in0000664000175000017500000000034214144454032032003 0ustar fabiofabio[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - xsettings Exec=csd-xsettings OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-5.2.0/plugins/xsettings/csd-xsettings-manager.c0000664000175000017500000012756314144454032025446 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Rodrigo Moya * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-enums.h" #include "csd-xsettings-manager.h" #include "csd-xsettings-gtk.h" #include "xsettings-manager.h" #include "fontconfig-monitor.h" #define GNOME_DESKTOP_USE_UNSTABLE_API #include #define CINNAMON_XSETTINGS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CINNAMON_TYPE_XSETTINGS_MANAGER, CinnamonSettingsXSettingsManagerPrivate)) #define MOUSE_SETTINGS_SCHEMA "org.cinnamon.settings-daemon.peripherals.mouse" #define INTERFACE_SETTINGS_SCHEMA "org.cinnamon.desktop.interface" #define INTERFACE_WM_SETTINGS_SCHEMA "org.cinnamon.desktop.wm.preferences" #define SOUND_SETTINGS_SCHEMA "org.cinnamon.desktop.sound" #define PRIVACY_SETTINGS_SCHEMA "org.cinnamon.desktop.privacy" #define XSETTINGS_PLUGIN_SCHEMA "org.cinnamon.settings-daemon.plugins.xsettings" #define XSETTINGS_OVERRIDE_KEY "overrides" #define GTK_MODULES_DISABLED_KEY "disabled-gtk-modules" #define GTK_MODULES_ENABLED_KEY "enabled-gtk-modules" #define TEXT_SCALING_FACTOR_KEY "text-scaling-factor" #define SCALING_FACTOR_KEY "scaling-factor" #define CURSOR_SIZE_KEY "cursor-size" #define FONT_ANTIALIASING_KEY "antialiasing" #define FONT_HINTING_KEY "hinting" #define FONT_RGBA_ORDER_KEY "rgba-order" /* As we cannot rely on the X server giving us good DPI information, and * that we don't want multi-monitor screens to have different DPIs (thus * different text sizes), we'll hard-code the value of the DPI * * See also: * https://bugzilla.novell.com/show_bug.cgi?id=217790• * https://bugzilla.gnome.org/show_bug.cgi?id=643704 * * http://lists.fedoraproject.org/pipermail/devel/2011-October/157671.html * Why EDID is not trustworthy for DPI * Adam Jackson ajax at redhat.com * Tue Oct 4 17:54:57 UTC 2011 * * Previous message: GNOME 3 - font point sizes now scaled? * Next message: Why EDID is not trustworthy for DPI * Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] * * On Tue, 2011-10-04 at 11:46 -0400, Kaleb S. KEITHLEY wrote: * * > Grovelling around in the F15 xorg-server sources and reviewing the Xorg * > log file on my F15 box, I see, with _modern hardware_ at least, that we * > do have the monitor geometry available from DDC or EDIC, and obviously * > it is trivial to compute the actual, correct DPI for each screen. * * I am clearly going to have to explain this one more time, forever. * Let's see if I can't write it authoritatively once and simply answer * with a URL from here out. (As always, use of the second person "you" * herein is plural, not singular.) * * EDID does not reliably give you the size of the display. * * Base EDID has at least two different places where you can give a * physical size (before considering extensions that aren't widely deployed * so whatever). The first is a global property, measured in centimeters, * of the physical size of the glass. The second is attached to your (zero * or more) detailed timing specifications, and reflects the size of the * mode, in millimeters. * * So, how does this screw you? * * a) Glass size is too coarse. On a large display that cm roundoff isn't * a big deal, but on subnotebooks it's a different game. The 11" MBA is * 25.68x14.44 cm, so that gives you a range of 52.54-54.64 dpcm horizontal * and 51.20-54.86 dpcm vertical (133.4-138.8 dpi h and 130.0-139.3 dpi v). * Which is optimistic, because that's doing the math forward from knowing * the actual size, and you as the EDID parser can't know which way the * manufacturer rounded. * * b) Glass size need not be non-zero. This is in fact the usual case for * projectors, which don't have a fixed display size since it's a function * of how far away the wall is from the lens. * * c) Glass size could be partially non-zero. Yes, really. EDID 1.4 * defines a method of using these two bytes to encode aspect ratio, where * if vertical size is 0 then the aspect ratio is computed as (horizontal * value + 99) / 100 in portrait mode (and the obvious reverse thing if * horizontal is zero). Admittedly, unlike every other item in this list, * I've never seen this in the wild. But it's legal. * * d) Glass size could be a direct encoding of the aspect ratio. Base EDID * doesn't condone this behaviour, but the CEA spec (to which all HDMI * monitors must conform) does allow-but-not-require it, which means your * 1920x1080 TV could claim to be 16 "cm" by 9 "cm". So of course that's * what TV manufacturers do because that way they don't have to modify the * EDID info when physical construction changes, and that's cheaper. * * e) You could use mode size to get size in millimeters, but you might not * have any detailed timings. * * f) You could use mode size, but mode size is explicitly _not_ glass * size. It's the size that the display chooses to present that mode. * Sometimes those are the same, and sometimes they're not. You could be * scaled or {letter,pillar}boxed, and that's not necessarily something you * can control from the host side. * * g) You could use mode size, but it could be an encoded aspect ratio, as * in case d above, because CEA says that's okay. * * h) You could use mode size, but it could be the aspect ratio from case d * multiplied by 10 in each direction (because, of course, you gave size in * centimeters and so your authoring tool just multiplied it up). * * i) Any or all of the above could be complete and utter garbage, because * - and I really, really need you to understand this - there is no * requirements program for any commercial OS or industry standard that * requires honesty here, as far as I'm aware. There is every incentive * for there to _never_ be one, because it would make the manufacturing * process more expensive. * * So from this point the suggestion is usually "well come up with some * heuristic to make a good guess assuming there's some correlation between * the various numbers you're given". I have in fact written heuristics * for this, and they're in your kernel and your X server, and they still * encounter a huge number of cases where we simply _cannot_ know from EDID * anything like a physical size, because - to pick only one example - the * consumer electronics industry are cheap bastards, because you the * consumer demanded that they be cheap. * * And then your only recourse is to an external database, and now you're * up the creek again because the identifying information here is a * vendor/model/serial tuple, and the vendor can and does change physical * construction without changing model number. Now you get to play the * guessing game of how big the serial number range is for each subvariant, * assuming they bothered to encode a serial number - and they didn't. Or, * if they bothered to encode week/year of manufacturer correctly - and * they didn't - which weeks meant which models. And then you still have * to go out and buy one of every TV at Fry's, and that covers you for one * market, for three months. * * If someone wants to write something better, please, by all means. If * it's kernel code, send it to dri-devel at lists.freedesktop.org and cc me * and I will happily review it. Likewise xorg-devel@ for X server * changes. * * I gently suggest that doing so is a waste of time. * * But if there's one thing free software has taught me, it's that you can * not tell people something is a bad idea and have any expectation they * will believe you. * * > Obviously in a multi-screen set-up using Xinerama this has the potential * > to be a Hard Problem if the monitors differ greatly in their DPI. * > * > If the major resistance is over what to do with older hardware that * > doesn't have this data available, then yes, punt; use a hard-coded * > default. Likewise, if the two monitors really differ greatly, then punt. * * I'm going to limit myself to observing that "greatly" is a matter of * opinion, and that in order to be really useful you'd need some way of * communicating "I punted" to the desktop. * * Beyond that, sure, pick a heuristic, accept that it's going to be * insufficient for someone, and then sit back and wait to get * second-guessed on it over and over. * * > And it wouldn't be so hard to to add something like -dpi:0, -dpi:1, * > -dpi:2 command line options to specify per-screen dpi. I kinda thought I * > did that a long, long time ago, but maybe I only thought about doing it * > and never actually got around to it. * * The RANDR extension as of version 1.2 does allow you to override * physical size on a per-output basis at runtime. We even try pretty hard * to set them as honestly as we can up front. The 96dpi thing people * complain about is from the per-screen info, which is simply a default * because of all the tl;dr above; because you have N outputs per screen * which means a single number is in general useless; and because there is * no way to refresh the per-screen info at runtime, as it's only ever sent * in the initial connection handshake. * * - ajax * */ #define DPI_FALLBACK 96 typedef struct _TranslationEntry TranslationEntry; typedef void (* TranslationFunc) (CinnamonSettingsXSettingsManager *manager, TranslationEntry *trans, GVariant *value); struct _TranslationEntry { const char *gsettings_schema; const char *gsettings_key; const char *xsetting_name; TranslationFunc translate; }; struct CinnamonSettingsXSettingsManagerPrivate { guint start_idle_id; XSettingsManager **managers; GHashTable *settings; GSettings *plugin_settings; fontconfig_monitor_handle_t *fontconfig_handle; CsdXSettingsGtk *gtk; guint notify_idle_id; }; #define CSD_XSETTINGS_ERROR csd_xsettings_error_quark () enum { CSD_XSETTINGS_ERROR_INIT }; static void cinnamon_xsettings_manager_finalize (GObject *object); G_DEFINE_TYPE (CinnamonSettingsXSettingsManager, cinnamon_xsettings_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static GQuark csd_xsettings_error_quark (void) { return g_quark_from_static_string ("csd-xsettings-error-quark"); } static void translate_bool_int (CinnamonSettingsXSettingsManager *manager, TranslationEntry *trans, GVariant *value) { int i; for (i = 0; manager->priv->managers [i]; i++) { xsettings_manager_set_int (manager->priv->managers [i], trans->xsetting_name, g_variant_get_boolean (value)); } } static void translate_int_int (CinnamonSettingsXSettingsManager *manager, TranslationEntry *trans, GVariant *value) { int i; for (i = 0; manager->priv->managers [i]; i++) { xsettings_manager_set_int (manager->priv->managers [i], trans->xsetting_name, g_variant_get_int32 (value)); } } static void translate_string_string (CinnamonSettingsXSettingsManager *manager, TranslationEntry *trans, GVariant *value) { int i; for (i = 0; manager->priv->managers [i]; i++) { xsettings_manager_set_string (manager->priv->managers [i], trans->xsetting_name, g_variant_get_string (value, NULL)); } } static void translate_string_string_toolbar (CinnamonSettingsXSettingsManager *manager, TranslationEntry *trans, GVariant *value) { int i; const char *tmp; /* This is kind of a workaround since GNOME expects the key value to be * "both_horiz" and gtk+ wants the XSetting to be "both-horiz". */ tmp = g_variant_get_string (value, NULL); if (tmp && strcmp (tmp, "both_horiz") == 0) { tmp = "both-horiz"; } for (i = 0; manager->priv->managers [i]; i++) { xsettings_manager_set_string (manager->priv->managers [i], trans->xsetting_name, tmp); } } static void translate_string_string_window_buttons (CinnamonSettingsXSettingsManager *manager, TranslationEntry *trans, GVariant *value) { int i; const char *tmp; gchar *ptr, *final_str; /* This is kind of a workaround. "menu" is useless in metacity titlebars * it duplicates the same features as the right-click menu. * In CSD windows on the hand it is required to show unique featues. */ tmp = g_variant_get_string (value, NULL); /* Check if menu is in the setting string already */ ptr = g_strstr_len (tmp, -1, "menu"); if (!ptr) { /* If it wasn't there already, we add it... */ /* Simple cases, :* - all items on right, just prepend menu on left side*/ if (g_str_has_prefix (tmp, ":")) { final_str = g_strdup_printf ("menu%s", tmp); } else /* All items on left... * (no :), append menu - we want actual window controls on the outside */ if (!g_strstr_len (tmp, -1, ":")) { final_str = g_strdup_printf ("%s,menu", tmp); } else { /* Items on both sides, split it, append menu to the lefthand, and re- * construct the string with the : separator */ gchar **split = g_strsplit (tmp, ":", 2); final_str = g_strdup_printf ("%s,menu:%s", split[0], split[1]); g_strfreev (split); } } else { /* If menu was already included, just copy the original string */ final_str = g_strdup (tmp); } for (i = 0; manager->priv->managers [i]; i++) { xsettings_manager_set_string (manager->priv->managers [i], trans->xsetting_name, final_str); } g_free (final_str); } static TranslationEntry translations [] = { { "org.cinnamon.settings-daemon.peripherals.mouse", "double-click", "Net/DoubleClickTime", translate_int_int }, { "org.cinnamon.settings-daemon.peripherals.mouse", "drag-threshold", "Net/DndDragThreshold", translate_int_int }, { "org.cinnamon.desktop.interface", "gtk-color-palette", "Gtk/ColorPalette", translate_string_string }, { "org.cinnamon.desktop.interface", "font-name", "Gtk/FontName", translate_string_string }, { "org.cinnamon.desktop.interface", "gtk-key-theme", "Gtk/KeyThemeName", translate_string_string }, { "org.cinnamon.desktop.interface", "toolbar-style", "Gtk/ToolbarStyle", translate_string_string_toolbar }, { "org.cinnamon.desktop.interface", "toolbar-icons-size", "Gtk/ToolbarIconSize", translate_string_string }, { "org.cinnamon.desktop.interface", "can-change-accels", "Gtk/CanChangeAccels", translate_bool_int }, { "org.cinnamon.desktop.interface", "cursor-blink", "Net/CursorBlink", translate_bool_int }, { "org.cinnamon.desktop.interface", "cursor-blink-time", "Net/CursorBlinkTime", translate_int_int }, { "org.cinnamon.desktop.interface", "cursor-blink-timeout", "Gtk/CursorBlinkTimeout", translate_int_int }, { "org.cinnamon.desktop.interface", "gtk-theme", "Net/ThemeName", translate_string_string }, { "org.cinnamon.desktop.interface", "gtk-timeout-initial", "Gtk/TimeoutInitial", translate_int_int }, { "org.cinnamon.desktop.interface", "gtk-timeout-repeat", "Gtk/TimeoutRepeat", translate_int_int }, { "org.cinnamon.desktop.interface", "gtk-color-scheme", "Gtk/ColorScheme", translate_string_string }, { "org.cinnamon.desktop.interface", "gtk-im-preedit-style", "Gtk/IMPreeditStyle", translate_string_string }, { "org.cinnamon.desktop.interface", "gtk-im-status-style", "Gtk/IMStatusStyle", translate_string_string }, { "org.cinnamon.desktop.interface", "gtk-im-module", "Gtk/IMModule", translate_string_string }, { "org.cinnamon.desktop.interface", "icon-theme", "Net/IconThemeName", translate_string_string }, { "org.cinnamon.settings-daemon.plugins.xsettings", "menus-have-icons", "Gtk/MenuImages", translate_bool_int }, { "org.cinnamon.settings-daemon.plugins.xsettings", "buttons-have-icons", "Gtk/ButtonImages", translate_bool_int }, { "org.cinnamon.desktop.interface", "menubar-accel", "Gtk/MenuBarAccel", translate_string_string }, { "org.cinnamon.desktop.interface", "enable-animations", "Gtk/EnableAnimations", translate_bool_int }, { "org.cinnamon.desktop.interface", "cursor-theme", "Gtk/CursorThemeName", translate_string_string }, { "org.cinnamon.desktop.wm.preferences", "button-layout", "Gtk/DecorationLayout", translate_string_string_window_buttons }, { "org.cinnamon.desktop.wm.preferences", "action-double-click-titlebar", "Gtk/TitlebarDoubleClick", translate_string_string }, { "org.cinnamon.desktop.wm.preferences", "action-middle-click-titlebar", "Gtk/TitlebarMiddleClick", translate_string_string }, { "org.cinnamon.desktop.wm.preferences", "action-right-click-titlebar", "Gtk/TitlebarRightClick", translate_string_string }, { "org.cinnamon.settings-daemon.plugins.xsettings", "show-input-method-menu", "Gtk/ShowInputMethodMenu", translate_bool_int }, { "org.cinnamon.settings-daemon.plugins.xsettings", "show-unicode-menu", "Gtk/ShowUnicodeMenu", translate_bool_int }, { "org.cinnamon.settings-daemon.plugins.xsettings", "automatic-mnemonics", "Gtk/AutoMnemonics", translate_bool_int }, { "org.cinnamon.desktop.sound", "theme-name", "Net/SoundThemeName", translate_string_string }, { "org.cinnamon.desktop.sound", "event-sounds", "Net/EnableEventSounds" , translate_bool_int }, { "org.cinnamon.desktop.sound", "input-feedback-sounds", "Net/EnableInputFeedbackSounds", translate_bool_int }, { "org.cinnamon.desktop.privacy", "recent-files-max-age", "Gtk/RecentFilesMaxAge", translate_int_int }, { "org.cinnamon.desktop.privacy", "remember-recent-files", "Gtk/RecentFilesEnabled", translate_bool_int } }; static gboolean notify_idle (gpointer data) { CinnamonSettingsXSettingsManager *manager = data; gint i; for (i = 0; manager->priv->managers [i]; i++) { xsettings_manager_notify (manager->priv->managers[i]); } manager->priv->notify_idle_id = 0; return G_SOURCE_REMOVE; } static void queue_notify (CinnamonSettingsXSettingsManager *manager) { if (manager->priv->notify_idle_id != 0) return; manager->priv->notify_idle_id = g_idle_add (notify_idle, manager); } static double get_dpi_from_gsettings (CinnamonSettingsXSettingsManager *manager) { GSettings *interface_settings; double dpi; double factor; interface_settings = g_hash_table_lookup (manager->priv->settings, INTERFACE_SETTINGS_SCHEMA); factor = g_settings_get_double (interface_settings, TEXT_SCALING_FACTOR_KEY); dpi = DPI_FALLBACK; return dpi * factor; } static int get_window_scale (CinnamonSettingsXSettingsManager *manager) { GSettings *interface_settings; GError *error = NULL; int window_scale; interface_settings = g_hash_table_lookup (manager->priv->settings, INTERFACE_SETTINGS_SCHEMA); window_scale = g_settings_get_uint (interface_settings, SCALING_FACTOR_KEY); if (window_scale == 0) { GnomeRRScreen *screen = gnome_rr_screen_new (gdk_screen_get_default (), &error); if (!error) { window_scale = gnome_rr_screen_calculate_best_global_scale (screen, -1); g_object_unref (screen); } else { g_warning ("Could not get/create GnomeRRScreen instance: %s", error->message); g_error_free (error); } } return window_scale; } typedef struct { gboolean antialias; gboolean hinting; int scaled_dpi; int dpi; int window_scale; int cursor_size; const char *rgba; const char *hintstyle; } CinnamonSettingsXftSettings; /* Read GSettings and determine the appropriate Xft settings based on them. */ static void xft_settings_get (CinnamonSettingsXSettingsManager *manager, CinnamonSettingsXftSettings *settings) { GSettings *interface_settings; CsdFontAntialiasingMode antialiasing; CsdFontHinting hinting; CsdFontRgbaOrder order; gboolean use_rgba = FALSE; double dpi; int cursor_size; interface_settings = g_hash_table_lookup (manager->priv->settings, INTERFACE_SETTINGS_SCHEMA); antialiasing = g_settings_get_enum (manager->priv->plugin_settings, FONT_ANTIALIASING_KEY); hinting = g_settings_get_enum (manager->priv->plugin_settings, FONT_HINTING_KEY); order = g_settings_get_enum (manager->priv->plugin_settings, FONT_RGBA_ORDER_KEY); settings->antialias = (antialiasing != CSD_FONT_ANTIALIASING_MODE_NONE); settings->hinting = (hinting != CSD_FONT_HINTING_NONE); settings->window_scale = get_window_scale (manager); dpi = get_dpi_from_gsettings (manager); settings->dpi = dpi * 1024; /* Xft wants 1/1024ths of an inch */ settings->scaled_dpi = dpi * settings->window_scale * 1024; cursor_size = g_settings_get_int (interface_settings, CURSOR_SIZE_KEY); settings->cursor_size = cursor_size * settings->window_scale; settings->rgba = "rgb"; settings->hintstyle = "hintfull"; switch (hinting) { case CSD_FONT_HINTING_NONE: settings->hintstyle = "hintnone"; break; case CSD_FONT_HINTING_SLIGHT: settings->hintstyle = "hintslight"; break; case CSD_FONT_HINTING_MEDIUM: settings->hintstyle = "hintmedium"; break; case CSD_FONT_HINTING_FULL: settings->hintstyle = "hintfull"; break; } switch (order) { case CSD_FONT_RGBA_ORDER_RGBA: settings->rgba = "rgba"; break; case CSD_FONT_RGBA_ORDER_RGB: settings->rgba = "rgb"; break; case CSD_FONT_RGBA_ORDER_BGR: settings->rgba = "bgr"; break; case CSD_FONT_RGBA_ORDER_VRGB: settings->rgba = "vrgb"; break; case CSD_FONT_RGBA_ORDER_VBGR: settings->rgba = "vbgr"; break; } switch (antialiasing) { case CSD_FONT_ANTIALIASING_MODE_NONE: settings->antialias = 0; break; case CSD_FONT_ANTIALIASING_MODE_GRAYSCALE: settings->antialias = 1; break; case CSD_FONT_ANTIALIASING_MODE_RGBA: settings->antialias = 1; use_rgba = TRUE; } if (!use_rgba) { settings->rgba = "none"; } } static void xft_settings_set_xsettings (CinnamonSettingsXSettingsManager *manager, CinnamonSettingsXftSettings *settings) { int i; cinnamon_settings_profile_start (NULL); for (i = 0; manager->priv->managers [i]; i++) { xsettings_manager_set_int (manager->priv->managers [i], "Xft/Antialias", settings->antialias); xsettings_manager_set_int (manager->priv->managers [i], "Xft/Hinting", settings->hinting); xsettings_manager_set_string (manager->priv->managers [i], "Xft/HintStyle", settings->hintstyle); xsettings_manager_set_int (manager->priv->managers [i], "Gdk/WindowScalingFactor", settings->window_scale); xsettings_manager_set_int (manager->priv->managers [i], "Gdk/UnscaledDPI", settings->dpi); xsettings_manager_set_int (manager->priv->managers [i], "Xft/DPI", settings->scaled_dpi); xsettings_manager_set_string (manager->priv->managers [i], "Xft/RGBA", settings->rgba); xsettings_manager_set_int (manager->priv->managers [i], "Gtk/CursorThemeSize", settings->cursor_size); } cinnamon_settings_profile_end (NULL); } static void update_property (GString *props, const gchar* key, const gchar* value) { gchar* needle; size_t needle_len; gchar* found = NULL; /* update an existing property */ needle = g_strconcat (key, ":", NULL); needle_len = strlen (needle); if (g_str_has_prefix (props->str, needle)) found = props->str; else found = strstr (props->str, needle); if (found) { size_t value_index; gchar* end; end = strchr (found, '\n'); value_index = (found - props->str) + needle_len + 1; g_string_erase (props, value_index, end ? (end - found - needle_len) : -1); g_string_insert (props, value_index, "\n"); g_string_insert (props, value_index, value); } else { g_string_append_printf (props, "%s:\t%s\n", key, value); } g_free (needle); } static void xft_settings_set_xresources (CinnamonSettingsXftSettings *settings) { GString *add_string; char dpibuf[G_ASCII_DTOSTR_BUF_SIZE]; Display *dpy; cinnamon_settings_profile_start (NULL); /* get existing properties */ dpy = XOpenDisplay (NULL); g_return_if_fail (dpy != NULL); add_string = g_string_new (XResourceManagerString (dpy)); g_debug("xft_settings_set_xresources: orig res '%s'", add_string->str); update_property (add_string, "Xft.dpi", g_ascii_dtostr (dpibuf, sizeof (dpibuf), (double) settings->scaled_dpi / 1024.0)); update_property (add_string, "Xft.antialias", settings->antialias ? "1" : "0"); update_property (add_string, "Xft.hinting", settings->hinting ? "1" : "0"); update_property (add_string, "Xft.hintstyle", settings->hintstyle); update_property (add_string, "Xft.rgba", settings->rgba); g_debug("xft_settings_set_xresources: new res '%s'", add_string->str); /* Set the new X property */ XChangeProperty(dpy, RootWindow (dpy, 0), XA_RESOURCE_MANAGER, XA_STRING, 8, PropModeReplace, (const unsigned char *) add_string->str, add_string->len); XCloseDisplay (dpy); g_string_free (add_string, TRUE); cinnamon_settings_profile_end (NULL); } /* We mirror the Xft properties both through XSETTINGS and through * X resources */ static void update_xft_settings (CinnamonSettingsXSettingsManager *manager) { CinnamonSettingsXftSettings settings; cinnamon_settings_profile_start (NULL); xft_settings_get (manager, &settings); xft_settings_set_xsettings (manager, &settings); xft_settings_set_xresources (&settings); cinnamon_settings_profile_end (NULL); } static void xft_callback (GSettings *settings, const gchar *key, CinnamonSettingsXSettingsManager *manager) { update_xft_settings (manager); queue_notify (manager); } static void size_changed_callback (GdkScreen *screen, CinnamonSettingsXSettingsManager *manager) { update_xft_settings (manager); queue_notify (manager); } static void override_callback (GSettings *settings, const gchar *key, CinnamonSettingsXSettingsManager *manager) { GVariant *value; int i; value = g_settings_get_value (settings, XSETTINGS_OVERRIDE_KEY); for (i = 0; manager->priv->managers[i]; i++) { xsettings_manager_set_overrides (manager->priv->managers[i], value); } queue_notify (manager); g_variant_unref (value); } static void plugin_callback (GSettings *settings, const char *key, CinnamonSettingsXSettingsManager *manager) { if (g_str_equal (key, GTK_MODULES_DISABLED_KEY) || g_str_equal (key, GTK_MODULES_ENABLED_KEY)) { /* Do nothing, as CsdXsettingsGtk will handle it */ } else if (g_str_equal (key, XSETTINGS_OVERRIDE_KEY)) { override_callback (settings, key, manager); } else { xft_callback (settings, key, manager); } } static void gtk_modules_callback (CsdXSettingsGtk *gtk, GParamSpec *spec, CinnamonSettingsXSettingsManager *manager) { const char *modules = csd_xsettings_gtk_get_modules (manager->priv->gtk); int i; if (modules == NULL) { for (i = 0; manager->priv->managers [i]; ++i) { xsettings_manager_delete_setting (manager->priv->managers [i], "Gtk/Modules"); } } else { g_debug ("Setting GTK modules '%s'", modules); for (i = 0; manager->priv->managers [i]; ++i) { xsettings_manager_set_string (manager->priv->managers [i], "Gtk/Modules", modules); } } queue_notify (manager); } static void fontconfig_callback (fontconfig_monitor_handle_t *handle, CinnamonSettingsXSettingsManager *manager) { int i; int timestamp = time (NULL); cinnamon_settings_profile_start (NULL); for (i = 0; manager->priv->managers [i]; i++) { xsettings_manager_set_int (manager->priv->managers [i], "Fontconfig/Timestamp", timestamp); } queue_notify (manager); cinnamon_settings_profile_end (NULL); } static gboolean start_fontconfig_monitor_idle_cb (CinnamonSettingsXSettingsManager *manager) { cinnamon_settings_profile_start (NULL); manager->priv->fontconfig_handle = fontconfig_monitor_start ((GFunc) fontconfig_callback, manager); cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } static void start_fontconfig_monitor (CinnamonSettingsXSettingsManager *manager) { cinnamon_settings_profile_start (NULL); fontconfig_cache_init (); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_fontconfig_monitor_idle_cb, manager); cinnamon_settings_profile_end (NULL); } static void stop_fontconfig_monitor (CinnamonSettingsXSettingsManager *manager) { if (manager->priv->fontconfig_handle) { fontconfig_monitor_stop (manager->priv->fontconfig_handle); manager->priv->fontconfig_handle = NULL; } } static void process_value (CinnamonSettingsXSettingsManager *manager, TranslationEntry *trans, GVariant *value) { (* trans->translate) (manager, trans, value); } static TranslationEntry * find_translation_entry (GSettings *settings, const char *key) { guint i; char *schema; g_object_get (settings, "schema-id", &schema, NULL); for (i = 0; i < G_N_ELEMENTS (translations); i++) { if (g_str_equal (schema, translations[i].gsettings_schema) && g_str_equal (key, translations[i].gsettings_key)) { g_free (schema); return &translations[i]; } } g_free (schema); return NULL; } static void xsettings_callback (GSettings *settings, const char *key, CinnamonSettingsXSettingsManager *manager) { TranslationEntry *trans; guint i; GVariant *value; if (g_str_equal (key, TEXT_SCALING_FACTOR_KEY) || g_str_equal (key, SCALING_FACTOR_KEY) || g_str_equal (key, CURSOR_SIZE_KEY)) { xft_callback (NULL, key, manager); return; } trans = find_translation_entry (settings, key); if (trans == NULL) { return; } value = g_settings_get_value (settings, key); process_value (manager, trans, value); g_variant_unref (value); for (i = 0; manager->priv->managers [i]; i++) { xsettings_manager_set_string (manager->priv->managers [i], "Net/FallbackIconTheme", "gnome"); } queue_notify (manager); } static void terminate_cb (void *data) { gboolean *terminated = data; if (*terminated) { return; } *terminated = TRUE; g_warning ("X Settings Manager is terminating"); gtk_main_quit (); } static gboolean setup_xsettings_managers (CinnamonSettingsXSettingsManager *manager) { GdkDisplay *display; int i; int n_screens; gboolean res; gboolean terminated; display = gdk_display_get_default (); n_screens = gdk_display_get_n_screens (display); res = xsettings_manager_check_running (gdk_x11_display_get_xdisplay (display), gdk_screen_get_number (gdk_screen_get_default ())); if (res) { g_warning ("You can only run one xsettings manager at a time; exiting"); return FALSE; } manager->priv->managers = g_new0 (XSettingsManager *, n_screens + 1); terminated = FALSE; for (i = 0; i < n_screens; i++) { GdkScreen *screen; screen = gdk_display_get_screen (display, i); manager->priv->managers [i] = xsettings_manager_new (gdk_x11_display_get_xdisplay (display), gdk_screen_get_number (screen), terminate_cb, &terminated); if (! manager->priv->managers [i]) { g_warning ("Could not create xsettings manager for screen %d!", i); return FALSE; } g_signal_connect (screen, "size-changed", G_CALLBACK (size_changed_callback), manager); } return TRUE; } gboolean cinnamon_xsettings_manager_start (CinnamonSettingsXSettingsManager *manager, GError **error) { GVariant *overrides; guint i; GList *list, *l; g_debug ("Starting xsettings manager"); cinnamon_settings_profile_start (NULL); if (!setup_xsettings_managers (manager)) { g_set_error (error, CSD_XSETTINGS_ERROR, CSD_XSETTINGS_ERROR_INIT, "Could not initialize xsettings manager."); return FALSE; } manager->priv->settings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_object_unref); g_hash_table_insert (manager->priv->settings, MOUSE_SETTINGS_SCHEMA, g_settings_new (MOUSE_SETTINGS_SCHEMA)); g_hash_table_insert (manager->priv->settings, INTERFACE_SETTINGS_SCHEMA, g_settings_new (INTERFACE_SETTINGS_SCHEMA)); g_hash_table_insert (manager->priv->settings, INTERFACE_WM_SETTINGS_SCHEMA, g_settings_new (INTERFACE_WM_SETTINGS_SCHEMA)); g_hash_table_insert (manager->priv->settings, SOUND_SETTINGS_SCHEMA, g_settings_new (SOUND_SETTINGS_SCHEMA)); g_hash_table_insert (manager->priv->settings, XSETTINGS_PLUGIN_SCHEMA, g_settings_new (XSETTINGS_PLUGIN_SCHEMA)); g_hash_table_insert (manager->priv->settings, PRIVACY_SETTINGS_SCHEMA, g_settings_new (PRIVACY_SETTINGS_SCHEMA)); for (i = 0; i < G_N_ELEMENTS (translations); i++) { GVariant *val; GSettings *settings; settings = g_hash_table_lookup (manager->priv->settings, translations[i].gsettings_schema); if (settings == NULL) { g_warning ("Schemas '%s' has not been setup", translations[i].gsettings_schema); continue; } val = g_settings_get_value (settings, translations[i].gsettings_key); process_value (manager, &translations[i], val); g_variant_unref (val); } list = g_hash_table_get_values (manager->priv->settings); for (l = list; l != NULL; l = l->next) { g_signal_connect_object (G_OBJECT (l->data), "changed", G_CALLBACK (xsettings_callback), manager, 0); } g_list_free (list); /* Plugin settings (GTK modules and Xft) */ manager->priv->plugin_settings = g_settings_new (XSETTINGS_PLUGIN_SCHEMA); g_signal_connect_object (manager->priv->plugin_settings, "changed", G_CALLBACK (plugin_callback), manager, 0); manager->priv->gtk = csd_xsettings_gtk_new (); g_signal_connect (G_OBJECT (manager->priv->gtk), "notify::gtk-modules", G_CALLBACK (gtk_modules_callback), manager); gtk_modules_callback (manager->priv->gtk, NULL, manager); /* Xft settings */ update_xft_settings (manager); start_fontconfig_monitor (manager); overrides = g_settings_get_value (manager->priv->plugin_settings, XSETTINGS_OVERRIDE_KEY); for (i = 0; manager->priv->managers [i]; i++) { xsettings_manager_set_string (manager->priv->managers [i], "Net/FallbackIconTheme", "gnome"); xsettings_manager_set_overrides (manager->priv->managers [i], overrides); xsettings_manager_set_int (manager->priv->managers [i], "Gtk/ShellShowsAppMenu", FALSE); xsettings_manager_set_int (manager->priv->managers [i], "Gtk/ShellShowsMenubar", FALSE); } queue_notify (manager); g_variant_unref (overrides); cinnamon_settings_profile_end (NULL); return TRUE; } void cinnamon_xsettings_manager_stop (CinnamonSettingsXSettingsManager *manager) { CinnamonSettingsXSettingsManagerPrivate *p = manager->priv; int i; g_debug ("Stopping xsettings manager"); if (p->managers != NULL) { for (i = 0; p->managers [i]; ++i) xsettings_manager_destroy (p->managers [i]); g_free (p->managers); p->managers = NULL; } if (p->plugin_settings != NULL) { g_object_unref (p->plugin_settings); p->plugin_settings = NULL; } stop_fontconfig_monitor (manager); if (p->settings != NULL) { g_hash_table_destroy (p->settings); p->settings = NULL; } if (p->gtk != NULL) { g_object_unref (p->gtk); p->gtk = NULL; } } static GObject * cinnamon_xsettings_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CinnamonSettingsXSettingsManager *xsettings_manager; xsettings_manager = CINNAMON_XSETTINGS_MANAGER (G_OBJECT_CLASS (cinnamon_xsettings_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (xsettings_manager); } static void cinnamon_xsettings_manager_class_init (CinnamonSettingsXSettingsManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = cinnamon_xsettings_manager_constructor; object_class->finalize = cinnamon_xsettings_manager_finalize; g_type_class_add_private (klass, sizeof (CinnamonSettingsXSettingsManagerPrivate)); } static void cinnamon_xsettings_manager_init (CinnamonSettingsXSettingsManager *manager) { manager->priv = CINNAMON_XSETTINGS_MANAGER_GET_PRIVATE (manager); } static void cinnamon_xsettings_manager_finalize (GObject *object) { CinnamonSettingsXSettingsManager *xsettings_manager; g_return_if_fail (object != NULL); g_return_if_fail (CINNAMON_IS_XSETTINGS_MANAGER (object)); xsettings_manager = CINNAMON_XSETTINGS_MANAGER (object); g_return_if_fail (xsettings_manager->priv != NULL); if (xsettings_manager->priv->start_idle_id != 0) { g_source_remove (xsettings_manager->priv->start_idle_id); xsettings_manager->priv->start_idle_id = 0; } G_OBJECT_CLASS (cinnamon_xsettings_manager_parent_class)->finalize (object); } CinnamonSettingsXSettingsManager * cinnamon_xsettings_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CINNAMON_TYPE_XSETTINGS_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CINNAMON_XSETTINGS_MANAGER (manager_object); } cinnamon-settings-daemon-5.2.0/plugins/xsettings/main.c0000664000175000017500000000106614144454032022150 0ustar fabiofabio#define NEW cinnamon_xsettings_manager_new #define START cinnamon_xsettings_manager_start #define STOP cinnamon_xsettings_manager_stop #define MANAGER CinnamonSettingsXSettingsManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING FALSE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-xsettings-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-5.2.0/plugins/xsettings/xsettings-manager.h0000664000175000017500000000524014144454032024667 0ustar fabiofabio/* * Copyright © 2001 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Owen Taylor, Red Hat, Inc. */ #ifndef XSETTINGS_MANAGER_H #define XSETTINGS_MANAGER_H #include #include "xsettings-common.h" typedef struct _XSettingsManager XSettingsManager; typedef void (*XSettingsTerminateFunc) (void *cb_data); Bool xsettings_manager_check_running (Display *display, int screen); XSettingsManager *xsettings_manager_new (Display *display, int screen, XSettingsTerminateFunc terminate, void *cb_data); void xsettings_manager_destroy (XSettingsManager *manager); void xsettings_manager_delete_setting (XSettingsManager *manager, const char *name); void xsettings_manager_set_int (XSettingsManager *manager, const char *name, int value); void xsettings_manager_set_string (XSettingsManager *manager, const char *name, const char *value); void xsettings_manager_set_color (XSettingsManager *manager, const char *name, XSettingsColor *value); void xsettings_manager_notify (XSettingsManager *manager); void xsettings_manager_set_overrides (XSettingsManager *manager, GVariant *overrides); #endif /* XSETTINGS_MANAGER_H */ cinnamon-settings-daemon-5.2.0/plugins/xsettings/README.xsettings0000664000175000017500000000260014144454032023762 0ustar fabiofabioThis is very simple documentation for the 'override' GSettings key for cinnamon-setting-daemon's xsettings plugin. The override is given as a dictionary of overrides to be applied on top of the usual values that are exported to the X server as XSETTINGS. The intent of this is to allow users to override values of programmatically determined settings (such as 'Gtk/ShellShowsAppMenu') and to allow developers to introduce new XSETTINGS for testing (without having to kill the cinnamon-settings-daemon running in the session and run their own patched version). The type of the overrides is 'a{sv}'. The key gives the full XSETTINGS setting name to override (for example, 'Gtk/ShellShowsAppMenu'). The value is one of the following: - a string ('s') for the case of a string XSETTING - an int32 ('i') for the case of an integer XSETTING - a 4-tuple of uint16s ('(qqqq)') for the case of a color XSETTING Dictionary items with a value that is not one of the above types will be ignored. Specifically note that XSETTINGS does not have a concept of booleans -- you must use an integer that is either 0 or 1. An example setting for this key (as expressed in GVariant text format) might be: { 'Gtk/ShellShowsAppMenu': < 0 >, 'Xft/DPI', < 98304 > } Noting that variants must be specified in the usual way (wrapped in <>). Note also that DPI in the above example is expressed in 1024ths of an inch. cinnamon-settings-daemon-5.2.0/plugins/xsettings/test-gtk-modules.c0000664000175000017500000000127514144454032024436 0ustar fabiofabio #include "csd-xsettings-gtk.h" static void gtk_modules_callback (CsdXSettingsGtk *gtk, GParamSpec *spec, gpointer user_data) { const char *modules; modules = csd_xsettings_gtk_get_modules (gtk); g_message ("GTK+ modules list changed to: %s", modules ? modules : "(empty)"); } int main (int argc, char **argv) { GMainLoop *loop; CsdXSettingsGtk *gtk; gtk = csd_xsettings_gtk_new (); g_signal_connect (G_OBJECT (gtk), "notify::gtk-modules", G_CALLBACK (gtk_modules_callback), NULL); gtk_modules_callback (gtk, NULL, NULL); loop = g_main_loop_new (NULL, TRUE); g_main_loop_run (loop); g_main_loop_unref (loop); return 0; } cinnamon-settings-daemon-5.2.0/plugins/xsettings/csd-xsettings-gtk.h0000664000175000017500000000414414144454032024613 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Bastien Nocera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CSD_XSETTINGS_GTK_H__ #define __CSD_XSETTINGS_GTK_H__ #include #include #include G_BEGIN_DECLS #define CSD_TYPE_XSETTINGS_GTK (csd_xsettings_gtk_get_type ()) #define CSD_XSETTINGS_GTK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_XSETTINGS_GTK, CsdXSettingsGtk)) #define CSD_XSETTINGS_GTK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_XSETTINGS_GTK, CsdXSettingsGtkClass)) #define CSD_IS_XSETTINGS_GTK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_XSETTINGS_GTK)) #define CSD_IS_XSETTINGS_GTK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_XSETTINGS_GTK)) #define CSD_XSETTINGS_GTK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_XSETTINGS_GTK, CsdXSettingsGtkClass)) typedef struct CsdXSettingsGtkPrivate CsdXSettingsGtkPrivate; typedef struct { GObject parent; CsdXSettingsGtkPrivate *priv; } CsdXSettingsGtk; typedef struct { GObjectClass parent_class; } CsdXSettingsGtkClass; GType csd_xsettings_gtk_get_type (void) G_GNUC_CONST; CsdXSettingsGtk *csd_xsettings_gtk_new (void); const char * csd_xsettings_gtk_get_modules (CsdXSettingsGtk *gtk); G_END_DECLS #endif /* __CSD_XSETTINGS_GTK_H__ */ cinnamon-settings-daemon-5.2.0/plugins/xsettings/fontconfig-monitor.c0000664000175000017500000001142314144454032025043 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Author: Behdad Esfahbod, Red Hat, Inc. */ #include "fontconfig-monitor.h" #include #include #define TIMEOUT_SECONDS 2 static void stuff_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, gpointer handle); void fontconfig_cache_init (void) { FcInit (); } gboolean fontconfig_cache_update (void) { return !FcConfigUptoDate (NULL) && FcInitReinitialize (); } static void monitor_files (GPtrArray *monitors, FcStrList *list, gpointer data) { const char *str; while ((str = (const char *) FcStrListNext (list))) { GFile *file; GFileMonitor *monitor; file = g_file_new_for_path (str); monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, NULL); g_object_unref (file); if (!monitor) continue; g_signal_connect (monitor, "changed", G_CALLBACK (stuff_changed), data); g_ptr_array_add (monitors, monitor); } FcStrListDone (list); } struct _fontconfig_monitor_handle { GPtrArray *monitors; guint timeout; GFunc notify_callback; gpointer notify_data; }; static GPtrArray * monitors_create (gpointer data) { GPtrArray *monitors = g_ptr_array_new (); monitor_files (monitors, FcConfigGetConfigFiles (NULL), data); monitor_files (monitors, FcConfigGetFontDirs (NULL) , data); return monitors; } static void monitors_free (GPtrArray *monitors) { if (!monitors) return; g_ptr_array_foreach (monitors, (GFunc) g_object_unref, NULL); g_ptr_array_free (monitors, TRUE); } static gboolean update (gpointer data) { fontconfig_monitor_handle_t *handle = data; gboolean notify = FALSE; handle->timeout = 0; if (fontconfig_cache_update ()) { notify = TRUE; monitors_free (handle->monitors); handle->monitors = monitors_create (data); } /* we finish modifying handle before calling the notify callback, * allowing the callback to free the monitor if it decides to. */ if (notify && handle->notify_callback) handle->notify_callback (data, handle->notify_data); return FALSE; } static void stuff_changed (GFileMonitor *monitor G_GNUC_UNUSED, GFile *file G_GNUC_UNUSED, GFile *other_file G_GNUC_UNUSED, GFileMonitorEvent event_type G_GNUC_UNUSED, gpointer data) { fontconfig_monitor_handle_t *handle = data; /* wait for quiescence */ if (handle->timeout) { g_source_remove (handle->timeout); handle->timeout = 0; } handle->timeout = g_timeout_add_seconds (TIMEOUT_SECONDS, update, data); } fontconfig_monitor_handle_t * fontconfig_monitor_start (GFunc notify_callback, gpointer notify_data) { fontconfig_monitor_handle_t *handle = g_slice_new0 (fontconfig_monitor_handle_t); handle->notify_callback = notify_callback; handle->notify_data = notify_data; handle->monitors = monitors_create (handle); return handle; } void fontconfig_monitor_stop (fontconfig_monitor_handle_t *handle) { if (handle->timeout) { g_source_remove (handle->timeout); handle->timeout = 0; } monitors_free (handle->monitors); handle->monitors = NULL; } #ifdef FONTCONFIG_MONITOR_TEST static void yay (void) { g_message ("yay"); } int main (void) { GMainLoop *loop; fontconfig_monitor_start ((GFunc) yay, NULL); loop = g_main_loop_new (NULL, TRUE); g_main_loop_run (loop); g_main_loop_unref (loop); return 0; } #endif cinnamon-settings-daemon-5.2.0/plugins/xsettings/csd-xsettings-gtk.c0000664000175000017500000003021214144454032024601 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include "csd-xsettings-gtk.h" #define XSETTINGS_PLUGIN_SCHEMA "org.cinnamon.settings-daemon.plugins.xsettings" #define GTK_MODULES_DISABLED_KEY "disabled-gtk-modules" #define GTK_MODULES_ENABLED_KEY "enabled-gtk-modules" enum { PROP_0, PROP_GTK_MODULES }; struct CsdXSettingsGtkPrivate { char *modules; GHashTable *dir_modules; GSettings *settings; guint64 dir_mtime; GFileMonitor *monitor; GList *cond_settings; }; #define CSD_XSETTINGS_GTK_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_XSETTINGS_GTK, CsdXSettingsGtkPrivate)) G_DEFINE_TYPE(CsdXSettingsGtk, csd_xsettings_gtk, G_TYPE_OBJECT) static void update_gtk_modules (CsdXSettingsGtk *gtk); static void empty_cond_settings_list (CsdXSettingsGtk *gtk) { if (gtk->priv->cond_settings == NULL) return; /* Empty the list of settings */ g_list_foreach (gtk->priv->cond_settings, (GFunc) g_object_unref, NULL); g_list_free (gtk->priv->cond_settings); gtk->priv->cond_settings = NULL; } static void cond_setting_changed (GSettings *settings, const char *key, CsdXSettingsGtk *gtk) { gboolean enabled; const char *module_name; module_name = g_object_get_data (G_OBJECT (settings), "module-name"); enabled = g_settings_get_boolean (settings, key); if (enabled != FALSE) { if (gtk->priv->dir_modules == NULL) gtk->priv->dir_modules = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); g_hash_table_insert (gtk->priv->dir_modules, g_strdup (module_name), NULL); } else if (gtk->priv->dir_modules != NULL) { g_hash_table_remove (gtk->priv->dir_modules, module_name); } update_gtk_modules (gtk); } static char * process_desktop_file (const char *path, CsdXSettingsGtk *gtk) { GKeyFile *keyfile; char *retval; char *module_name; retval = NULL; if (g_str_has_suffix (path, ".desktop") == FALSE && g_str_has_suffix (path, ".gtk-module") == FALSE) return retval; keyfile = g_key_file_new (); if (g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, NULL) == FALSE) goto bail; if (g_key_file_has_group (keyfile, "GTK Module") == FALSE) goto bail; module_name = g_key_file_get_string (keyfile, "GTK Module", "X-GTK-Module-Name", NULL); if (module_name == NULL) goto bail; if (g_key_file_has_key (keyfile, "GTK Module", "X-GTK-Module-Enabled-Schema", NULL) != FALSE) { char *schema; char *key; gboolean enabled; GSettings *settings; char *signal; schema = g_key_file_get_string (keyfile, "GTK Module", "X-GTK-Module-Enabled-Schema", NULL); key = g_key_file_get_string (keyfile, "GTK Module", "X-GTK-Module-Enabled-Key", NULL); settings = g_settings_new (schema); enabled = g_settings_get_boolean (settings, key); gtk->priv->cond_settings = g_list_prepend (gtk->priv->cond_settings, settings); g_object_set_data_full (G_OBJECT (settings), "module-name", g_strdup (module_name), (GDestroyNotify) g_free); signal = g_strdup_printf ("changed::%s", key); g_signal_connect_object (G_OBJECT (settings), signal, G_CALLBACK (cond_setting_changed), gtk, 0); g_free (signal); g_free (schema); g_free (key); if (enabled != FALSE) retval = g_strdup (module_name); } else { retval = g_strdup (module_name); } g_free (module_name); bail: g_key_file_free (keyfile); return retval; } static void get_gtk_modules_from_dir (CsdXSettingsGtk *gtk) { GFile *file; GFileInfo *info; GHashTable *ht; file = g_file_new_for_path (GTK_MODULES_DIRECTORY); info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL); if (info != NULL) { guint64 dir_mtime; dir_mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); if (gtk->priv->dir_mtime == 0 || dir_mtime > gtk->priv->dir_mtime) { GDir *dir; const char *name; empty_cond_settings_list (gtk); gtk->priv->dir_mtime = dir_mtime; if (gtk->priv->dir_modules != NULL) { g_hash_table_destroy (gtk->priv->dir_modules); gtk->priv->dir_modules = NULL; } dir = g_dir_open (GTK_MODULES_DIRECTORY, 0, NULL); if (dir == NULL) goto bail; ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); while ((name = g_dir_read_name (dir)) != NULL) { char *path; char *module; path = g_build_filename (GTK_MODULES_DIRECTORY, name, NULL); module = process_desktop_file (path, gtk); if (module != NULL) g_hash_table_insert (ht, module, NULL); g_free (path); } g_dir_close (dir); gtk->priv->dir_modules = ht; } } else { empty_cond_settings_list (gtk); } bail: if (info != NULL) g_object_unref (info); g_object_unref (file); } static void stringify_gtk_modules (gpointer key, gpointer value, GString *str) { if (str->len != 0) g_string_append_c (str, ':'); g_string_append (str, key); } static void update_gtk_modules (CsdXSettingsGtk *gtk) { char **enabled, **disabled; GHashTable *ht; guint i; GString *str; char *modules; enabled = g_settings_get_strv (gtk->priv->settings, GTK_MODULES_ENABLED_KEY); disabled = g_settings_get_strv (gtk->priv->settings, GTK_MODULES_DISABLED_KEY); ht = g_hash_table_new (g_str_hash, g_str_equal); if (gtk->priv->dir_modules != NULL) { GList *list, *l; list = g_hash_table_get_keys (gtk->priv->dir_modules); for (l = list; l != NULL; l = l->next) { g_hash_table_insert (ht, l->data, NULL); } g_list_free (list); } for (i = 0; enabled[i] != NULL; i++) g_hash_table_insert (ht, enabled[i], NULL); for (i = 0; disabled[i] != NULL; i++) g_hash_table_remove (ht, disabled[i]); str = g_string_new (NULL); g_hash_table_foreach (ht, (GHFunc) stringify_gtk_modules, str); g_hash_table_destroy (ht); modules = g_string_free (str, FALSE); if (modules == NULL || gtk->priv->modules == NULL || g_str_equal (modules, gtk->priv->modules) == FALSE) { g_free (gtk->priv->modules); gtk->priv->modules = modules; g_object_notify (G_OBJECT (gtk), "gtk-modules"); } else { g_free (modules); } g_strfreev (enabled); g_strfreev (disabled); } static void gtk_modules_dir_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, CsdXSettingsGtk *gtk) { get_gtk_modules_from_dir (gtk); update_gtk_modules (gtk); } static void csd_xsettings_gtk_init (CsdXSettingsGtk *gtk) { GFile *file; gtk->priv = CSD_XSETTINGS_GTK_GET_PRIVATE (gtk); g_debug ("CsdXSettingsGtk initializing"); gtk->priv->settings = g_settings_new (XSETTINGS_PLUGIN_SCHEMA); get_gtk_modules_from_dir (gtk); file = g_file_new_for_path (GTK_MODULES_DIRECTORY); gtk->priv->monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, NULL); g_signal_connect (G_OBJECT (gtk->priv->monitor), "changed", G_CALLBACK (gtk_modules_dir_changed_cb), gtk); g_object_unref (file); update_gtk_modules (gtk); } static void csd_xsettings_gtk_finalize (GObject *object) { CsdXSettingsGtk *gtk; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_XSETTINGS_GTK (object)); g_debug ("CsdXSettingsGtk finalizing"); gtk = CSD_XSETTINGS_GTK (object); g_return_if_fail (gtk->priv != NULL); g_free (gtk->priv->modules); gtk->priv->modules = NULL; if (gtk->priv->dir_modules != NULL) { g_hash_table_destroy (gtk->priv->dir_modules); gtk->priv->dir_modules = NULL; } g_object_unref (gtk->priv->settings); if (gtk->priv->monitor != NULL) g_object_unref (gtk->priv->monitor); empty_cond_settings_list (gtk); G_OBJECT_CLASS (csd_xsettings_gtk_parent_class)->finalize (object); } static void csd_xsettings_gtk_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdXSettingsGtk *self; self = CSD_XSETTINGS_GTK (object); switch (prop_id) { case PROP_GTK_MODULES: g_value_set_string (value, self->priv->modules); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_xsettings_gtk_class_init (CsdXSettingsGtkClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = csd_xsettings_gtk_get_property; object_class->finalize = csd_xsettings_gtk_finalize; g_object_class_install_property (object_class, PROP_GTK_MODULES, g_param_spec_string ("gtk-modules", NULL, NULL, NULL, G_PARAM_READABLE)); g_type_class_add_private (klass, sizeof (CsdXSettingsGtkPrivate)); } CsdXSettingsGtk * csd_xsettings_gtk_new (void) { return CSD_XSETTINGS_GTK (g_object_new (CSD_TYPE_XSETTINGS_GTK, NULL)); } const char * csd_xsettings_gtk_get_modules (CsdXSettingsGtk *gtk) { return gtk->priv->modules; } cinnamon-settings-daemon-5.2.0/plugins/xsettings/xsettings-manager.c0000664000175000017500000002560714144454032024673 0ustar fabiofabio/* * Copyright © 2001 Red Hat, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Owen Taylor, Red Hat, Inc. */ #include #include #include #include #include /* For CARD16 */ #include "xsettings-manager.h" #define XSETTINGS_VARIANT_TYPE_COLOR (G_VARIANT_TYPE ("(qqqq)")) struct _XSettingsManager { Display *display; int screen; Window window; Atom manager_atom; Atom selection_atom; Atom xsettings_atom; XSettingsTerminateFunc terminate; void *cb_data; GHashTable *settings; unsigned long serial; GVariant *overrides; }; typedef struct { Window window; Atom timestamp_prop_atom; } TimeStampInfo; static Bool timestamp_predicate (Display *display, XEvent *xevent, XPointer arg) { TimeStampInfo *info = (TimeStampInfo *)arg; if (xevent->type == PropertyNotify && xevent->xproperty.window == info->window && xevent->xproperty.atom == info->timestamp_prop_atom) return True; return False; } /** * get_server_time: * @display: display from which to get the time * @window: a #Window, used for communication with the server. * The window must have PropertyChangeMask in its * events mask or a hang will result. * * Routine to get the current X server time stamp. * * Return value: the time stamp. **/ static Time get_server_time (Display *display, Window window) { unsigned char c = 'a'; XEvent xevent; TimeStampInfo info; info.timestamp_prop_atom = XInternAtom (display, "_TIMESTAMP_PROP", False); info.window = window; XChangeProperty (display, window, info.timestamp_prop_atom, info.timestamp_prop_atom, 8, PropModeReplace, &c, 1); XIfEvent (display, &xevent, timestamp_predicate, (XPointer)&info); return xevent.xproperty.time; } Bool xsettings_manager_check_running (Display *display, int screen) { char buffer[256]; Atom selection_atom; sprintf(buffer, "_XSETTINGS_S%d", screen); selection_atom = XInternAtom (display, buffer, False); if (XGetSelectionOwner (display, selection_atom)) return True; else return False; } XSettingsManager * xsettings_manager_new (Display *display, int screen, XSettingsTerminateFunc terminate, void *cb_data) { XSettingsManager *manager; Time timestamp; XClientMessageEvent xev; char buffer[256]; manager = g_slice_new (XSettingsManager); manager->display = display; manager->screen = screen; sprintf(buffer, "_XSETTINGS_S%d", screen); manager->selection_atom = XInternAtom (display, buffer, False); manager->xsettings_atom = XInternAtom (display, "_XSETTINGS_SETTINGS", False); manager->manager_atom = XInternAtom (display, "MANAGER", False); manager->terminate = terminate; manager->cb_data = cb_data; manager->settings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) xsettings_setting_free); manager->serial = 0; manager->overrides = NULL; manager->window = XCreateSimpleWindow (display, RootWindow (display, screen), 0, 0, 10, 10, 0, WhitePixel (display, screen), WhitePixel (display, screen)); XSelectInput (display, manager->window, PropertyChangeMask); timestamp = get_server_time (display, manager->window); XSetSelectionOwner (display, manager->selection_atom, manager->window, timestamp); /* Check to see if we managed to claim the selection. If not, * we treat it as if we got it then immediately lost it */ if (XGetSelectionOwner (display, manager->selection_atom) == manager->window) { xev.type = ClientMessage; xev.window = RootWindow (display, screen); xev.message_type = manager->manager_atom; xev.format = 32; xev.data.l[0] = timestamp; xev.data.l[1] = manager->selection_atom; xev.data.l[2] = manager->window; xev.data.l[3] = 0; /* manager specific data */ xev.data.l[4] = 0; /* manager specific data */ XSendEvent (display, RootWindow (display, screen), False, StructureNotifyMask, (XEvent *)&xev); } else { manager->terminate (manager->cb_data); } return manager; } void xsettings_manager_destroy (XSettingsManager *manager) { XDestroyWindow (manager->display, manager->window); g_hash_table_unref (manager->settings); g_slice_free (XSettingsManager, manager); } static void xsettings_manager_set_setting (XSettingsManager *manager, const gchar *name, gint tier, GVariant *value) { XSettingsSetting *setting; setting = g_hash_table_lookup (manager->settings, name); if (setting == NULL) { setting = xsettings_setting_new (name); setting->last_change_serial = manager->serial; g_hash_table_insert (manager->settings, setting->name, setting); } xsettings_setting_set (setting, tier, value, manager->serial); if (xsettings_setting_get (setting) == NULL) g_hash_table_remove (manager->settings, name); } void xsettings_manager_set_int (XSettingsManager *manager, const char *name, int value) { xsettings_manager_set_setting (manager, name, 0, g_variant_new_int32 (value)); } void xsettings_manager_set_string (XSettingsManager *manager, const char *name, const char *value) { xsettings_manager_set_setting (manager, name, 0, g_variant_new_string (value)); } void xsettings_manager_set_color (XSettingsManager *manager, const char *name, XSettingsColor *value) { GVariant *tmp; tmp = g_variant_new ("(qqqq)", value->red, value->green, value->blue, value->alpha); g_assert (g_variant_is_of_type (tmp, XSETTINGS_VARIANT_TYPE_COLOR)); /* paranoia... */ xsettings_manager_set_setting (manager, name, 0, tmp); } void xsettings_manager_delete_setting (XSettingsManager *manager, const char *name) { xsettings_manager_set_setting (manager, name, 0, NULL); } static gchar xsettings_get_typecode (GVariant *value) { switch (g_variant_classify (value)) { case G_VARIANT_CLASS_INT32: return XSETTINGS_TYPE_INT; case G_VARIANT_CLASS_STRING: return XSETTINGS_TYPE_STRING; case G_VARIANT_CLASS_TUPLE: return XSETTINGS_TYPE_COLOR; default: g_assert_not_reached (); } } static void align_string (GString *string, gint alignment) { /* Adds nul-bytes to the string until its length is an even multiple * of the specified alignment requirement. */ while ((string->len % alignment) != 0) g_string_append_c (string, '\0'); } static void setting_store (XSettingsSetting *setting, GString *buffer) { XSettingsType type; GVariant *value; guint16 len16; value = xsettings_setting_get (setting); type = xsettings_get_typecode (value); g_string_append_c (buffer, type); g_string_append_c (buffer, 0); len16 = strlen (setting->name); g_string_append_len (buffer, (gchar *) &len16, 2); g_string_append (buffer, setting->name); align_string (buffer, 4); g_string_append_len (buffer, (gchar *) &setting->last_change_serial, 4); if (type == XSETTINGS_TYPE_STRING) { const gchar *string; gsize stringlen; guint32 len32; string = g_variant_get_string (value, &stringlen); len32 = stringlen; g_string_append_len (buffer, (gchar *) &len32, 4); g_string_append (buffer, string); align_string (buffer, 4); } else /* GVariant format is the same as XSETTINGS format for the non-string types */ g_string_append_len (buffer, g_variant_get_data (value), g_variant_get_size (value)); } void xsettings_manager_notify (XSettingsManager *manager) { GString *buffer; GHashTableIter iter; int n_settings; gpointer value; n_settings = g_hash_table_size (manager->settings); buffer = g_string_new (NULL); g_string_append_c (buffer, xsettings_byte_order ()); g_string_append_c (buffer, '\0'); g_string_append_c (buffer, '\0'); g_string_append_c (buffer, '\0'); g_string_append_len (buffer, (gchar *) &manager->serial, 4); g_string_append_len (buffer, (gchar *) &n_settings, 4); g_hash_table_iter_init (&iter, manager->settings); while (g_hash_table_iter_next (&iter, NULL, &value)) setting_store (value, buffer); XChangeProperty (manager->display, manager->window, manager->xsettings_atom, manager->xsettings_atom, 8, PropModeReplace, (guchar *) buffer->str, buffer->len); g_string_free (buffer, TRUE); manager->serial++; } void xsettings_manager_set_overrides (XSettingsManager *manager, GVariant *overrides) { GVariantIter iter; const gchar *key; GVariant *value; g_return_if_fail (overrides != NULL && g_variant_is_of_type (overrides, G_VARIANT_TYPE_VARDICT)); if (manager->overrides) { /* unset the existing overrides */ g_variant_iter_init (&iter, manager->overrides); while (g_variant_iter_next (&iter, "{&sv}", &key, NULL)) /* only unset it at this point if it's not in the new list */ if (!g_variant_lookup (overrides, key, "*", NULL)) xsettings_manager_set_setting (manager, key, 1, NULL); g_variant_unref (manager->overrides); } /* save this so we can do the unsets next time */ manager->overrides = g_variant_ref_sink (overrides); /* set the new values */ g_variant_iter_init (&iter, overrides); while (g_variant_iter_loop (&iter, "{&sv}", &key, &value)) { /* only accept recognised types... */ if (!g_variant_is_of_type (value, G_VARIANT_TYPE_STRING) && !g_variant_is_of_type (value, G_VARIANT_TYPE_INT32) && !g_variant_is_of_type (value, XSETTINGS_VARIANT_TYPE_COLOR)) continue; xsettings_manager_set_setting (manager, key, 1, value); } } cinnamon-settings-daemon-5.2.0/plugins/mouse/0000775000175000017500000000000014144454032020155 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/mouse/csd-mouse-manager.c0000664000175000017500000022246214144454032023640 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #ifdef __linux #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-mouse-manager.h" #include "csd-input-helper.h" #include "csd-enums.h" #define CSD_MOUSE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_MOUSE_MANAGER, CsdMouseManagerPrivate)) #define SETTINGS_MOUSE_DIR "org.cinnamon.settings-daemon.peripherals.mouse" #define SETTINGS_TOUCHPAD_DIR "org.cinnamon.settings-daemon.peripherals.touchpad" #define SETTINGS_TRACKBALL_DIR "org.cinnamon.settings-daemon.peripherals.trackball" /* Keys for both touchpad and mouse */ #define KEY_LEFT_HANDED "left-handed" /* a boolean for mouse, an enum for touchpad */ #define KEY_CUSTOM_ACCELERATION "custom-acceleration" #define KEY_MOTION_ACCELERATION "motion-acceleration" #define KEY_CUSTOM_THRESHOLD "custom-threshold" #define KEY_MOTION_THRESHOLD "motion-threshold" /* Touchpad settings */ #define KEY_TOUCHPAD_DISABLE_W_TYPING "disable-while-typing" #define KEY_TAP_TO_CLICK "tap-to-click" #define KEY_CLICKPAD_CLICK "clickpad-click" #define KEY_SCROLL_METHOD "scrolling-method" #define KEY_HORIZ_SCROLL "horizontal-scrolling" #define KEY_TOUCHPAD_ENABLED "touchpad-enabled" #define KEY_NATURAL_SCROLL_ENABLED "natural-scroll" #define KEY_TOUCHPAD_DISABLE_WITH_MOUSE "disable-with-external-mouse" /* Mouse settings */ #define KEY_LOCATE_POINTER "locate-pointer" #define KEY_DWELL_CLICK_ENABLED "dwell-click-enabled" #define KEY_SECONDARY_CLICK_ENABLED "secondary-click-enabled" #define KEY_MIDDLE_BUTTON_EMULATION "middle-button-enabled" /* Trackball settings */ #define KEY_SCROLL_WHEEL_BUTTON "scroll-wheel-emulation-button" struct CsdMouseManagerPrivate { guint start_idle_id; GSettings *touchpad_settings; GSettings *mouse_settings; GSettings *mouse_a11y_settings; GSettings *trackball_settings; GdkDeviceManager *device_manager; guint device_added_id; guint device_removed_id; GHashTable *blacklist; gboolean mousetweaks_daemon_running; gboolean syndaemon_spawned; GPid syndaemon_pid; gboolean locate_pointer_spawned; GPid locate_pointer_pid; }; static void csd_mouse_manager_finalize (GObject *object); static void set_tap_to_click (GdkDevice *device, gboolean state, gboolean left_handed); static void set_click_actions (GdkDevice *device, gint clickpad_click, gboolean left_handed); static void set_natural_scroll (CsdMouseManager *manager, GdkDevice *device, gboolean natural_scroll); G_DEFINE_TYPE (CsdMouseManager, csd_mouse_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static void csd_mouse_manager_class_init (CsdMouseManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_mouse_manager_finalize; g_type_class_add_private (klass, sizeof (CsdMouseManagerPrivate)); } static XDevice * open_gdk_device (GdkDevice *device) { XDevice *xdevice; int id; g_object_get (G_OBJECT (device), "device-id", &id, NULL); gdk_x11_display_error_trap_push (gdk_display_get_default ()); xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) != 0) return NULL; return xdevice; } static gboolean gdkdevice_is_touchpad (GdkDevice *device) { XDevice *xdevice; gboolean ret = FALSE; xdevice = open_gdk_device (device); if (xdevice == NULL) return ret; ret = device_is_touchpad (xdevice); xdevice_close (xdevice); return ret; } static gboolean device_is_trackball (GdkDevice *device) { XDeviceInfo *device_info; gboolean retval = FALSE; gint n_devices; guint i; int id; g_object_get (G_OBJECT (device), "device-id", &id, NULL); gdk_error_trap_push (); device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return retval; for (i = 0; i < n_devices; i++) { if (device_info[i].id != id) continue; retval = device_info_is_trackball (&device_info[i]); break; } XFreeDeviceList (device_info); if (gdk_error_trap_pop () != 0) return FALSE; return retval; } static gboolean device_is_blacklisted (CsdMouseManager *manager, GdkDevice *device) { int id; g_object_get (G_OBJECT (device), "device-id", &id, NULL); if (g_hash_table_lookup (manager->priv->blacklist, GINT_TO_POINTER (id)) != NULL) { g_debug ("device %s (%d) is blacklisted", gdk_device_get_name (device), id); return TRUE; } return FALSE; } static gboolean device_is_ignored (CsdMouseManager *manager, GdkDevice *device) { GdkInputSource source; const char *name; if (device_is_blacklisted (manager, device)) return TRUE; source = gdk_device_get_source (device); if (source != GDK_SOURCE_MOUSE && source != GDK_SOURCE_TOUCHPAD && source != GDK_SOURCE_CURSOR) return TRUE; name = gdk_device_get_name (device); if (name != NULL && g_str_equal ("Virtual core XTEST pointer", name)) return TRUE; return FALSE; } static void configure_button_layout (guchar *buttons, gint n_buttons, gboolean left_handed) { const gint left_button = 1; gint right_button; gint i; /* if the button is higher than 2 (3rd button) then it's * probably one direction of a scroll wheel or something else * uninteresting */ right_button = MIN (n_buttons, 3); /* If we change things we need to make sure we only swap buttons. * If we end up with multiple physical buttons assigned to the same * logical button the server will complain. This code assumes physical * button 0 is the physical left mouse button, and that the physical * button other than 0 currently assigned left_button or right_button * is the physical right mouse button. */ /* check if the current mapping satisfies the above assumptions */ if (buttons[left_button - 1] != left_button && buttons[left_button - 1] != right_button) /* The current mapping is weird. Swapping buttons is probably not a * good idea. */ return; /* check if we are left_handed and currently not swapped */ if (left_handed && buttons[left_button - 1] == left_button) { /* find the right button */ for (i = 0; i < n_buttons; i++) { if (buttons[i] == right_button) { buttons[i] = left_button; break; } } /* swap the buttons */ buttons[left_button - 1] = right_button; } /* check if we are not left_handed but are swapped */ else if (!left_handed && buttons[left_button - 1] == right_button) { /* find the right button */ for (i = 0; i < n_buttons; i++) { if (buttons[i] == left_button) { buttons[i] = right_button; break; } } /* swap the buttons */ buttons[left_button - 1] = left_button; } } static gboolean xinput_device_has_buttons (GdkDevice *device) { int i; XAnyClassInfo *class_info; /* FIXME can we use the XDevice's classes here instead? */ XDeviceInfo *device_info, *info; gint n_devices; int id; /* Find the XDeviceInfo for the GdkDevice */ g_object_get (G_OBJECT (device), "device-id", &id, NULL); device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return FALSE; info = NULL; for (i = 0; i < n_devices; i++) { if (device_info[i].id == id) { info = &device_info[i]; break; } } if (info == NULL) goto bail; class_info = info->inputclassinfo; for (i = 0; i < info->num_classes; i++) { if (class_info->class == ButtonClass) { XButtonInfo *button_info; button_info = (XButtonInfo *) class_info; if (button_info->num_buttons > 0) { XFreeDeviceList (device_info); return TRUE; } } class_info = (XAnyClassInfo *) (((guchar *) class_info) + class_info->length); } bail: XFreeDeviceList (device_info); return FALSE; } static Atom property_from_name (const char *property_name) { Atom prop; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), property_name, True); return prop; } static gboolean touchpad_has_single_button (XDevice *device) { Atom type, prop; int format; unsigned long nitems, bytes_after; unsigned char *data; gboolean is_single_button = FALSE; int rc; prop = property_from_name ("Synaptics Capabilities"); if (!prop) return FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop, 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3) is_single_button = (data[0] == 1 && data[1] == 0 && data[2] == 0); if (rc == Success) XFree (data); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); return is_single_button; } static gboolean property_exists_on_device (GdkDevice *device, const char * property_name) { int rc; Atom act_type, property; int act_format; unsigned long nitems, bytes_after; unsigned char *data; XDevice *xdevice; property = property_from_name (property_name); if (!property) return FALSE; xdevice = open_gdk_device (device); if (xdevice == NULL) return FALSE; gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, 0, 1, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success) XFree(data); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); xdevice_close (xdevice); return rc == Success; } static void property_set_bool (GdkDevice *device, XDevice *xdevice, const char * property_name, int property_index, gboolean enable) { int rc; Atom act_type, property; int act_format; unsigned long nitems, bytes_after; unsigned char *data; property = property_from_name (property_name); if (!property) { return; } int value = 0; if (enable) { value = 1; } g_debug ("Setting %s on %s to %d", property_name, gdk_device_get_name (device), value); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, 0, 1, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success && act_type == XA_INTEGER && act_format == 8 && nitems > property_index) { data[property_index] = value; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) { XFree (data); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) { g_warning ("Error while setting %s on \"%s\"", property_name, gdk_device_get_name (device)); } } static gboolean property_get_bool (GdkDevice *device, XDevice *xdevice, const char * property_name, int property_index) { int rc; Atom act_type, property; int act_format; unsigned long nitems, bytes_after; unsigned char *data; gboolean ret = FALSE; property = property_from_name (property_name); if (!property) { return FALSE; } g_debug ("Getting %s on %s", property_name, gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, 0, 1, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success && act_type == XA_INTEGER && act_format == 8 && nitems > property_index) { ret = data[property_index]; } if (rc == Success) { XFree (data); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) { g_warning ("Error while getting %s on \"%s\"", property_name, gdk_device_get_name (device)); } return ret; } static void touchpad_set_bool (GdkDevice *device, const char * property_name, int property_index, gboolean enable) { XDevice *xdevice; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (device_is_touchpad (xdevice)) property_set_bool (device, xdevice, property_name, property_index, enable); xdevice_close (xdevice); } static gboolean touchpad_get_bool (GdkDevice *device, const char * property_name, int property_index) { XDevice *xdevice; gboolean ret = FALSE; xdevice = open_gdk_device (device); if (xdevice == NULL) return ret; if (device_is_touchpad (xdevice)) ret = property_get_bool (device, xdevice, property_name, property_index); xdevice_close (xdevice); return ret; } static void set_left_handed_legacy_driver (CsdMouseManager *manager, GdkDevice *device, gboolean mouse_left_handed, gboolean touchpad_left_handed) { XDevice *xdevice; guchar *buttons; gsize buttons_capacity = 16; gboolean left_handed; gint n_buttons; if (!xinput_device_has_buttons (device)) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; g_debug ("setting handedness on %s", gdk_device_get_name (device)); buttons = g_new (guchar, buttons_capacity); /* If the device is a touchpad, swap tap buttons * around too, otherwise a tap would be a right-click */ if (device_is_touchpad (xdevice)) { gboolean tap = g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TAP_TO_CLICK); gboolean single_button = touchpad_has_single_button (xdevice); left_handed = touchpad_left_handed; if (tap && !single_button) set_tap_to_click (device, tap, left_handed); if (single_button) goto out; } else { left_handed = mouse_left_handed; } gdk_x11_display_error_trap_push (gdk_display_get_default ()); n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, buttons, buttons_capacity); while (n_buttons > buttons_capacity) { buttons_capacity = n_buttons; buttons = (guchar *) g_realloc (buttons, buttons_capacity * sizeof (guchar)); n_buttons = XGetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, buttons, buttons_capacity); } configure_button_layout (buttons, n_buttons, left_handed); XSetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, buttons, n_buttons); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); out: xdevice_close (xdevice); g_free (buttons); } static void set_left_handed_libinput (GdkDevice *device, gboolean mouse_left_handed, gboolean touchpad_left_handed) { XDevice *xdevice; gboolean want_lefthanded; xdevice = open_gdk_device (device); if (xdevice == NULL) return; want_lefthanded = device_is_touchpad (xdevice) ? touchpad_left_handed : mouse_left_handed; property_set_bool (device, xdevice, "libinput Left Handed Enabled", 0, want_lefthanded); xdevice_close (xdevice); } static void set_left_handed (CsdMouseManager *manager, GdkDevice *device, gboolean mouse_left_handed, gboolean touchpad_left_handed) { if (property_exists_on_device (device, "libinput Left Handed Enabled")) set_left_handed_libinput (device, mouse_left_handed, touchpad_left_handed); else set_left_handed_legacy_driver (manager, device, mouse_left_handed, touchpad_left_handed); } static void set_motion_legacy_driver (CsdMouseManager *manager, GdkDevice *device) { XDevice *xdevice; XPtrFeedbackControl feedback; XFeedbackState *states, *state; int num_feedbacks; int numerator, denominator; gfloat motion_acceleration; gboolean custom_acceleration; int motion_threshold; gboolean custom_threshold; GSettings *settings; guint i; xdevice = open_gdk_device (device); if (xdevice == NULL) return; g_debug ("setting motion on %s", gdk_device_get_name (device)); if (device_is_touchpad (xdevice)) settings = manager->priv->touchpad_settings; else settings = manager->priv->mouse_settings; /* Calculate acceleration */ motion_acceleration = g_settings_get_double (settings, KEY_MOTION_ACCELERATION); custom_acceleration = g_settings_get_boolean (settings, KEY_CUSTOM_ACCELERATION); if (custom_acceleration) { if (motion_acceleration >= 1.0) { /* we want to get the acceleration, with a resolution of 0.5 */ if ((motion_acceleration - floor (motion_acceleration)) < 0.25) { numerator = floor (motion_acceleration); denominator = 1; } else if ((motion_acceleration - floor (motion_acceleration)) < 0.5) { numerator = ceil (2.0 * motion_acceleration); denominator = 2; } else if ((motion_acceleration - floor (motion_acceleration)) < 0.75) { numerator = floor (2.0 *motion_acceleration); denominator = 2; } else { numerator = ceil (motion_acceleration); denominator = 1; } } else if (motion_acceleration < 1.0 && motion_acceleration > 0) { /* This we do to 1/10ths */ numerator = floor (motion_acceleration * 10) + 1; denominator= 10; } else { numerator = -1; denominator = -1; } } else { numerator = -1; denominator = -1; } /* And threshold */ custom_threshold = g_settings_get_boolean (settings, KEY_CUSTOM_THRESHOLD); if (custom_threshold) { motion_threshold = g_settings_get_int (settings, KEY_MOTION_THRESHOLD); } else { motion_threshold = -1; } gdk_x11_display_error_trap_push (gdk_display_get_default ()); /* Get the list of feedbacks for the device */ states = XGetFeedbackControl (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, &num_feedbacks); if (states == NULL) goto out; state = (XFeedbackState *) states; for (i = 0; i < num_feedbacks; i++) { if (state->class == PtrFeedbackClass) { /* And tell the device */ feedback.class = PtrFeedbackClass; feedback.length = sizeof (XPtrFeedbackControl); feedback.id = state->id; feedback.threshold = motion_threshold; feedback.accelNum = numerator; feedback.accelDenom = denominator; g_debug ("Setting accel %d/%d, threshold %d for device '%s'", numerator, denominator, motion_threshold, gdk_device_get_name (device)); XChangeFeedbackControl (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, DvAccelNum | DvAccelDenom | DvThreshold, (XFeedbackControl *) &feedback); break; } state = (XFeedbackState *) ((char *) state + state->length); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error setting acceleration on \"%s\"", gdk_device_get_name (device)); XFreeFeedbackList (states); out: xdevice_close (xdevice); } static void set_motion_libinput (CsdMouseManager *manager, GdkDevice *device) { int rc; XDevice *xdevice; GSettings *settings; Atom act_type, property, float_type; int act_format; unsigned long nitems, bytes_after; union { unsigned char *c; long *l; } data; gfloat accel; gfloat motion_acceleration; gboolean custom_acceleration; xdevice = open_gdk_device (device); if (xdevice == NULL) return; g_debug ("setting motion on %s", gdk_device_get_name (device)); if (device_is_touchpad (xdevice)) settings = manager->priv->touchpad_settings; else settings = manager->priv->mouse_settings; /* Calculate acceleration */ motion_acceleration = g_settings_get_double (settings, KEY_MOTION_ACCELERATION); custom_acceleration = g_settings_get_boolean (settings, KEY_CUSTOM_ACCELERATION); /* panel gives us a range of 1.0-10.0, map to libinput's -1, 1 oldrange = (oldmax - oldmin) newrange = (newmax - newmin) mapped = (value - oldmin) * newrange / oldrange + oldmin */ if (motion_acceleration == -1.0 || !custom_acceleration) /* unset */ accel = 0.0; else accel = (motion_acceleration - 1.0) * 2.0 / 9.0 - 1; float_type = property_from_name ("FLOAT"); if (!float_type) return; property = property_from_name ("libinput Accel Speed"); if (!property) { return; } gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, 0, 1, False, float_type, &act_type, &act_format, &nitems, &bytes_after, &data.c); if (rc == Success && act_type == float_type && act_format == 32 && nitems >= 1) { *(float*)data.l = accel; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, property, float_type, 32, PropModeReplace, data.c, nitems); } if (rc == Success) { XFree (data.c); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) { g_warning ("Error while setting accel speed on \"%s\"", gdk_device_get_name (device)); } xdevice_close (xdevice); } static void set_motion (CsdMouseManager *manager, GdkDevice *device) { if (property_exists_on_device (device, "libinput Accel Speed")) set_motion_libinput (manager, device); else set_motion_legacy_driver (manager, device); } static void set_middle_button_evdev (CsdMouseManager *manager, GdkDevice *device, gboolean middle_button) { Atom prop; XDevice *xdevice; Atom type; int format; unsigned long nitems, bytes_after; unsigned char *data; int rc; prop = property_from_name ("Evdev Middle Button Emulation"); if (!prop) /* no evdev devices */ return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; g_debug ("setting middle button on %s", gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && format == 8 && type == XA_INTEGER && nitems == 1) { data[0] = middle_button ? 1 : 0; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, type, format, PropModeReplace, data, nitems); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error in setting middle button emulation on \"%s\"", gdk_device_get_name (device)); if (rc == Success) XFree (data); xdevice_close (xdevice); } static void set_middle_button_libinput (CsdMouseManager *manager, GdkDevice *device, gboolean middle_button) { XDevice *xdevice; g_debug ("setting middle button on %s", gdk_device_get_name (device)); xdevice = open_gdk_device (device); if (xdevice == NULL) return; /* we didn't set it for synaptics, so bail out for touchpads */ if (device_is_touchpad (xdevice)) return; property_set_bool (device, xdevice, "libinput Middle Emulation Enabled", 0, middle_button); xdevice_close (xdevice); } static void set_middle_button (CsdMouseManager *manager, GdkDevice *device, gboolean middle_button) { if (property_from_name ("Evdev Middle Button Emulation")) set_middle_button_evdev (manager, device, middle_button); if (property_from_name ("libinput Middle Emulation Enabled")) set_middle_button_libinput (manager, device, middle_button); } /* Ensure that syndaemon dies together with us, to avoid running several of * them */ static void setup_syndaemon (gpointer user_data) { #ifdef __linux prctl (PR_SET_PDEATHSIG, SIGHUP); #endif } static gboolean have_program_in_path (const char *name) { gchar *path; gboolean result; path = g_find_program_in_path (name); result = (path != NULL); g_free (path); return result; } static void syndaemon_died (GPid pid, gint status, gpointer user_data) { CsdMouseManager *manager = CSD_MOUSE_MANAGER (user_data); g_debug ("syndaemon stopped with status %i", status); g_spawn_close_pid (pid); manager->priv->syndaemon_spawned = FALSE; } static int set_disable_w_typing_synaptics (CsdMouseManager *manager, gboolean state) { if (state && touchpad_is_present ()) { GError *error = NULL; GPtrArray *args; if (manager->priv->syndaemon_spawned) return 0; if (!have_program_in_path ("syndaemon")) return 0; args = g_ptr_array_new (); g_ptr_array_add (args, "syndaemon"); g_ptr_array_add (args, "-i"); g_ptr_array_add (args, "1.0"); g_ptr_array_add (args, "-t"); g_ptr_array_add (args, "-K"); g_ptr_array_add (args, "-R"); g_ptr_array_add (args, NULL); /* we must use G_SPAWN_DO_NOT_REAP_CHILD to avoid * double-forking, otherwise syndaemon will immediately get * killed again through (PR_SET_PDEATHSIG when the intermediate * process dies */ g_spawn_async (g_get_home_dir (), (char **) args->pdata, NULL, G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, setup_syndaemon, NULL, &manager->priv->syndaemon_pid, &error); manager->priv->syndaemon_spawned = (error == NULL); g_ptr_array_free (args, FALSE); if (error) { g_warning ("Failed to launch syndaemon: %s", error->message); g_settings_set_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING, FALSE); g_error_free (error); } else { g_child_watch_add (manager->priv->syndaemon_pid, syndaemon_died, manager); g_debug ("Launched syndaemon"); } } else if (manager->priv->syndaemon_spawned) { kill (manager->priv->syndaemon_pid, SIGHUP); g_spawn_close_pid (manager->priv->syndaemon_pid); manager->priv->syndaemon_spawned = FALSE; g_debug ("Killed syndaemon"); } return 0; } static int set_disable_w_typing_libinput (CsdMouseManager *manager, gboolean state) { GList *devices, *l; /* This is only called once for synaptics but for libinput we need * to loop through the list of devices */ devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; if (device_is_ignored (manager, device)) continue; touchpad_set_bool (device, "libinput Disable While Typing Enabled", 0, state); } g_list_free (devices); return 0; } static int set_disable_w_typing (CsdMouseManager *manager, gboolean state) { if (property_from_name ("Synaptics Off")) set_disable_w_typing_synaptics (manager, state); if (property_from_name ("libinput Disable While Typing Enabled")) set_disable_w_typing_libinput (manager, state); return 0; } static int set_disable_w_mouse_attached_libinput (CsdMouseManager *manager, gboolean state) { GList *devices, *l; /* This is only called once for synaptics but for libinput we need * to loop through the list of devices */ devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; if (device_is_ignored (manager, device)) continue; if (touchpad_get_bool (device, "libinput Send Events Modes Available", 1)) { touchpad_set_bool (device, "libinput Send Events Mode Enabled", 1, state); } } g_list_free (devices); return 0; } static void set_disable_w_mouse_attached (CsdMouseManager *manager, gboolean state) { set_disable_w_mouse_attached_libinput (manager, state); } static void set_tap_to_click_synaptics (GdkDevice *device, gboolean state, gboolean left_handed) { int format, rc; unsigned long nitems, bytes_after; XDevice *xdevice; unsigned char* data; Atom prop, type; prop = property_from_name ("Synaptics Tap Action"); if (!prop) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("setting tap to click on %s", gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 7) { /* Set MR mapping for corner tapping on the right side*/ data[0] = (state) ? 2 : 0; data[1] = (state) ? 3 : 0; /* Set RLM mapping for 1/2/3 fingers*/ data[4] = (state) ? ((left_handed) ? 3 : 1) : 0; data[5] = (state) ? ((left_handed) ? 1 : 3) : 0; data[6] = (state) ? 2 : 0; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error in setting tap to click on \"%s\"", gdk_device_get_name (device)); xdevice_close (xdevice); } static void set_tap_to_click_libinput (GdkDevice *device, gboolean state) { g_debug ("setting tap to click on %s", gdk_device_get_name (device)); touchpad_set_bool (device, "libinput Tapping Enabled", 0, state); } static void set_tap_to_click (GdkDevice *device, gboolean state, gboolean left_handed) { if (property_from_name ("Synaptics Tap Action")) set_tap_to_click_synaptics (device, state, left_handed); if (property_from_name ("libinput Tapping Enabled")) set_tap_to_click_libinput (device, state); } static void set_click_actions_synaptics (GdkDevice *device, gint clickpad_click, gboolean left_handed) { int format, rc; unsigned long nitems, bytes_after; XDevice *xdevice; unsigned char* data; Atom prop, type; gboolean state; prop = property_from_name ("Synaptics Click Action"); if (!prop) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("setting click action to click on %s", gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); state = (clickpad_click == 2) || (clickpad_click == 3); if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3) { data[0] = 1; data[1] = (state)? ((left_handed) ? 1 : 3) : 0; data[2] = (state)? 2 : 0; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error in setting click actions on \"%s\"", gdk_device_get_name (device)); xdevice_close (xdevice); } static void set_click_actions_libinput (GdkDevice *device, gint clickpad_click) { int format, rc, rc_default; unsigned long nitems, bytes_after; XDevice *xdevice; unsigned char* data, * data_default; Atom prop, prop_default, type; prop = property_from_name ("libinput Click Method Enabled"); if (!prop) return; prop_default = property_from_name("libinput Click Method Enabled Default"); if (!prop_default && clickpad_click == 3) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("setting click action to click on %s", gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (clickpad_click == 3) { rc_default = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_default, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data_default); } if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 2 && (rc_default == Success || clickpad_click != 3)) { data[0] = (clickpad_click == 1) || (clickpad_click == 3 && data_default[0]); data[1] = (clickpad_click == 2) || (clickpad_click == 3 && data_default[1]); XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); if (clickpad_click == 3 && rc_default == Success) XFree (data_default); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error in setting click actions on \"%s\"", gdk_device_get_name (device)); xdevice_close (xdevice); } static void set_click_actions (GdkDevice *device, gint clickpad_click, gboolean left_handed) { if (property_from_name ("Synaptics Click Action")) set_click_actions_synaptics (device, clickpad_click, left_handed); if (property_from_name ("libinput Click Method Enabled")) set_click_actions_libinput (device, clickpad_click); } static void set_scrolling_synaptics (GdkDevice *device, gint scrolling_method, gboolean horizontal_scroll) { gboolean want_edge, want_2fg; want_2fg = (scrolling_method == 1 || scrolling_method == 3); want_edge = (scrolling_method == 2 || scrolling_method == 3); touchpad_set_bool (device, "Synaptics Edge Scrolling", 0, want_edge); touchpad_set_bool (device, "Synaptics Edge Scrolling", 1, want_edge && horizontal_scroll); touchpad_set_bool (device, "Synaptics Two-Finger Scrolling", 0, want_2fg); touchpad_set_bool (device, "Synaptics Two-Finger Scrolling", 1, want_2fg && horizontal_scroll); } static void set_scrolling_libinput (GdkDevice *device, gint scrolling_method, gboolean horizontal_scroll) { int format, rc, rc_default; unsigned long nitems, bytes_after; XDevice *xdevice; unsigned char* data, * data_default; Atom prop, prop_default, type; prop = property_from_name ("libinput Scroll Method Enabled"); if (!prop) return; prop_default = property_from_name("libinput Scroll Method Enabled Default"); if (!prop_default && scrolling_method == 3) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("setting scroll method on %s", gdk_device_get_name (device)); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (scrolling_method == 3) { rc_default = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_default, 0, 2, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data_default); } if (rc == Success && type == XA_INTEGER && format == 8 && nitems >= 3 && (rc_default == Success || scrolling_method != 3)) { data[0] = (scrolling_method == 1) || (scrolling_method == 3 && data_default[0]); data[1] = (scrolling_method == 2) || (scrolling_method == 3 && data_default[1]); data[2] = 0 || (scrolling_method == 3 && data_default[2]); XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); if (scrolling_method == 3 && rc_default == Success) XFree (data_default); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error in setting scroll method on \"%s\"", gdk_device_get_name (device)); xdevice_close (xdevice); /* there are versions of libinput around with an undocumented missing T in Horizontal */ if (property_from_name ("libinput Horizonal Scroll Enabled")) touchpad_set_bool (device, "libinput Horizonal Scroll Enabled", 0, horizontal_scroll); else touchpad_set_bool (device, "libinput Horizontal Scroll Enabled", 0, horizontal_scroll); } static void set_scrolling (GdkDevice *device, gint scrolling_method, gboolean horizontal_scroll) { if (property_from_name ("Synaptics Edge Scrolling")) set_scrolling_synaptics (device, scrolling_method, horizontal_scroll); if (property_from_name ("libinput Scroll Method Enabled")) set_scrolling_libinput (device, scrolling_method, horizontal_scroll); } static void set_touchpad_disabled (GdkDevice *device) { int id; XDevice *xdevice; g_object_get (G_OBJECT (device), "device-id", &id, NULL); g_debug ("Trying to set device disabled for \"%s\" (%d)", gdk_device_get_name (device), id); xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } if (set_device_enabled (id, FALSE) == FALSE) g_warning ("Error disabling device \"%s\" (%d)", gdk_device_get_name (device), id); else g_debug ("Disabled device \"%s\" (%d)", gdk_device_get_name (device), id); xdevice_close (xdevice); } static void set_touchpad_enabled (int id) { XDevice *xdevice; g_debug ("Trying to set device enabled for %d", id); gdk_x11_display_error_trap_push (gdk_display_get_default ()); xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) != 0) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } if (set_device_enabled (id, TRUE) == FALSE) g_warning ("Error enabling device \"%d\"", id); else g_debug ("Enabled device %d", id); xdevice_close (xdevice); } static void set_locate_pointer (CsdMouseManager *manager, gboolean state) { if (state) { GError *error = NULL; char *args[2]; if (manager->priv->locate_pointer_spawned) return; args[0] = LIBEXECDIR "/csd-locate-pointer"; args[1] = NULL; g_spawn_async (NULL, args, NULL, 0, NULL, NULL, &manager->priv->locate_pointer_pid, &error); manager->priv->locate_pointer_spawned = (error == NULL); if (error) { g_settings_set_boolean (manager->priv->mouse_settings, KEY_LOCATE_POINTER, FALSE); g_error_free (error); } } else if (manager->priv->locate_pointer_spawned) { kill (manager->priv->locate_pointer_pid, SIGHUP); g_spawn_close_pid (manager->priv->locate_pointer_pid); manager->priv->locate_pointer_spawned = FALSE; } } static void set_mousetweaks_daemon (CsdMouseManager *manager, gboolean dwell_click_enabled, gboolean secondary_click_enabled) { GError *error = NULL; gchar *comm; gboolean run_daemon = dwell_click_enabled || secondary_click_enabled; if (run_daemon || manager->priv->mousetweaks_daemon_running) comm = g_strdup_printf ("mousetweaks %s", run_daemon ? "" : "-s"); else return; if (run_daemon) manager->priv->mousetweaks_daemon_running = TRUE; if (! g_spawn_command_line_async (comm, &error)) { if (error->code == G_SPAWN_ERROR_NOENT && run_daemon) { if (dwell_click_enabled) { g_settings_set_boolean (manager->priv->mouse_a11y_settings, KEY_DWELL_CLICK_ENABLED, FALSE); } else if (secondary_click_enabled) { g_settings_set_boolean (manager->priv->mouse_a11y_settings, KEY_SECONDARY_CLICK_ENABLED, FALSE); } g_warning("Error enabling mouse accessibility features (mousetweaks is not installed)"); } g_error_free (error); } g_free (comm); } static gboolean get_touchpad_handedness (CsdMouseManager *manager, gboolean mouse_left_handed) { switch (g_settings_get_enum (manager->priv->touchpad_settings, KEY_LEFT_HANDED)) { case CSD_TOUCHPAD_HANDEDNESS_RIGHT: return FALSE; case CSD_TOUCHPAD_HANDEDNESS_LEFT: return TRUE; case CSD_TOUCHPAD_HANDEDNESS_MOUSE: return mouse_left_handed; default: g_assert_not_reached (); } } static void set_scroll_wheel_button (CsdMouseManager *manager, GdkDevice *device) { Atom wheel_prop, button_prop; XDevice *xdevice; Atom type; int format; unsigned long nitems, bytes_after; unsigned char *data = NULL; int button; int rc; if (!device_is_trackball (device)) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; wheel_prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Evdev Wheel Emulation", True); button_prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Evdev Wheel Emulation Button", True); if (!wheel_prop || !button_prop) { xdevice_close (xdevice); return; } g_debug ("setting scroll wheel emulation on %s", gdk_device_get_name (device)); gdk_error_trap_push (); button = g_settings_get_int (manager->priv->trackball_settings, KEY_SCROLL_WHEEL_BUTTON); /* Whether scroll wheel emulation is enabled */ rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, wheel_prop, 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && format == 8 && type == XA_INTEGER && nitems == 1) { data[0] = button > 0 ? 1 : 0; gdk_error_trap_push (); XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, wheel_prop, type, format, PropModeReplace, data, nitems); } if (data) { XFree (data); data = NULL; } /* Which button is used for the emulation */ if (button > 0) { rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, button_prop, 0, 1, False, XA_INTEGER, &type, &format, &nitems, &bytes_after, &data); if (rc == Success && format == 8 && type == XA_INTEGER && nitems == 1) { data[0] = button; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, button_prop, type, format, PropModeReplace, data, nitems); } if (data) XFree (data); } if (gdk_error_trap_pop ()) g_warning ("Error in setting scroll wheel emulation on \"%s\"", gdk_device_get_name (device)); xdevice_close (xdevice); } static void set_mouse_settings (CsdMouseManager *manager, GdkDevice *device) { gboolean mouse_left_handed, touchpad_left_handed; mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED); touchpad_left_handed = get_touchpad_handedness (manager, mouse_left_handed); set_left_handed (manager, device, mouse_left_handed, touchpad_left_handed); set_motion (manager, device); set_middle_button (manager, device, g_settings_get_boolean (manager->priv->mouse_settings, KEY_MIDDLE_BUTTON_EMULATION)); set_tap_to_click (device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TAP_TO_CLICK), touchpad_left_handed); set_click_actions( device, g_settings_get_int (manager->priv->touchpad_settings, KEY_CLICKPAD_CLICK), touchpad_left_handed); set_scrolling (device, g_settings_get_int (manager->priv->touchpad_settings, KEY_SCROLL_METHOD), g_settings_get_boolean (manager->priv->touchpad_settings, KEY_HORIZ_SCROLL)); if (gdkdevice_is_touchpad (device)) { set_natural_scroll (manager, device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_NATURAL_SCROLL_ENABLED)); } else { set_natural_scroll (manager, device, g_settings_get_boolean (manager->priv->mouse_settings, KEY_NATURAL_SCROLL_ENABLED)); } if (g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_ENABLED) == FALSE) set_touchpad_disabled (device); set_scroll_wheel_button (manager, device); } static void set_natural_scroll_synaptics (CsdMouseManager *manager, GdkDevice *device, gboolean natural_scroll) { XDevice *xdevice; Atom scrolling_distance, act_type; int rc, act_format; unsigned long nitems, bytes_after; unsigned char *data; glong *ptr; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("Trying to set %s for \"%s\"", natural_scroll ? "natural (reverse) scroll" : "normal scroll", gdk_device_get_name (device)); scrolling_distance = property_from_name ("Synaptics Scrolling Distance"); gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, scrolling_distance, 0, 2, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success && act_type == XA_INTEGER && act_format == 32 && nitems >= 2) { ptr = (glong *) data; if (natural_scroll) { ptr[0] = -abs(ptr[0]); ptr[1] = -abs(ptr[1]); } else { ptr[0] = abs(ptr[0]); ptr[1] = abs(ptr[1]); } XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, scrolling_distance, XA_INTEGER, act_format, PropModeReplace, data, nitems); } if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Error setting %s for \"%s\"", natural_scroll ? "natural (reverse) scroll" : "normal scroll", gdk_device_get_name (device)); if (rc == Success) XFree (data); xdevice_close (xdevice); } static void set_natural_scroll_libinput (CsdMouseManager *manager, GdkDevice *device, gboolean natural_scroll) { g_debug ("Trying to set %s for \"%s\"", natural_scroll ? "natural (reverse) scroll" : "normal scroll", gdk_device_get_name (device)); XDevice *xdevice; xdevice = open_gdk_device (device); if (xdevice == NULL) return; property_set_bool (device, xdevice, "libinput Natural Scrolling Enabled", 0, natural_scroll); xdevice_close (xdevice); } static void set_natural_scroll (CsdMouseManager *manager, GdkDevice *device, gboolean natural_scroll) { if (property_from_name ("Synaptics Scrolling Distance")) set_natural_scroll_synaptics (manager, device, natural_scroll); if (property_from_name ("libinput Natural Scrolling Enabled")) set_natural_scroll_libinput (manager, device, natural_scroll); } static void mouse_callback (GSettings *settings, const gchar *key, CsdMouseManager *manager) { GList *devices, *l; if (g_str_equal (key, KEY_DWELL_CLICK_ENABLED) || g_str_equal (key, KEY_SECONDARY_CLICK_ENABLED)) { set_mousetweaks_daemon (manager, g_settings_get_boolean (settings, KEY_DWELL_CLICK_ENABLED), g_settings_get_boolean (settings, KEY_SECONDARY_CLICK_ENABLED)); return; } else if (g_str_equal (key, KEY_LOCATE_POINTER)) { set_locate_pointer (manager, g_settings_get_boolean (settings, KEY_LOCATE_POINTER)); return; } devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; if (device_is_ignored (manager, device)) continue; if (gdkdevice_is_touchpad (device)) continue; if (g_str_equal (key, KEY_LEFT_HANDED)) { gboolean mouse_left_handed; mouse_left_handed = g_settings_get_boolean (settings, KEY_LEFT_HANDED); set_left_handed (manager, device, mouse_left_handed, get_touchpad_handedness (manager, mouse_left_handed)); } else if (g_str_equal (key, KEY_MOTION_ACCELERATION) || g_str_equal (key, KEY_CUSTOM_ACCELERATION) || g_str_equal (key, KEY_MOTION_THRESHOLD) || g_str_equal (key, KEY_CUSTOM_THRESHOLD)) { set_motion (manager, device); } else if (g_str_equal (key, KEY_MIDDLE_BUTTON_EMULATION)) { set_middle_button (manager, device, g_settings_get_boolean (settings, KEY_MIDDLE_BUTTON_EMULATION)); } else if (g_str_equal (key, KEY_NATURAL_SCROLL_ENABLED)) { set_natural_scroll (manager, device, g_settings_get_boolean (settings, key)); } } g_list_free (devices); } static void trackball_callback (GSettings *settings, const gchar *key, CsdMouseManager *manager) { GList *devices, *l; devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; if (device_is_ignored (manager, device)) continue; set_scroll_wheel_button (manager, device); } g_list_free (devices); } /* Re-enable touchpad when any other pointing device isn't present. */ static void ensure_touchpad_active (CsdMouseManager *manager) { if (mouse_is_present () == FALSE && touchscreen_is_present () == FALSE && touchpad_is_present ()) g_settings_set_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_ENABLED, TRUE); } static void touchpad_callback (GSettings *settings, const gchar *key, CsdMouseManager *manager) { GList *devices, *l; if (g_str_equal (key, KEY_TOUCHPAD_DISABLE_W_TYPING)) { set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, key)); return; } if (g_str_equal (key, KEY_TOUCHPAD_DISABLE_WITH_MOUSE)) { set_disable_w_mouse_attached (manager, g_settings_get_boolean (manager->priv->touchpad_settings, key)); return; } devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; if (device_is_ignored (manager, device)) continue; if (!gdkdevice_is_touchpad (device)) continue; if (g_str_equal (key, KEY_TAP_TO_CLICK)) { gboolean mouse_left_handed; mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED); set_tap_to_click (device, g_settings_get_boolean (settings, key), get_touchpad_handedness (manager, mouse_left_handed)); } else if (g_str_equal(key, KEY_CLICKPAD_CLICK)) { gboolean mouse_left_handed; mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED); set_click_actions( device, g_settings_get_int (manager->priv->touchpad_settings, KEY_CLICKPAD_CLICK), get_touchpad_handedness(manager, mouse_left_handed)); } else if (g_str_equal (key, KEY_SCROLL_METHOD) || g_str_equal (key, KEY_HORIZ_SCROLL)) { set_scrolling (device, g_settings_get_int (manager->priv->touchpad_settings, KEY_SCROLL_METHOD), g_settings_get_boolean (manager->priv->touchpad_settings, KEY_HORIZ_SCROLL)); } else if (g_str_equal (key, KEY_TOUCHPAD_ENABLED)) { if (g_settings_get_boolean (settings, key) == FALSE) set_touchpad_disabled (device); else set_touchpad_enabled (gdk_x11_device_get_id (device)); } else if (g_str_equal (key, KEY_MOTION_ACCELERATION) || g_str_equal (key, KEY_CUSTOM_ACCELERATION) || g_str_equal (key, KEY_MOTION_THRESHOLD) || g_str_equal (key, KEY_CUSTOM_THRESHOLD)) { set_motion (manager, device); } else if (g_str_equal (key, KEY_LEFT_HANDED)) { gboolean mouse_left_handed; mouse_left_handed = g_settings_get_boolean (manager->priv->mouse_settings, KEY_LEFT_HANDED); set_left_handed (manager, device, mouse_left_handed, get_touchpad_handedness (manager, mouse_left_handed)); } else if (g_str_equal (key, KEY_NATURAL_SCROLL_ENABLED)) { set_natural_scroll (manager, device, g_settings_get_boolean (settings, key)); } } g_list_free (devices); if (g_str_equal (key, KEY_TOUCHPAD_ENABLED) && g_settings_get_boolean (settings, key)) { devices = get_disabled_devices (manager->priv->device_manager); for (l = devices; l != NULL; l = l->next) { int device_id; device_id = GPOINTER_TO_INT (l->data); set_touchpad_enabled (device_id); } g_list_free (devices); } } static void device_added_cb (GdkDeviceManager *device_manager, GdkDevice *device, CsdMouseManager *manager) { if (device_is_ignored (manager, device) == FALSE) { if (run_custom_command (device, COMMAND_DEVICE_ADDED) == FALSE) { set_mouse_settings (manager, device); } else { int id; g_object_get (G_OBJECT (device), "device-id", &id, NULL); g_hash_table_insert (manager->priv->blacklist, GINT_TO_POINTER (id), GINT_TO_POINTER (1)); } /* If a touchpad was to appear... */ set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING)); set_disable_w_mouse_attached (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_WITH_MOUSE)); } } static void device_removed_cb (GdkDeviceManager *device_manager, GdkDevice *device, CsdMouseManager *manager) { int id; /* Remove the device from the hash table so that * device_is_ignored () doesn't check for blacklisted devices */ g_object_get (G_OBJECT (device), "device-id", &id, NULL); g_hash_table_remove (manager->priv->blacklist, GINT_TO_POINTER (id)); if (device_is_ignored (manager, device) == FALSE) { run_custom_command (device, COMMAND_DEVICE_REMOVED); /* If a touchpad was to disappear... */ set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING)); ensure_touchpad_active (manager); } } static void set_devicepresence_handler (CsdMouseManager *manager) { GdkDeviceManager *device_manager; device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); manager->priv->device_added_id = g_signal_connect (G_OBJECT (device_manager), "device-added", G_CALLBACK (device_added_cb), manager); manager->priv->device_removed_id = g_signal_connect (G_OBJECT (device_manager), "device-removed", G_CALLBACK (device_removed_cb), manager); manager->priv->device_manager = device_manager; } static void csd_mouse_manager_init (CsdMouseManager *manager) { manager->priv = CSD_MOUSE_MANAGER_GET_PRIVATE (manager); manager->priv->blacklist = g_hash_table_new (g_direct_hash, g_direct_equal); } static gboolean csd_mouse_manager_idle_cb (CsdMouseManager *manager) { GList *devices, *l; cinnamon_settings_profile_start (NULL); set_devicepresence_handler (manager); manager->priv->mouse_settings = g_settings_new (SETTINGS_MOUSE_DIR); g_signal_connect (manager->priv->mouse_settings, "changed", G_CALLBACK (mouse_callback), manager); manager->priv->mouse_a11y_settings = g_settings_new ("org.cinnamon.desktop.a11y.mouse"); g_signal_connect (manager->priv->mouse_a11y_settings, "changed", G_CALLBACK (mouse_callback), manager); manager->priv->touchpad_settings = g_settings_new (SETTINGS_TOUCHPAD_DIR); g_signal_connect (manager->priv->touchpad_settings, "changed", G_CALLBACK (touchpad_callback), manager); manager->priv->trackball_settings = g_settings_new (SETTINGS_TRACKBALL_DIR); g_signal_connect (manager->priv->trackball_settings, "changed", G_CALLBACK (trackball_callback), manager); manager->priv->syndaemon_spawned = FALSE; set_locate_pointer (manager, g_settings_get_boolean (manager->priv->mouse_settings, KEY_LOCATE_POINTER)); set_mousetweaks_daemon (manager, g_settings_get_boolean (manager->priv->mouse_a11y_settings, KEY_DWELL_CLICK_ENABLED), g_settings_get_boolean (manager->priv->mouse_a11y_settings, KEY_SECONDARY_CLICK_ENABLED)); set_disable_w_typing (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_W_TYPING)); set_disable_w_mouse_attached (manager, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_DISABLE_WITH_MOUSE)); devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; if (device_is_ignored (manager, device)) continue; if (run_custom_command (device, COMMAND_DEVICE_PRESENT) == FALSE) { set_mouse_settings (manager, device); } else { int id; g_object_get (G_OBJECT (device), "device-id", &id, NULL); g_hash_table_insert (manager->priv->blacklist, GINT_TO_POINTER (id), GINT_TO_POINTER (1)); } } g_list_free (devices); ensure_touchpad_active (manager); if (g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_ENABLED)) { devices = get_disabled_devices (manager->priv->device_manager); for (l = devices; l != NULL; l = l->next) { int device_id; device_id = GPOINTER_TO_INT (l->data); set_touchpad_enabled (device_id); } g_list_free (devices); } cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } gboolean csd_mouse_manager_start (CsdMouseManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); if (!supports_xinput_devices ()) { g_debug ("XInput is not supported, not applying any settings"); return TRUE; } manager->priv->start_idle_id = g_idle_add ((GSourceFunc) csd_mouse_manager_idle_cb, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_mouse_manager_stop (CsdMouseManager *manager) { CsdMouseManagerPrivate *p = manager->priv; g_debug ("Stopping mouse manager"); if (manager->priv->start_idle_id != 0) { g_source_remove (manager->priv->start_idle_id); manager->priv->start_idle_id = 0; } if (p->device_manager != NULL) { g_signal_handler_disconnect (p->device_manager, p->device_added_id); g_signal_handler_disconnect (p->device_manager, p->device_removed_id); p->device_manager = NULL; } g_clear_object (&p->mouse_a11y_settings); g_clear_object (&p->mouse_settings); g_clear_object (&p->touchpad_settings); g_clear_object (&p->trackball_settings); set_locate_pointer (manager, FALSE); } static void csd_mouse_manager_finalize (GObject *object) { CsdMouseManager *mouse_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_MOUSE_MANAGER (object)); mouse_manager = CSD_MOUSE_MANAGER (object); g_return_if_fail (mouse_manager->priv != NULL); csd_mouse_manager_stop (mouse_manager); G_OBJECT_CLASS (csd_mouse_manager_parent_class)->finalize (object); } CsdMouseManager * csd_mouse_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_MOUSE_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_MOUSE_MANAGER (manager_object); } cinnamon-settings-daemon-5.2.0/plugins/mouse/csd-locate-pointer.h0000664000175000017500000000153314144454032024024 0ustar fabiofabio/* * Copyright 2001 Jonathan Blandford * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Red Hat not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Red Hat makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * Authors: Jonathan Blandford */ #ifndef LOCATE_POINTER_H #define LOCATE_POINTER_H #include void csd_locate_pointer (GdkScreen *screen); #endif cinnamon-settings-daemon-5.2.0/plugins/mouse/meson.build0000664000175000017500000000236614144454032022326 0ustar fabiofabioplugin_name = 'mouse' mouse_sources = [ 'csd-mouse-manager.c', 'main.c', ] find_pointer_sources = [ 'csd-locate-pointer.c', 'csd-timeline.c', ] mouse_deps = [ common_dep, csd_dep, libnotify, math, ] executable( 'csd-mouse', mouse_sources, include_directories: [include_dirs, common_inc, include_enums], dependencies: mouse_deps, c_args: [ '-DPLUGIN_NAME="@0@"'.format(plugin_name), ], install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-mouse') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-mouse') endif executable( 'csd-locate-pointer', find_pointer_sources, include_directories: [include_dirs, common_inc], dependencies: mouse_deps, install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-locate-pointer') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-locate-pointer') endif configure_file( input: 'cinnamon-settings-daemon-mouse.desktop.in', output: 'cinnamon-settings-daemon-mouse.desktop', configuration: desktop_conf, install_dir: autostartdir, ) cinnamon-settings-daemon-5.2.0/plugins/mouse/csd-timeline.h0000664000175000017500000001210514144454032022702 0ustar fabiofabio/* csdtimeline.c * * Copyright (C) 2008 Carlos Garnacho * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. */ #ifndef __CSD_TIMELINE_H__ #define __CSD_TIMELINE_H__ #include #include G_BEGIN_DECLS #define CSD_TYPE_TIMELINE_DIRECTION (csd_timeline_direction_get_type ()) #define CSD_TYPE_TIMELINE_PROGRESS_TYPE (csd_timeline_progress_type_get_type ()) #define CSD_TYPE_TIMELINE (csd_timeline_get_type ()) #define CSD_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSD_TYPE_TIMELINE, CsdTimeline)) #define CSD_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSD_TYPE_TIMELINE, CsdTimelineClass)) #define CSD_IS_TIMELINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSD_TYPE_TIMELINE)) #define CSD_IS_TIMELINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSD_TYPE_TIMELINE)) #define CSD_TIMELINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CSD_TYPE_TIMELINE, CsdTimelineClass)) typedef enum { CSD_TIMELINE_DIRECTION_FORWARD, CSD_TIMELINE_DIRECTION_BACKWARD } CsdTimelineDirection; typedef enum { CSD_TIMELINE_PROGRESS_LINEAR, CSD_TIMELINE_PROGRESS_SINUSOIDAL, CSD_TIMELINE_PROGRESS_EXPONENTIAL } CsdTimelineProgressType; typedef struct CsdTimeline CsdTimeline; typedef struct CsdTimelineClass CsdTimelineClass; struct CsdTimeline { GObject parent_instance; }; struct CsdTimelineClass { GObjectClass parent_class; void (* started) (CsdTimeline *timeline); void (* finished) (CsdTimeline *timeline); void (* paused) (CsdTimeline *timeline); void (* frame) (CsdTimeline *timeline, gdouble progress); void (* __csd_reserved1) (void); void (* __csd_reserved2) (void); void (* __csd_reserved3) (void); void (* __csd_reserved4) (void); }; typedef gdouble (*CsdTimelineProgressFunc) (gdouble progress); GType csd_timeline_get_type (void) G_GNUC_CONST; GType csd_timeline_direction_get_type (void) G_GNUC_CONST; GType csd_timeline_progress_type_get_type (void) G_GNUC_CONST; CsdTimeline *csd_timeline_new (guint duration); CsdTimeline *csd_timeline_new_for_screen (guint duration, GdkScreen *screen); void csd_timeline_start (CsdTimeline *timeline); void csd_timeline_pause (CsdTimeline *timeline); void csd_timeline_rewind (CsdTimeline *timeline); gboolean csd_timeline_is_running (CsdTimeline *timeline); guint csd_timeline_get_fps (CsdTimeline *timeline); void csd_timeline_set_fps (CsdTimeline *timeline, guint fps); gboolean csd_timeline_get_loop (CsdTimeline *timeline); void csd_timeline_set_loop (CsdTimeline *timeline, gboolean loop); guint csd_timeline_get_duration (CsdTimeline *timeline); void csd_timeline_set_duration (CsdTimeline *timeline, guint duration); GdkScreen *csd_timeline_get_screen (CsdTimeline *timeline); void csd_timeline_set_screen (CsdTimeline *timeline, GdkScreen *screen); CsdTimelineDirection csd_timeline_get_direction (CsdTimeline *timeline); void csd_timeline_set_direction (CsdTimeline *timeline, CsdTimelineDirection direction); CsdTimelineProgressType csd_timeline_get_progress_type (CsdTimeline *timeline); void csd_timeline_set_progress_type (CsdTimeline *timeline, CsdTimelineProgressType type); void csd_timeline_get_progress_func (CsdTimeline *timeline); void csd_timeline_set_progress_func (CsdTimeline *timeline, CsdTimelineProgressFunc progress_func); gdouble csd_timeline_get_progress (CsdTimeline *timeline); G_END_DECLS #endif /* __CSD_TIMELINE_H__ */ cinnamon-settings-daemon-5.2.0/plugins/mouse/main.c0000664000175000017500000000100514144454032021241 0ustar fabiofabio#define NEW csd_mouse_manager_new #define START csd_mouse_manager_start #define STOP csd_mouse_manager_stop #define MANAGER CsdMouseManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-mouse-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-5.2.0/plugins/mouse/cinnamon-settings-daemon-mouse.desktop.in0000664000175000017500000000033214144454032030202 0ustar fabiofabio[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - mouse Exec=csd-mouse OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-5.2.0/plugins/mouse/csd-timeline.c0000664000175000017500000004741114144454032022705 0ustar fabiofabio/* csd-timeline.c * * Copyright (C) 2008 Carlos Garnacho * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. */ #include #include #include #include "csd-timeline.h" #define CSD_TIMELINE_GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CSD_TYPE_TIMELINE, CsdTimelinePriv)) #define MSECS_PER_SEC 1000 #define FRAME_INTERVAL(nframes) (MSECS_PER_SEC / nframes) #define DEFAULT_FPS 30 typedef struct CsdTimelinePriv CsdTimelinePriv; struct CsdTimelinePriv { guint duration; guint fps; guint source_id; GTimer *timer; GdkScreen *screen; CsdTimelineProgressType progress_type; CsdTimelineProgressFunc progress_func; guint loop : 1; guint direction : 1; }; enum { PROP_0, PROP_FPS, PROP_DURATION, PROP_LOOP, PROP_DIRECTION, PROP_SCREEN, PROP_PROGRESS_TYPE, }; enum { STARTED, PAUSED, FINISHED, FRAME, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0, }; static void csd_timeline_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void csd_timeline_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void csd_timeline_finalize (GObject *object); G_DEFINE_TYPE (CsdTimeline, csd_timeline, G_TYPE_OBJECT) GType csd_timeline_direction_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GEnumValue values[] = { { CSD_TIMELINE_DIRECTION_FORWARD, "CSD_TIMELINE_DIRECTION_FORWARD", "forward" }, { CSD_TIMELINE_DIRECTION_BACKWARD, "CSD_TIMELINE_DIRECTION_BACKWARD", "backward" }, { 0, NULL, NULL } }; type = g_enum_register_static (g_intern_static_string ("CsdTimelineDirection"), values); } return type; } GType csd_timeline_progress_type_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GEnumValue values[] = { { CSD_TIMELINE_PROGRESS_LINEAR, "CSD_TIMELINE_PROGRESS_LINEAR", "linear" }, { CSD_TIMELINE_PROGRESS_SINUSOIDAL, "CSD_TIMELINE_PROGRESS_SINUSOIDAL", "sinusoidal" }, { CSD_TIMELINE_PROGRESS_EXPONENTIAL, "CSD_TIMELINE_PROGRESS_EXPONENTIAL", "exponential" }, { 0, NULL, NULL } }; type = g_enum_register_static (g_intern_static_string ("CsdTimelineProgressType"), values); } return type; } static void csd_timeline_class_init (CsdTimelineClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); object_class->set_property = csd_timeline_set_property; object_class->get_property = csd_timeline_get_property; object_class->finalize = csd_timeline_finalize; g_object_class_install_property (object_class, PROP_FPS, g_param_spec_uint ("fps", "FPS", "Frames per second for the timeline", 1, G_MAXUINT, DEFAULT_FPS, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DURATION, g_param_spec_uint ("duration", "Animation Duration", "Animation Duration", 0, G_MAXUINT, 0, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_LOOP, g_param_spec_boolean ("loop", "Loop", "Whether the timeline loops or not", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DIRECTION, g_param_spec_enum ("direction", "Direction", "Whether the timeline moves forward or backward in time", CSD_TYPE_TIMELINE_DIRECTION, CSD_TIMELINE_DIRECTION_FORWARD, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_DIRECTION, g_param_spec_enum ("progress-type", "Progress type", "Type of progress through the timeline", CSD_TYPE_TIMELINE_PROGRESS_TYPE, CSD_TIMELINE_PROGRESS_LINEAR, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_SCREEN, g_param_spec_object ("screen", "Screen", "Screen to get the settings from", GDK_TYPE_SCREEN, G_PARAM_READWRITE)); signals[STARTED] = g_signal_new ("started", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdTimelineClass, started), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[PAUSED] = g_signal_new ("paused", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdTimelineClass, paused), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[FINISHED] = g_signal_new ("finished", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdTimelineClass, finished), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[FRAME] = g_signal_new ("frame", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdTimelineClass, frame), NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); g_type_class_add_private (class, sizeof (CsdTimelinePriv)); } static void csd_timeline_init (CsdTimeline *timeline) { CsdTimelinePriv *priv; priv = CSD_TIMELINE_GET_PRIV (timeline); priv->fps = DEFAULT_FPS; priv->duration = 0; priv->direction = CSD_TIMELINE_DIRECTION_FORWARD; priv->screen = gdk_screen_get_default (); } static void csd_timeline_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsdTimeline *timeline; timeline = CSD_TIMELINE (object); switch (prop_id) { case PROP_FPS: csd_timeline_set_fps (timeline, g_value_get_uint (value)); break; case PROP_DURATION: csd_timeline_set_duration (timeline, g_value_get_uint (value)); break; case PROP_LOOP: csd_timeline_set_loop (timeline, g_value_get_boolean (value)); break; case PROP_DIRECTION: csd_timeline_set_direction (timeline, g_value_get_enum (value)); break; case PROP_SCREEN: csd_timeline_set_screen (timeline, GDK_SCREEN (g_value_get_object (value))); break; case PROP_PROGRESS_TYPE: csd_timeline_set_progress_type (timeline, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void csd_timeline_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdTimeline *timeline; CsdTimelinePriv *priv; timeline = CSD_TIMELINE (object); priv = CSD_TIMELINE_GET_PRIV (timeline); switch (prop_id) { case PROP_FPS: g_value_set_uint (value, priv->fps); break; case PROP_DURATION: g_value_set_uint (value, priv->duration); break; case PROP_LOOP: g_value_set_boolean (value, priv->loop); break; case PROP_DIRECTION: g_value_set_enum (value, priv->direction); break; case PROP_SCREEN: g_value_set_object (value, priv->screen); break; case PROP_PROGRESS_TYPE: g_value_set_enum (value, priv->progress_type); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void csd_timeline_finalize (GObject *object) { CsdTimelinePriv *priv; priv = CSD_TIMELINE_GET_PRIV (object); if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; } if (priv->timer) g_timer_destroy (priv->timer); G_OBJECT_CLASS (csd_timeline_parent_class)->finalize (object); } /* Sinusoidal progress */ static gdouble sinusoidal_progress (gdouble progress) { return (sinf ((progress * G_PI) / 2)); } static gdouble exponential_progress (gdouble progress) { return progress * progress; } static CsdTimelineProgressFunc progress_type_to_func (CsdTimelineProgressType type) { if (type == CSD_TIMELINE_PROGRESS_SINUSOIDAL) return sinusoidal_progress; else if (type == CSD_TIMELINE_PROGRESS_EXPONENTIAL) return exponential_progress; return NULL; } static gboolean csd_timeline_run_frame (CsdTimeline *timeline, gboolean enable_animations) { CsdTimelinePriv *priv; gdouble linear_progress, progress; guint elapsed_time; CsdTimelineProgressFunc progress_func = NULL; priv = CSD_TIMELINE_GET_PRIV (timeline); if (enable_animations) { elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); linear_progress = (gdouble) elapsed_time / priv->duration; if (priv->direction == CSD_TIMELINE_DIRECTION_BACKWARD) linear_progress = 1 - linear_progress; linear_progress = CLAMP (linear_progress, 0., 1.); if (priv->progress_func) progress_func = priv->progress_func; else if (priv->progress_type) progress_func = progress_type_to_func (priv->progress_type); if (progress_func) progress = (progress_func) (linear_progress); else progress = linear_progress; } else progress = (priv->direction == CSD_TIMELINE_DIRECTION_FORWARD) ? 1.0 : 0.0; g_signal_emit (timeline, signals [FRAME], 0, CLAMP (progress, 0.0, 1.0)); if ((priv->direction == CSD_TIMELINE_DIRECTION_FORWARD && progress >= 1.0) || (priv->direction == CSD_TIMELINE_DIRECTION_BACKWARD && progress <= 0.0)) { if (!priv->loop) { if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; } g_signal_emit (timeline, signals [FINISHED], 0); return FALSE; } else csd_timeline_rewind (timeline); } return TRUE; } static gboolean csd_timeline_frame_idle_func (CsdTimeline *timeline) { return csd_timeline_run_frame (timeline, TRUE); } /** * csd_timeline_new: * @duration: duration in milliseconds for the timeline * * Creates a new #CsdTimeline with the specified number of frames. * * Return Value: the newly created #CsdTimeline **/ CsdTimeline * csd_timeline_new (guint duration) { return g_object_new (CSD_TYPE_TIMELINE, "duration", duration, NULL); } CsdTimeline * csd_timeline_new_for_screen (guint duration, GdkScreen *screen) { return g_object_new (CSD_TYPE_TIMELINE, "duration", duration, "screen", screen, NULL); } /** * csd_timeline_start: * @timeline: A #CsdTimeline * * Runs the timeline from the current frame. **/ void csd_timeline_start (CsdTimeline *timeline) { CsdTimelinePriv *priv; GtkSettings *settings; gboolean enable_animations = FALSE; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); if (priv->screen) { settings = gtk_settings_get_for_screen (priv->screen); g_object_get (settings, "gtk-enable-animations", &enable_animations, NULL); } if (enable_animations) { if (!priv->source_id) { if (priv->timer) g_timer_continue (priv->timer); else priv->timer = g_timer_new (); /* sanity check */ g_assert (priv->fps > 0); g_signal_emit (timeline, signals [STARTED], 0); priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), (GSourceFunc) csd_timeline_frame_idle_func, timeline); } } else { /* If animations are not enabled, only run the last frame, * it take us instantaneously to the last state of the animation. * The only potential flaw happens when people use the ::finished * signal to trigger another animation, or even worse, finally * loop into this animation again. */ g_signal_emit (timeline, signals [STARTED], 0); csd_timeline_run_frame (timeline, FALSE); } } /** * csd_timeline_pause: * @timeline: A #CsdTimeline * * Pauses the timeline. **/ void csd_timeline_pause (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; g_timer_stop (priv->timer); g_signal_emit (timeline, signals [PAUSED], 0); } } /** * csd_timeline_rewind: * @timeline: A #CsdTimeline * * Rewinds the timeline. **/ void csd_timeline_rewind (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); /* destroy and re-create timer if necessary */ if (priv->timer) { g_timer_destroy (priv->timer); if (csd_timeline_is_running (timeline)) priv->timer = g_timer_new (); else priv->timer = NULL; } } /** * csd_timeline_is_running: * @timeline: A #CsdTimeline * * Returns whether the timeline is running or not. * * Return Value: %TRUE if the timeline is running **/ gboolean csd_timeline_is_running (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), FALSE); priv = CSD_TIMELINE_GET_PRIV (timeline); return (priv->source_id != 0); } /** * csd_timeline_get_fps: * @timeline: A #CsdTimeline * * Returns the number of frames per second. * * Return Value: frames per second **/ guint csd_timeline_get_fps (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), 1); priv = CSD_TIMELINE_GET_PRIV (timeline); return priv->fps; } /** * csd_timeline_set_fps: * @timeline: A #CsdTimeline * @fps: frames per second * * Sets the number of frames per second that * the timeline will play. **/ void csd_timeline_set_fps (CsdTimeline *timeline, guint fps) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); g_return_if_fail (fps > 0); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->fps = fps; if (csd_timeline_is_running (timeline)) { if (priv->source_id) { g_source_remove (priv->source_id); priv->source_id = 0; } priv->source_id = gdk_threads_add_timeout (FRAME_INTERVAL (priv->fps), (GSourceFunc) csd_timeline_run_frame, timeline); } g_object_notify (G_OBJECT (timeline), "fps"); } /** * csd_timeline_get_loop: * @timeline: A #CsdTimeline * * Returns whether the timeline loops to the * beginning when it has reached the end. * * Return Value: %TRUE if the timeline loops **/ gboolean csd_timeline_get_loop (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), FALSE); priv = CSD_TIMELINE_GET_PRIV (timeline); return priv->loop; } /** * csd_timeline_set_loop: * @timeline: A #CsdTimeline * @loop: %TRUE to make the timeline loop * * Sets whether the timeline loops to the beginning * when it has reached the end. **/ void csd_timeline_set_loop (CsdTimeline *timeline, gboolean loop) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->loop = loop; g_object_notify (G_OBJECT (timeline), "loop"); } void csd_timeline_set_duration (CsdTimeline *timeline, guint duration) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->duration = duration; g_object_notify (G_OBJECT (timeline), "duration"); } guint csd_timeline_get_duration (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), 0); priv = CSD_TIMELINE_GET_PRIV (timeline); return priv->duration; } /** * csd_timeline_get_direction: * @timeline: A #CsdTimeline * * Returns the direction of the timeline. * * Return Value: direction **/ CsdTimelineDirection csd_timeline_get_direction (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), CSD_TIMELINE_DIRECTION_FORWARD); priv = CSD_TIMELINE_GET_PRIV (timeline); return priv->direction; } /** * csd_timeline_set_direction: * @timeline: A #CsdTimeline * @direction: direction * * Sets the direction of the timeline. **/ void csd_timeline_set_direction (CsdTimeline *timeline, CsdTimelineDirection direction) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->direction = direction; g_object_notify (G_OBJECT (timeline), "direction"); } GdkScreen * csd_timeline_get_screen (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), NULL); priv = CSD_TIMELINE_GET_PRIV (timeline); return priv->screen; } void csd_timeline_set_screen (CsdTimeline *timeline, GdkScreen *screen) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); g_return_if_fail (GDK_IS_SCREEN (screen)); priv = CSD_TIMELINE_GET_PRIV (timeline); if (priv->screen) g_object_unref (priv->screen); priv->screen = g_object_ref (screen); g_object_notify (G_OBJECT (timeline), "screen"); } void csd_timeline_set_progress_type (CsdTimeline *timeline, CsdTimelineProgressType type) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->progress_type = type; g_object_notify (G_OBJECT (timeline), "progress-type"); } CsdTimelineProgressType csd_timeline_get_progress_type (CsdTimeline *timeline) { CsdTimelinePriv *priv; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), CSD_TIMELINE_PROGRESS_LINEAR); priv = CSD_TIMELINE_GET_PRIV (timeline); if (priv->progress_func) return CSD_TIMELINE_PROGRESS_LINEAR; return priv->progress_type; } /** * csd_timeline_set_progress_func: * @timeline: A #CsdTimeline * @progress_func: progress function * * Sets the progress function. This function will be used to calculate * a different progress to pass to the ::frame signal based on the * linear progress through the timeline. Setting progress_func * to %NULL will make the timeline use the default function, * which is just a linear progress. * * All progresses are in the [0.0, 1.0] range. **/ void csd_timeline_set_progress_func (CsdTimeline *timeline, CsdTimelineProgressFunc progress_func) { CsdTimelinePriv *priv; g_return_if_fail (CSD_IS_TIMELINE (timeline)); priv = CSD_TIMELINE_GET_PRIV (timeline); priv->progress_func = progress_func; } gdouble csd_timeline_get_progress (CsdTimeline *timeline) { CsdTimelinePriv *priv; CsdTimelineProgressFunc progress_func = NULL; gdouble linear_progress, progress; guint elapsed_time; g_return_val_if_fail (CSD_IS_TIMELINE (timeline), 0.0); priv = CSD_TIMELINE_GET_PRIV (timeline); if (!priv->timer) return 0.; elapsed_time = (guint) (g_timer_elapsed (priv->timer, NULL) * 1000); linear_progress = (gdouble) elapsed_time / priv->duration; if (priv->direction == CSD_TIMELINE_DIRECTION_BACKWARD) linear_progress = 1 - linear_progress; linear_progress = CLAMP (linear_progress, 0., 1.); if (priv->progress_func) progress_func = priv->progress_func; else if (priv->progress_type) progress_func = progress_type_to_func (priv->progress_type); if (progress_func) progress = (progress_func) (linear_progress); else progress = linear_progress; return CLAMP (progress, 0., 1.); } cinnamon-settings-daemon-5.2.0/plugins/mouse/csd-locate-pointer.c0000664000175000017500000003567614144454032024036 0ustar fabiofabio/* csd-locate-pointer.c * * Copyright (C) 2008 Carlos Garnacho * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. */ #include #include "csd-timeline.h" #include "csd-locate-pointer.h" #include #include #include #define ANIMATION_LENGTH 750 #define WINDOW_SIZE 101 #define N_CIRCLES 4 /* All circles are supposed to be moving when progress * reaches 0.5, and each of them are supposed to long * for half of the progress, hence the need of 0.5 to * get the circles interval, and the multiplication * by 2 to know a circle progress */ #define CIRCLES_PROGRESS_INTERVAL (0.5 / N_CIRCLES) #define CIRCLE_PROGRESS(p) (MIN (1., ((gdouble) (p) * 2.))) typedef struct CsdLocatePointerData CsdLocatePointerData; struct CsdLocatePointerData { CsdTimeline *timeline; GtkWidget *widget; GdkWindow *window; gdouble progress; }; static CsdLocatePointerData *data = NULL; static void locate_pointer_paint (CsdLocatePointerData *data, cairo_t *cr, gboolean composite) { GdkRGBA color; gdouble progress, circle_progress; gint width, height, i; GtkStyleContext *context; progress = data->progress; width = gdk_window_get_width (data->window); height = gdk_window_get_height (data->window); context = gtk_widget_get_style_context (data->widget); gtk_style_context_get_background_color (context, GTK_STATE_FLAG_SELECTED, &color); cairo_set_source_rgba (cr, 1., 1., 1., 0.); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); for (i = 0; i <= N_CIRCLES; i++) { if (progress < 0.) break; circle_progress = MIN (1., (progress * 2)); progress -= CIRCLES_PROGRESS_INTERVAL; if (circle_progress >= 1.) continue; if (composite) { cairo_set_source_rgba (cr, color.red, color.green, color.blue, 1 - circle_progress); cairo_arc (cr, width / 2, height / 2, circle_progress * width / 2, 0, 2 * G_PI); cairo_fill (cr); } else { cairo_set_source_rgb (cr, 0., 0., 0.); cairo_set_line_width (cr, 3.); cairo_arc (cr, width / 2, height / 2, circle_progress * width / 2, 0, 2 * G_PI); cairo_stroke (cr); cairo_set_source_rgb (cr, 1., 1., 1.); cairo_set_line_width (cr, 1.); cairo_arc (cr, width / 2, height / 2, circle_progress * width / 2, 0, 2 * G_PI); cairo_stroke (cr); } } } static gboolean locate_pointer_draw (GtkWidget *widget, cairo_t *cr, gpointer user_data) { CsdLocatePointerData *data = (CsdLocatePointerData *) user_data; if (gtk_cairo_should_draw_window (cr, data->window)) locate_pointer_paint (data, cr, gtk_widget_is_composited (data->widget)); return TRUE; } static void update_shape (CsdLocatePointerData *data) { cairo_t *cr; cairo_region_t *region; cairo_surface_t *mask; mask = cairo_image_surface_create (CAIRO_FORMAT_A1, WINDOW_SIZE, WINDOW_SIZE); cr = cairo_create (mask); locate_pointer_paint (data, cr, FALSE); region = gdk_cairo_region_create_from_surface (mask); gdk_window_shape_combine_region (data->window, region, 0, 0); cairo_region_destroy (region); cairo_destroy (cr); cairo_surface_destroy (mask); } static void timeline_frame_cb (CsdTimeline *timeline, gdouble progress, gpointer user_data) { CsdLocatePointerData *data = (CsdLocatePointerData *) user_data; GdkScreen *screen; GdkDeviceManager *device_manager; gint cursor_x, cursor_y; if (gtk_widget_is_composited (data->widget)) { gdk_window_invalidate_rect (data->window, NULL, FALSE); data->progress = progress; } else if (progress >= data->progress + CIRCLES_PROGRESS_INTERVAL) { /* only invalidate window each circle interval */ update_shape (data); gdk_window_invalidate_rect (data->window, NULL, FALSE); data->progress += CIRCLES_PROGRESS_INTERVAL; } screen = gdk_window_get_screen (data->window); device_manager = gdk_display_get_device_manager (gdk_window_get_display (data->window)); gdk_window_get_device_position (gdk_screen_get_root_window (screen), gdk_device_manager_get_client_pointer (device_manager), &cursor_x, &cursor_y, NULL); gdk_window_move (data->window, cursor_x - WINDOW_SIZE / 2, cursor_y - WINDOW_SIZE / 2); } static void set_transparent_shape (GdkWindow *window) { cairo_region_t *region; region = cairo_region_create (); gdk_window_shape_combine_region (data->window, region, 0, 0); cairo_region_destroy (region); } static void unset_transparent_shape (GdkWindow *window) { gdk_window_shape_combine_region (data->window, NULL, 0, 0); } static void composited_changed (GtkWidget *widget, CsdLocatePointerData *data) { if (!gtk_widget_is_composited (widget)) set_transparent_shape (data->window); else unset_transparent_shape (data->window); } static void timeline_finished_cb (CsdTimeline *timeline, gpointer user_data) { CsdLocatePointerData *data = (CsdLocatePointerData *) user_data; /* set transparent shape and hide window */ if (!gtk_widget_is_composited (data->widget)) set_transparent_shape (data->window); gtk_widget_hide (data->widget); gdk_window_hide (data->window); } static void create_window (CsdLocatePointerData *data, GdkScreen *screen) { GdkVisual *visual; GdkWindowAttr attributes; gint attributes_mask; visual = gdk_screen_get_rgba_visual (screen); if (visual == NULL) visual = gdk_screen_get_system_visual (screen); attributes_mask = GDK_WA_X | GDK_WA_Y; if (visual != NULL) attributes_mask = attributes_mask | GDK_WA_VISUAL; attributes.window_type = GDK_WINDOW_TEMP; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = visual; attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK; attributes.width = 1; attributes.height = 1; data->window = gdk_window_new (gdk_screen_get_root_window (screen), &attributes, attributes_mask); gdk_window_set_user_data (data->window, data->widget); } static CsdLocatePointerData * csd_locate_pointer_data_new (GdkScreen *screen) { CsdLocatePointerData *data; data = g_new0 (CsdLocatePointerData, 1); /* this widget will never be shown, it's * mainly used to get signals/events from */ data->widget = gtk_invisible_new (); gtk_widget_realize (data->widget); g_signal_connect (G_OBJECT (data->widget), "draw", G_CALLBACK (locate_pointer_draw), data); data->timeline = csd_timeline_new (ANIMATION_LENGTH); g_signal_connect (data->timeline, "frame", G_CALLBACK (timeline_frame_cb), data); g_signal_connect (data->timeline, "finished", G_CALLBACK (timeline_finished_cb), data); create_window (data, screen); return data; } static void move_locate_pointer_window (CsdLocatePointerData *data, GdkScreen *screen) { GdkDeviceManager *device_manager; cairo_region_t *region; gint cursor_x, cursor_y; device_manager = gdk_display_get_device_manager (gdk_window_get_display (data->window)); gdk_window_get_device_position (gdk_screen_get_root_window (screen), gdk_device_manager_get_client_pointer (device_manager), &cursor_x, &cursor_y, NULL); gdk_window_move_resize (data->window, cursor_x - WINDOW_SIZE / 2, cursor_y - WINDOW_SIZE / 2, WINDOW_SIZE, WINDOW_SIZE); /* allow events to happen through the window */ region = cairo_region_create (); gdk_window_input_shape_combine_region (data->window, region, 0, 0); cairo_region_destroy (region); } void csd_locate_pointer (GdkScreen *screen) { if (!data) data = csd_locate_pointer_data_new (screen); csd_timeline_pause (data->timeline); csd_timeline_rewind (data->timeline); /* Create again the window if it is not for the current screen */ if (gdk_screen_get_number (screen) != gdk_screen_get_number (gdk_window_get_screen (data->window))) { gdk_window_set_user_data (data->window, NULL); gdk_window_destroy (data->window); create_window (data, screen); } data->progress = 0.; g_signal_connect (data->widget, "composited-changed", G_CALLBACK (composited_changed), data); move_locate_pointer_window (data, screen); composited_changed (data->widget, data); gdk_window_show (data->window); gtk_widget_show (data->widget); csd_timeline_start (data->timeline); } #define KEYBOARD_GROUP_SHIFT 13 #define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14)) /* Owen magic */ static GdkFilterReturn filter (GdkXEvent *xevent, GdkEvent *event, gpointer data) { XEvent *xev = (XEvent *) xevent; guint keyval; gint group; GdkScreen *screen = (GdkScreen *)data; if (xev->type == ButtonPress) { XAllowEvents (xev->xbutton.display, ReplayPointer, xev->xbutton.time); XUngrabButton (xev->xbutton.display, AnyButton, AnyModifier, xev->xbutton.window); XUngrabKeyboard (xev->xbutton.display, xev->xbutton.time); } if (xev->type == KeyPress || xev->type == KeyRelease) { /* get the keysym */ group = (xev->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT; gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (), xev->xkey.keycode, xev->xkey.state, group, &keyval, NULL, NULL, NULL); if (keyval == GDK_KEY_Control_L || keyval == GDK_KEY_Control_R) { if (xev->type == KeyPress) { XAllowEvents (xev->xkey.display, SyncKeyboard, xev->xkey.time); XGrabButton (xev->xkey.display, AnyButton, AnyModifier, xev->xkey.window, False, ButtonPressMask, GrabModeSync, GrabModeAsync, None, None); } else { XUngrabButton (xev->xkey.display, AnyButton, AnyModifier, xev->xkey.window); XAllowEvents (xev->xkey.display, AsyncKeyboard, xev->xkey.time); csd_locate_pointer (screen); } } else { XAllowEvents (xev->xkey.display, ReplayKeyboard, xev->xkey.time); XUngrabButton (xev->xkey.display, AnyButton, AnyModifier, xev->xkey.window); XUngrabKeyboard (xev->xkey.display, xev->xkey.time); } } return GDK_FILTER_CONTINUE; } static void set_locate_pointer (void) { GdkKeymapKey *keys; GdkDisplay *display; GdkScreen *screen; Window xroot; int n_keys; gboolean has_entries; static const guint keyvals[] = { GDK_KEY_Control_L, GDK_KEY_Control_R }; unsigned i,j; display = gdk_display_get_default (); screen = gdk_screen_get_default (); xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (screen)); for (j = 0 ; j < G_N_ELEMENTS (keyvals) ; j++) { has_entries = gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), keyvals[j], &keys, &n_keys); if (has_entries) { for (i = 0; i < n_keys; i++) { gdk_x11_display_error_trap_push (display); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[i].keycode, 0, xroot, False, GrabModeAsync, GrabModeSync); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[i].keycode, LockMask, xroot, False, GrabModeAsync, GrabModeSync); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[i].keycode, Mod2Mask, xroot, False, GrabModeAsync, GrabModeSync); XGrabKey (GDK_DISPLAY_XDISPLAY (display), keys[i].keycode, Mod4Mask, xroot, False, GrabModeAsync, GrabModeSync); gdk_x11_display_error_trap_pop_ignored (display); } g_free (keys); gdk_window_add_filter (gdk_screen_get_root_window (screen), filter, screen); } } } int main (int argc, char *argv[]) { gdk_disable_multidevice (); gtk_init (&argc, &argv); set_locate_pointer (); gtk_main (); return 0; } cinnamon-settings-daemon-5.2.0/plugins/mouse/csd-mouse-manager.h0000664000175000017500000000437314144454032023644 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CSD_MOUSE_MANAGER_H #define __CSD_MOUSE_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_MOUSE_MANAGER (csd_mouse_manager_get_type ()) #define CSD_MOUSE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_MOUSE_MANAGER, CsdMouseManager)) #define CSD_MOUSE_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_MOUSE_MANAGER, CsdMouseManagerClass)) #define CSD_IS_MOUSE_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_MOUSE_MANAGER)) #define CSD_IS_MOUSE_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_MOUSE_MANAGER)) #define CSD_MOUSE_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_MOUSE_MANAGER, CsdMouseManagerClass)) typedef struct CsdMouseManagerPrivate CsdMouseManagerPrivate; typedef struct { GObject parent; CsdMouseManagerPrivate *priv; } CsdMouseManager; typedef struct { GObjectClass parent_class; } CsdMouseManagerClass; GType csd_mouse_manager_get_type (void); CsdMouseManager * csd_mouse_manager_new (void); gboolean csd_mouse_manager_start (CsdMouseManager *manager, GError **error); void csd_mouse_manager_stop (CsdMouseManager *manager); G_END_DECLS #endif /* __CSD_MOUSE_MANAGER_H */ cinnamon-settings-daemon-5.2.0/plugins/wacom/0000775000175000017500000000000014144454032020133 5ustar fabiofabiocinnamon-settings-daemon-5.2.0/plugins/wacom/csd-wacom-osd-window.h0000664000175000017500000000636314144454032024261 0ustar fabiofabio/* * Copyright (C) 2012 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Author: Olivier Fourdan * */ #ifndef __CSD_WACOM_OSD_WINDOW_H #define __CSD_WACOM_OSD_WINDOW_H #include #include #include "csd-wacom-device.h" #define CSD_TYPE_WACOM_OSD_WINDOW (csd_wacom_osd_window_get_type ()) #define CSD_WACOM_OSD_WINDOW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_WACOM_OSD_WINDOW, CsdWacomOSDWindow)) #define CSD_WACOM_OSD_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_WACOM_OSD_WINDOW, CsdWacomOSDWindowClass)) #define CSD_IS_WACOM_OSD_WINDOW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_WACOM_OSD_WINDOW)) #define CSD_IS_WACOM_OSD_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_WACOM_OSD_WINDOW)) #define CSD_WACOM_OSD_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_WACOM_OSD_WINDOW, CsdWacomOSDWindowClass)) typedef struct CsdWacomOSDWindowPrivate CsdWacomOSDWindowPrivate; typedef struct { GtkWindow window; CsdWacomOSDWindowPrivate *priv; } CsdWacomOSDWindow; typedef struct { GtkWindowClass parent_class; } CsdWacomOSDWindowClass; GType csd_wacom_osd_window_get_type (void) G_GNUC_CONST; CsdWacomDevice * csd_wacom_osd_window_get_device (CsdWacomOSDWindow *osd_window); void csd_wacom_osd_window_set_message (CsdWacomOSDWindow *osd_window, const gchar *str); const char * csd_wacom_osd_window_get_message (CsdWacomOSDWindow *osd_window); void csd_wacom_osd_window_set_active (CsdWacomOSDWindow *osd_window, CsdWacomTabletButton *button, GtkDirectionType dir, gboolean active); void csd_wacom_osd_window_set_mode (CsdWacomOSDWindow *osd_window, gint group_id, gint mode); GtkWidget * csd_wacom_osd_window_new (CsdWacomDevice *pad, const gchar *message); #endif /* __CSD_WACOM_OSD_WINDOW_H */ cinnamon-settings-daemon-5.2.0/plugins/wacom/list-wacom.c0000664000175000017500000001735014144454032022364 0ustar fabiofabio/* * Copyright (C) 2011 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Author: Bastien Nocera * */ #include "config.h" #include #include "csd-wacom-device.h" static gboolean fake_devices = FALSE; static gboolean monitor_styli = FALSE; static gboolean option_debug = FALSE; static char * get_loc (GSettings *settings) { char *path, *schema, *ret; g_return_val_if_fail (G_IS_SETTINGS (settings), NULL); g_object_get (G_OBJECT (settings), "path", &path, "schema-id", &schema, NULL); ret = g_strdup_printf ("schema-id: %s (path: %s)", schema, path); g_free (schema); g_free (path); return ret; } static const char * stylus_type_to_string (CsdWacomStylusType type) { switch (type) { case WACOM_STYLUS_TYPE_UNKNOWN: return "Unknown"; case WACOM_STYLUS_TYPE_GENERAL: return "General"; case WACOM_STYLUS_TYPE_INKING: return "Inking"; case WACOM_STYLUS_TYPE_AIRBRUSH: return "Airbrush"; case WACOM_STYLUS_TYPE_CLASSIC: return "Classic"; case WACOM_STYLUS_TYPE_MARKER: return "Marker"; case WACOM_STYLUS_TYPE_STROKE: return "Stroke"; case WACOM_STYLUS_TYPE_PUCK: return "Puck"; default: g_assert_not_reached (); } return NULL; } static const char * button_type_to_string (CsdWacomTabletButtonType type) { switch (type) { case WACOM_TABLET_BUTTON_TYPE_NORMAL: return "normal"; case WACOM_TABLET_BUTTON_TYPE_STRIP: return "touch-strip"; case WACOM_TABLET_BUTTON_TYPE_RING: return "touch-ring"; case WACOM_TABLET_BUTTON_TYPE_HARDCODED: return "hard-coded"; default: g_assert_not_reached (); } } #define BOOL_AS_STR(x) (x ? "yes" : "no") static void print_stylus (CsdWacomStylus *stylus, gboolean is_current) { CsdWacomDevice *device; char *loc; device = csd_wacom_stylus_get_device (stylus); g_print ("\t%sStylus: '%s' (Type: %s, ID: 0x%x)\n", is_current ? "*** " : "", csd_wacom_stylus_get_name (stylus), stylus_type_to_string (csd_wacom_stylus_get_stylus_type (stylus)), csd_wacom_stylus_get_id (stylus)); loc = get_loc (csd_wacom_stylus_get_settings (stylus)); g_print ("\t\tSettings: %s\n", loc); g_free (loc); g_print ("\t\tIcon name: %s\n", csd_wacom_stylus_get_icon_name (stylus)); if (csd_wacom_device_get_device_type (device) == WACOM_TYPE_STYLUS) { int num_buttons; char *buttons; g_print ("\t\tHas Eraser: %s\n", BOOL_AS_STR(csd_wacom_stylus_get_has_eraser (stylus))); num_buttons = csd_wacom_stylus_get_num_buttons (stylus); if (num_buttons < 0) num_buttons = 2; if (num_buttons > 0) buttons = g_strdup_printf ("%d buttons", num_buttons); else buttons = g_strdup ("no button"); g_print ("\t\tButtons: %s\n", buttons); g_free (buttons); } } static void print_buttons (CsdWacomDevice *device) { GList *buttons, *l; buttons = csd_wacom_device_get_buttons (device); if (buttons == NULL) return; for (l = buttons; l != NULL; l = l->next) { CsdWacomTabletButton *button = l->data; g_print ("\tButton: %s (%s)\n", button->name, button->id); g_print ("\t\tType: %s\n", button_type_to_string (button->type)); if (button->group_id > 0) { g_print ("\t\tGroup: %d", button->group_id); if (button->idx >= 0) g_print (" Index: %d\n", button->idx); else g_print ("\n"); } if (button->settings) { char *loc; loc = get_loc (button->settings); g_print ("\t\tSettings: %s\n", loc); g_free (loc); } } g_list_free (buttons); } static void last_stylus_changed (CsdWacomDevice *device, GParamSpec *pspec, gpointer user_data) { CsdWacomStylus *stylus; g_object_get (device, "last-stylus", &stylus, NULL); g_print ("Stylus changed for device '%s'\n", csd_wacom_device_get_tool_name (device)); print_stylus (stylus, TRUE); } static void list_devices (GList *devices) { GList *l; for (l = devices; l ; l = l->next) { CsdWacomDevice *device; CsdWacomDeviceType type; char *loc; device = l->data; g_signal_connect (G_OBJECT (device), "notify::last-stylus", G_CALLBACK (last_stylus_changed), NULL); g_print ("Device '%s' (type: %s)\n", csd_wacom_device_get_name (device), csd_wacom_device_type_to_string (csd_wacom_device_get_device_type (device))); g_print ("\tReversible: %s\n", BOOL_AS_STR (csd_wacom_device_reversible (device))); g_print ("\tScreen Tablet: %s\n", BOOL_AS_STR (csd_wacom_device_is_screen_tablet (device))); g_print ("\tIntegrated Device: %s\n", BOOL_AS_STR (csd_wacom_device_is_isd (device))); g_print ("\tUnknown (fallback) device: %s\n", BOOL_AS_STR(csd_wacom_device_is_fallback (device))); loc = get_loc (csd_wacom_device_get_settings (device)); g_print ("\tGeneric settings: %s\n", loc); g_free (loc); type = csd_wacom_device_get_device_type (device); if (type == WACOM_TYPE_STYLUS || type == WACOM_TYPE_ERASER) { GList *styli, *j; CsdWacomStylus *current_stylus; g_object_get (device, "last-stylus", ¤t_stylus, NULL); styli = csd_wacom_device_list_styli (device); for (j = styli; j; j = j->next) { CsdWacomStylus *stylus; stylus = j->data; print_stylus (stylus, current_stylus == stylus); } g_list_free (styli); } print_buttons (device); if (monitor_styli == FALSE) g_object_unref (device); } g_list_free (devices); } static void list_actual_devices (void) { GdkDeviceManager *mgr; GList *list, *l, *devices; mgr = gdk_display_get_device_manager (gdk_display_get_default ()); list = gdk_device_manager_list_devices (mgr, GDK_DEVICE_TYPE_SLAVE); devices = NULL; for (l = list; l ; l = l->next) { CsdWacomDevice *device; device = csd_wacom_device_new (l->data); if (csd_wacom_device_get_device_type (device) == WACOM_TYPE_INVALID) { g_object_unref (device); continue; } devices = g_list_prepend (devices, device); } g_list_free (list); list_devices (devices); } static void list_fake_devices (void) { GList *devices; devices = csd_wacom_device_create_fake_cintiq (); list_devices (devices); devices = csd_wacom_device_create_fake_bt (); list_devices (devices); devices = csd_wacom_device_create_fake_x201 (); list_devices (devices); devices = csd_wacom_device_create_fake_intuos4 (); list_devices (devices); } int main (int argc, char **argv) { GError *error = NULL; GOptionContext *context; const GOptionEntry entries[] = { { "fake", 'f', 0, G_OPTION_ARG_NONE, &fake_devices, "Output fake devices", NULL }, { "monitor", 'm', 0, G_OPTION_ARG_NONE, &monitor_styli, "Monitor changing styli", NULL }, { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug, "Debug output", NULL }, { NULL } }; gtk_init (&argc, &argv); context = g_option_context_new ("- test parser functions"); g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) { g_print ("Option parsing failed: %s\n", error->message); g_option_context_free (context); return 1; } if (option_debug) g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); if (fake_devices == FALSE) list_actual_devices (); else list_fake_devices (); if (monitor_styli) gtk_main (); g_option_context_free (context); return 0; } cinnamon-settings-daemon-5.2.0/plugins/wacom/meson.build0000664000175000017500000000446414144454032022305 0ustar fabiofabioplugin_name = 'wacom' wacom_resources = gnome.compile_resources( 'csd-wacom-resources', 'wacom.gresource.xml', c_name: 'csd_wacom', ) wacom_common_sources = [ 'csd-wacom-device.c', ] list_wacom_sources = [ 'list-wacom.c', wacom_common_sources, ] wacom_sources = [ 'csd-wacom-manager.c', 'csd-wacom-osd-window.c', 'main.c', wacom_common_sources, wacom_resources, ] wacom_osd_sources = [ 'test-osd-window.c', 'csd-wacom-osd-window.c', wacom_common_sources, wacom_resources, ] wacom_deps = [ cinnamon_desktop, common_dep, csd_dep, gtk, gudev, libnotify, librsvg, math, wacom, xfixes, xorg_wacom, xtst, ] executable( 'csd-wacom', wacom_sources, include_directories: [include_dirs, common_inc, include_enums], dependencies: wacom_deps, c_args: [ '-DPLUGIN_NAME="@0@"'.format(plugin_name), ], install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-wacom') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-wacom') endif executable( 'csd-list-wacom', list_wacom_sources, include_directories: [include_dirs, common_inc, include_enums], dependencies: wacom_deps, install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-list-wacom') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-list-wacom') endif executable( 'csd-wacom-osd', wacom_osd_sources, include_directories: [include_dirs, common_inc, include_enums], dependencies: wacom_deps, install: true, install_dir: libexecdir, ) meson.add_install_script(ln_script, libexecdir, bindir, 'csd-wacom-osd') if libexecdir != pkglibdir meson.add_install_script(ln_script, libexecdir, pkglibdir, 'csd-wacom-osd') endif configure_file( input: 'cinnamon-settings-daemon-wacom.desktop.in', output: 'cinnamon-settings-daemon-wacom.desktop', configuration: desktop_conf, install_dir: autostartdir, ) configure_file( input: 'org.cinnamon.settings-daemon.plugins.wacom.policy.in', output: 'org.cinnamon.settings-daemon.plugins.wacom.policy', configuration: desktop_conf, install_dir: polkitdir, ) cinnamon-settings-daemon-5.2.0/plugins/wacom/cinnamon-settings-daemon-wacom.desktop.in0000664000175000017500000000033214144454032030136 0ustar fabiofabio[Desktop Entry] Type=Application Name=Cinnamon Settings Daemon - wacom Exec=csd-wacom OnlyShowIn=X-Cinnamon; NoDisplay=true X-GNOME-Autostart-Phase=Initialization X-GNOME-Autostart-Notify=true X-GNOME-AutoRestart=true cinnamon-settings-daemon-5.2.0/plugins/wacom/csd-wacom-manager.c0000664000175000017500000013123614144454032023572 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2010 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include "csd-enums.h" #include "csd-input-helper.h" #include "csd-keygrab.h" #include "cinnamon-settings-profile.h" #include "csd-wacom-manager.h" #include "csd-wacom-device.h" #include "csd-wacom-osd-window.h" #define CSD_WACOM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_WACOM_MANAGER, CsdWacomManagerPrivate)) #define KEY_ROTATION "rotation" #define KEY_TOUCH "touch" #define KEY_TPCBUTTON "tablet-pc-button" #define KEY_IS_ABSOLUTE "is-absolute" #define KEY_AREA "area" #define KEY_DISPLAY "display" #define KEY_KEEP_ASPECT "keep-aspect" #define KEY_KEEP_ROTATION "keep-rotation" /* Stylus and Eraser settings */ #define KEY_BUTTON_MAPPING "buttonmapping" #define KEY_PRESSURETHRESHOLD "pressurethreshold" #define KEY_PRESSURECURVE "pressurecurve" /* Button settings */ #define KEY_ACTION_TYPE "action-type" #define KEY_CUSTOM_ACTION "custom-action" #define KEY_CUSTOM_ELEVATOR_ACTION "custom-elevator-action" /* See "Wacom Pressure Threshold" */ #define DEFAULT_PRESSURE_THRESHOLD 27 struct CsdWacomManagerPrivate { guint start_idle_id; GdkDeviceManager *device_manager; guint device_added_id; guint device_removed_id; GHashTable *devices; /* key = GdkDevice, value = CsdWacomDevice */ GList *rr_screens; /* button capture */ GSList *screens; int opcode; /* Help OSD window */ GtkWidget *osd_window; }; static void csd_wacom_manager_class_init (CsdWacomManagerClass *klass); static void csd_wacom_manager_init (CsdWacomManager *wacom_manager); static void csd_wacom_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdWacomManager, csd_wacom_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static GObject * csd_wacom_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdWacomManager *wacom_manager; wacom_manager = CSD_WACOM_MANAGER (G_OBJECT_CLASS (csd_wacom_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (wacom_manager); } static void csd_wacom_manager_dispose (GObject *object) { G_OBJECT_CLASS (csd_wacom_manager_parent_class)->dispose (object); } static void csd_wacom_manager_class_init (CsdWacomManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_wacom_manager_constructor; object_class->dispose = csd_wacom_manager_dispose; object_class->finalize = csd_wacom_manager_finalize; g_type_class_add_private (klass, sizeof (CsdWacomManagerPrivate)); } static int get_device_id (CsdWacomDevice *device) { GdkDevice *gdk_device; int id; g_object_get (device, "gdk-device", &gdk_device, NULL); if (gdk_device == NULL) return -1; g_object_get (gdk_device, "device-id", &id, NULL); return id; } static XDevice * open_device (CsdWacomDevice *device) { XDevice *xdev; int id; id = get_device_id (device); if (id < 0) return NULL; gdk_x11_display_error_trap_push (gdk_display_get_default ()); xdev = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) || (xdev == NULL)) return NULL; return xdev; } static void wacom_set_property (CsdWacomDevice *device, PropertyHelper *property) { XDevice *xdev; xdev = open_device (device); device_set_property (xdev, csd_wacom_device_get_tool_name (device), property); xdevice_close (xdev); } static void set_rotation (CsdWacomDevice *device, CsdWacomRotation rotation) { gchar rot = rotation; PropertyHelper property = { .name = "Wacom Rotation", .nitems = 1, .format = 8, .type = XA_INTEGER, .data.c = &rot, }; wacom_set_property (device, &property); } static void set_pressurecurve (CsdWacomDevice *device, GVariant *value) { PropertyHelper property = { .name = "Wacom Pressurecurve", .nitems = 4, .type = XA_INTEGER, .format = 32, }; gsize nvalues; property.data.i = g_variant_get_fixed_array (value, &nvalues, sizeof (gint32)); if (nvalues != 4) { g_error ("Pressurecurve requires 4 values."); return; } wacom_set_property (device, &property); g_variant_unref (value); } /* Area handling. Each area is defined as top x/y, bottom x/y and limits the * usable area of the physical device to the given area (in device coords) */ static void set_area (CsdWacomDevice *device, GVariant *value) { PropertyHelper property = { .name = "Wacom Tablet Area", .nitems = 4, .type = XA_INTEGER, .format = 32, }; gsize nvalues; property.data.i = g_variant_get_fixed_array (value, &nvalues, sizeof (gint32)); if (nvalues != 4) { g_error ("Area configuration requires 4 values."); return; } wacom_set_property (device, &property); g_variant_unref (value); } /* Returns the rotation to apply a device relative to the current rotation of the output */ static CsdWacomRotation get_relative_rotation (CsdWacomRotation device_rotation, CsdWacomRotation output_rotation) { CsdWacomRotation rotations[] = { CSD_WACOM_ROTATION_HALF, CSD_WACOM_ROTATION_CW, CSD_WACOM_ROTATION_NONE, CSD_WACOM_ROTATION_CCW }; guint i; if (device_rotation == output_rotation) return CSD_WACOM_ROTATION_NONE; if (output_rotation == CSD_WACOM_ROTATION_NONE) return device_rotation; for (i = 0; i < G_N_ELEMENTS (rotations); i++){ if (device_rotation == rotations[i]) break; } if (output_rotation == CSD_WACOM_ROTATION_HALF) return rotations[(i + G_N_ELEMENTS (rotations) - 2) % G_N_ELEMENTS (rotations)]; if (output_rotation == CSD_WACOM_ROTATION_CW) return rotations[(i + G_N_ELEMENTS (rotations) - 1) % G_N_ELEMENTS (rotations)]; if (output_rotation == CSD_WACOM_ROTATION_CCW) return rotations[(i + 1) % G_N_ELEMENTS (rotations)]; /* fallback */ return CSD_WACOM_ROTATION_NONE; } static void set_display (CsdWacomDevice *device, GVariant *value) { CsdWacomRotation device_rotation; CsdWacomRotation output_rotation; GSettings *settings; float matrix[NUM_ELEMS_MATRIX]; PropertyHelper property = { .name = "Coordinate Transformation Matrix", .nitems = NUM_ELEMS_MATRIX, .format = 32, .type = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "FLOAT", True), }; csd_wacom_device_get_display_matrix (device, matrix); property.data.i = (gint*)(&matrix); g_debug ("Applying matrix to device..."); wacom_set_property (device, &property); /* Apply display rotation to device */ settings = csd_wacom_device_get_settings (device); if (g_settings_get_boolean (settings, KEY_KEEP_ROTATION)) { device_rotation = g_settings_get_enum (settings, KEY_ROTATION); output_rotation = csd_wacom_device_get_display_rotation (device); set_rotation (device, get_relative_rotation (device_rotation, output_rotation)); } g_variant_unref (value); } static void set_absolute (CsdWacomDevice *device, gint is_absolute) { XDevice *xdev; xdev = open_device (device); gdk_x11_display_error_trap_push (gdk_display_get_default ()); XSetDeviceMode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev, is_absolute ? Absolute : Relative); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_error ("Failed to set mode \"%s\" for \"%s\".", is_absolute ? "Absolute" : "Relative", csd_wacom_device_get_tool_name (device)); xdevice_close (xdev); } static void compute_aspect_area (gint monitor, gint *area, CsdWacomRotation rotation) { gint width = area[2] - area[0]; gint height = area[3] - area[1]; GdkScreen *screen; GdkRectangle monitor_geometry; float aspect; screen = gdk_screen_get_default (); if (monitor < 0) { monitor_geometry.width = gdk_screen_get_width (screen); monitor_geometry.height = gdk_screen_get_height (screen); } else { gdk_screen_get_monitor_geometry (screen, monitor, &monitor_geometry); } if (rotation == CSD_WACOM_ROTATION_CW || rotation == CSD_WACOM_ROTATION_CCW) aspect = (float) monitor_geometry.height / (float) monitor_geometry.width; else aspect = (float) monitor_geometry.width / (float) monitor_geometry.height; if ((float) width / (float) height > aspect) width = height * aspect; else height = width / aspect; switch (rotation) { case CSD_WACOM_ROTATION_NONE: area[2] = area[0] + width; area[3] = area[1] + height; break; case CSD_WACOM_ROTATION_CW: area[0] = area[2] - width; area[3] = area[1] + height; break; case CSD_WACOM_ROTATION_HALF: area[0] = area[2] - width; area[1] = area[3] - height; break; case CSD_WACOM_ROTATION_CCW: area[2] = area[0] + width; area[1] = area[3] - height; break; default: break; } } static void set_keep_aspect (CsdWacomDevice *device, gboolean keep_aspect) { GVariant *values[4], *variant; guint i; gint *area; gint monitor = CSD_WACOM_SET_ALL_MONITORS; CsdWacomRotation rotation; GSettings *settings; settings = csd_wacom_device_get_settings (device); /* Set area to default values for the device */ for (i = 0; i < G_N_ELEMENTS (values); i++) values[i] = g_variant_new_int32 (-1); variant = g_variant_new_array (G_VARIANT_TYPE_INT32, values, G_N_ELEMENTS (values)); /* If keep_aspect is not set, just reset the area to default and let * gsettings notification call set_area() for us... */ if (!keep_aspect) { g_settings_set_value (settings, KEY_AREA, variant); return; } /* Reset the device area to get the default area */ set_area (device, variant); /* Get current rotation */ rotation = g_settings_get_enum (settings, KEY_ROTATION); /* Get current area */ area = csd_wacom_device_get_area (device); if (!area) { g_warning("Device area not available.\n"); return; } /* Get corresponding monitor size */ monitor = csd_wacom_device_get_display_monitor (device); /* Adjust area to match the monitor aspect ratio */ g_debug ("Initial device area: (%d,%d) (%d,%d)", area[0], area[1], area[2], area[3]); compute_aspect_area (monitor, area, rotation); g_debug ("Adjusted device area: (%d,%d) (%d,%d)", area[0], area[1], area[2], area[3]); for (i = 0; i < G_N_ELEMENTS (values); i++) values[i] = g_variant_new_int32 (area[i]); variant = g_variant_new_array (G_VARIANT_TYPE_INT32, values, G_N_ELEMENTS (values)); g_settings_set_value (settings, KEY_AREA, variant); g_free (area); } static void set_device_buttonmap (CsdWacomDevice *device, GVariant *value) { XDevice *xdev; gsize nmap; const gint *intmap; unsigned char *map; int i, j, rc; xdev = open_device (device); intmap = g_variant_get_fixed_array (value, &nmap, sizeof (gint32)); map = g_new0 (unsigned char, nmap); for (i = 0; i < nmap; i++) map[i] = intmap[i]; g_variant_unref (value); gdk_x11_display_error_trap_push (gdk_display_get_default ()); /* X refuses to change the mapping while buttons are engaged, * so if this is the case we'll retry a few times */ for (j = 0; j < 20 && (rc = XSetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev, map, nmap)) == MappingBusy; ++j) { g_usleep (300); } if ((gdk_x11_display_error_trap_pop (gdk_display_get_default ()) && rc != MappingSuccess) || rc != MappingSuccess) g_warning ("Error in setting button mapping for \"%s\"", csd_wacom_device_get_tool_name (device)); g_free (map); xdevice_close (xdev); } static void set_touch (CsdWacomDevice *device, gboolean touch) { gchar data = touch; PropertyHelper property = { .name = "Wacom Enable Touch", .nitems = 1, .format = 8, .type = XA_INTEGER, .data.c = &data, }; wacom_set_property (device, &property); } static void set_tpcbutton (CsdWacomDevice *device, gboolean tpcbutton) { /* Wacom's TPCButton option which this setting emulates is to enable * Tablet PC stylus behaviour when on. The property "Hover Click" * works the other way round, i.e. if Hover Click is enabled this * is the equivalent of TPC behaviour disabled. */ gchar data = tpcbutton ? 0 : 1; PropertyHelper property = { .name = "Wacom Hover Click", .nitems = 1, .format = 8, .type = XA_INTEGER, .data.c = &data, }; wacom_set_property (device, &property); } static void set_pressurethreshold (CsdWacomDevice *device, gint threshold) { PropertyHelper property = { .name = "Wacom Pressure Threshold", .nitems = 1, .format = 32, .type = XA_INTEGER, .data.i = &threshold, }; wacom_set_property (device, &property); } static void apply_stylus_settings (CsdWacomDevice *device) { GSettings *stylus_settings; CsdWacomStylus *stylus; int threshold; g_object_get (device, "last-stylus", &stylus, NULL); if (stylus == NULL) { g_warning ("Last stylus is not set"); return; } g_debug ("Applying setting for stylus '%s' on device '%s'", csd_wacom_stylus_get_name (stylus), csd_wacom_device_get_name (device)); stylus_settings = csd_wacom_stylus_get_settings (stylus); set_pressurecurve (device, g_settings_get_value (stylus_settings, KEY_PRESSURECURVE)); set_device_buttonmap (device, g_settings_get_value (stylus_settings, KEY_BUTTON_MAPPING)); threshold = g_settings_get_int (stylus_settings, KEY_PRESSURETHRESHOLD); if (threshold == -1) threshold = DEFAULT_PRESSURE_THRESHOLD; set_pressurethreshold (device, threshold); } struct DefaultButtons { const char *button; int num; }; struct DefaultButtons def_touchrings_buttons[] = { /* Touchrings */ { "AbsWheelUp", 90 }, { "AbsWheelDown", 91 }, { "RelWheelUp", 90 }, { "RelWheelDown", 91 }, { "AbsWheel2Up", 92 }, { "AbsWheel2Down", 93 }, { NULL, 0 } }; struct DefaultButtons def_touchstrip_buttons[] = { /* Touchstrips */ { "StripLeftUp", 94 }, { "StripLeftDown", 95 }, { "StripRightUp", 96 }, { "StripRightDown", 97 }, { NULL, 0 } }; static void reset_touch_buttons (XDevice *xdev, struct DefaultButtons *buttons, const char *device_property) { Atom actions[6]; Atom action_prop; guint i; /* Create a device property with the action for button i */ for (i = 0; buttons[i].button != NULL; i++) { char *propname; glong action[2]; /* press + release */ Atom prop; int mapped_button = buttons[i].num; action[0] = AC_BUTTON | AC_KEYBTNPRESS | mapped_button; action[1] = AC_BUTTON | mapped_button; propname = g_strdup_printf ("Button %s action", buttons[i].button); prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), propname, False); g_free (propname); XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev, prop, XA_INTEGER, 32, PropModeReplace, (const guchar *) &action, 2); /* prop now contains press + release for the mapped button */ actions[i] = prop; } /* Now set the actual action property to contain references to the various * actions */ action_prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_property, True); XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev, action_prop, XA_ATOM, 32, PropModeReplace, (const guchar *) actions, i); } static void reset_pad_buttons (CsdWacomDevice *device) { XDevice *xdev; int nmap; unsigned char *map; int i, j, rc; GList *buttons, *l; /* Normal buttons */ xdev = open_device (device); gdk_x11_display_error_trap_push (gdk_display_get_default ()); nmap = 256; map = g_new0 (unsigned char, nmap); for (i = 0; i < nmap && i < sizeof (map); i++) map[i] = i + 1; /* X refuses to change the mapping while buttons are engaged, * so if this is the case we'll retry a few times */ for (j = 0; j < 20 && (rc = XSetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev, map, nmap)) == MappingBusy; ++j) { g_usleep (300); } if ((gdk_x11_display_error_trap_pop (gdk_display_get_default ()) && rc != MappingSuccess) || rc != MappingSuccess) g_warning ("Error in resetting button mapping for \"%s\" (rc=%d)", csd_wacom_device_get_tool_name (device), rc); g_free (map); gdk_x11_display_error_trap_push (gdk_display_get_default ()); reset_touch_buttons (xdev, def_touchrings_buttons, "Wacom Wheel Buttons"); reset_touch_buttons (xdev, def_touchstrip_buttons, "Wacom Strip Buttons"); gdk_x11_display_error_trap_pop_ignored (gdk_display_get_default ()); xdevice_close (xdev); /* Reset all the LEDs */ buttons = csd_wacom_device_get_buttons (device); for (l = buttons; l != NULL; l = l->next) { CsdWacomTabletButton *button = l->data; } g_list_free (buttons); } static void set_wacom_settings (CsdWacomManager *manager, CsdWacomDevice *device) { CsdWacomDeviceType type; GSettings *settings; g_debug ("Applying settings for device '%s' (type: %s)", csd_wacom_device_get_tool_name (device), csd_wacom_device_type_to_string (csd_wacom_device_get_device_type (device))); settings = csd_wacom_device_get_settings (device); set_rotation (device, g_settings_get_enum (settings, KEY_ROTATION)); set_touch (device, g_settings_get_boolean (settings, KEY_TOUCH)); type = csd_wacom_device_get_device_type (device); if (type == WACOM_TYPE_TOUCH && csd_wacom_device_is_screen_tablet (device) == FALSE) { set_absolute (device, FALSE); return; } if (type == WACOM_TYPE_CURSOR) { GVariant *values[4], *variant; guint i; set_absolute (device, FALSE); for (i = 0; i < G_N_ELEMENTS (values); i++) values[i] = g_variant_new_int32 (-1); variant = g_variant_new_array (G_VARIANT_TYPE_INT32, values, G_N_ELEMENTS (values)); set_area (device, variant); return; } if (type == WACOM_TYPE_PAD) { int id; id = get_device_id (device); reset_pad_buttons (device); grab_button (id, TRUE, manager->priv->screens); return; } if (type == WACOM_TYPE_STYLUS) set_tpcbutton (device, g_settings_get_boolean (settings, KEY_TPCBUTTON)); set_absolute (device, g_settings_get_boolean (settings, KEY_IS_ABSOLUTE)); /* Ignore touch devices as they do not share the same range of values for area */ if (type != WACOM_TYPE_TOUCH) { if (csd_wacom_device_is_screen_tablet (device) == FALSE) set_keep_aspect (device, g_settings_get_boolean (settings, KEY_KEEP_ASPECT)); set_area (device, g_settings_get_value (settings, KEY_AREA)); } set_display (device, g_settings_get_value (settings, KEY_DISPLAY)); /* only pen and eraser have pressure threshold and curve settings */ if (type == WACOM_TYPE_STYLUS || type == WACOM_TYPE_ERASER) { apply_stylus_settings (device); } } static void wacom_settings_changed (GSettings *settings, gchar *key, CsdWacomDevice *device) { CsdWacomDeviceType type; type = csd_wacom_device_get_device_type (device); if (g_str_equal (key, KEY_ROTATION)) { if (type != WACOM_TYPE_PAD) set_rotation (device, g_settings_get_enum (settings, key)); } else if (g_str_equal (key, KEY_TOUCH)) { set_touch (device, g_settings_get_boolean (settings, key)); } else if (g_str_equal (key, KEY_TPCBUTTON)) { set_tpcbutton (device, g_settings_get_boolean (settings, key)); } else if (g_str_equal (key, KEY_IS_ABSOLUTE)) { if (type != WACOM_TYPE_CURSOR && type != WACOM_TYPE_PAD && type != WACOM_TYPE_TOUCH) set_absolute (device, g_settings_get_boolean (settings, key)); } else if (g_str_equal (key, KEY_AREA)) { if (type != WACOM_TYPE_CURSOR && type != WACOM_TYPE_PAD && type != WACOM_TYPE_TOUCH) set_area (device, g_settings_get_value (settings, key)); } else if (g_str_equal (key, KEY_DISPLAY)) { if (type != WACOM_TYPE_CURSOR && type != WACOM_TYPE_PAD) set_display (device, g_settings_get_value (settings, key)); } else if (g_str_equal (key, KEY_KEEP_ASPECT)) { if (type != WACOM_TYPE_CURSOR && type != WACOM_TYPE_PAD && type != WACOM_TYPE_TOUCH && !csd_wacom_device_is_screen_tablet (device)) set_keep_aspect (device, g_settings_get_boolean (settings, key)); } else { g_warning ("Unhandled tablet-wide setting '%s' changed", key); } } static void stylus_settings_changed (GSettings *settings, gchar *key, CsdWacomStylus *stylus) { CsdWacomDevice *device; CsdWacomStylus *last_stylus; device = csd_wacom_stylus_get_device (stylus); g_object_get (device, "last-stylus", &last_stylus, NULL); if (last_stylus != stylus) { g_debug ("Not applying changed settings because '%s' is the current stylus, not '%s'", last_stylus ? csd_wacom_stylus_get_name (last_stylus) : "NONE", csd_wacom_stylus_get_name (stylus)); return; } if (g_str_equal (key, KEY_PRESSURECURVE)) { set_pressurecurve (device, g_settings_get_value (settings, key)); } else if (g_str_equal (key, KEY_PRESSURETHRESHOLD)) { int threshold; threshold = g_settings_get_int (settings, KEY_PRESSURETHRESHOLD); if (threshold == -1) threshold = DEFAULT_PRESSURE_THRESHOLD; set_pressurethreshold (device, threshold); } else if (g_str_equal (key, KEY_BUTTON_MAPPING)) { set_device_buttonmap (device, g_settings_get_value (settings, key)); } else { g_warning ("Unhandled stylus setting '%s' changed", key); } } static void last_stylus_changed (CsdWacomDevice *device, GParamSpec *pspec, CsdWacomManager *manager) { g_debug ("Stylus for device '%s' changed, applying settings", csd_wacom_device_get_name (device)); apply_stylus_settings (device); } static void osd_window_destroy (CsdWacomManager *manager) { g_return_if_fail (manager != NULL); g_clear_pointer (&manager->priv->osd_window, gtk_widget_destroy); } static gboolean osd_window_on_key_release_event (GtkWidget *widget, GdkEventKey *event, CsdWacomManager *manager) { if (event->type != GDK_KEY_RELEASE) return FALSE; if (event->keyval != GDK_KEY_Escape) return FALSE; osd_window_destroy (manager); return FALSE; } static gboolean osd_window_on_focus_out_event (GtkWidget *widget, GdkEvent *event, CsdWacomManager *manager) { /* If the OSD window loses focus, hide it */ osd_window_destroy (manager); return FALSE; } static gboolean osd_window_toggle_visibility (CsdWacomManager *manager, CsdWacomDevice *device) { GtkWidget *widget; const gchar *layout_path; if (manager->priv->osd_window) { osd_window_destroy (manager); return FALSE; } layout_path = csd_wacom_device_get_layout_path (device); if (layout_path == NULL) { g_warning ("Cannot display the on-screen help window as the tablet " "definition for %s is missing the layout\n" "Please consider contributing the layout for your " "tablet to libwacom at linuxwacom-devel@lists.sourceforge.net\n", csd_wacom_device_get_name (device)); return FALSE; } if (g_file_test (layout_path, G_FILE_TEST_EXISTS) == FALSE) { g_warning ("Cannot display the on-screen help window as the " "layout file %s cannot be found on disk\n" "Please check your libwacom installation\n", layout_path); return FALSE; } widget = csd_wacom_osd_window_new (device, NULL); /* Connect some signals to the OSD window */ g_signal_connect (widget, "key-release-event", G_CALLBACK(osd_window_on_key_release_event), manager); g_signal_connect (widget, "focus-out-event", G_CALLBACK(osd_window_on_focus_out_event), manager); g_object_add_weak_pointer (G_OBJECT (widget), (gpointer *) &manager->priv->osd_window); gtk_window_present (GTK_WINDOW(widget)); manager->priv->osd_window = widget; return TRUE; } static gboolean osd_window_update_viewable (CsdWacomManager *manager, CsdWacomTabletButton *button, GtkDirectionType dir, XIEvent *xiev) { if (manager->priv->osd_window == NULL) return FALSE; csd_wacom_osd_window_set_active (CSD_WACOM_OSD_WINDOW (manager->priv->osd_window), button, dir, xiev->evtype == XI_ButtonPress); return TRUE; } static void device_added_cb (GdkDeviceManager *device_manager, GdkDevice *gdk_device, CsdWacomManager *manager) { CsdWacomDevice *device; GSettings *settings; device = csd_wacom_device_new (gdk_device); if (csd_wacom_device_get_device_type (device) == WACOM_TYPE_INVALID) { g_object_unref (device); return; } g_debug ("Adding device '%s' (type: '%s') to known devices list", csd_wacom_device_get_tool_name (device), csd_wacom_device_type_to_string (csd_wacom_device_get_device_type (device))); g_hash_table_insert (manager->priv->devices, (gpointer) gdk_device, device); settings = csd_wacom_device_get_settings (device); g_signal_connect (G_OBJECT (settings), "changed", G_CALLBACK (wacom_settings_changed), device); if (csd_wacom_device_get_device_type (device) == WACOM_TYPE_STYLUS || csd_wacom_device_get_device_type (device) == WACOM_TYPE_ERASER) { GList *styli, *l; styli = csd_wacom_device_list_styli (device); for (l = styli ; l ; l = l->next) { settings = csd_wacom_stylus_get_settings (l->data); g_signal_connect (G_OBJECT (settings), "changed", G_CALLBACK (stylus_settings_changed), l->data); } g_list_free (styli); g_signal_connect (G_OBJECT (device), "notify::last-stylus", G_CALLBACK (last_stylus_changed), manager); } set_wacom_settings (manager, device); } static void device_removed_cb (GdkDeviceManager *device_manager, GdkDevice *gdk_device, CsdWacomManager *manager) { g_debug ("Removing device '%s' from known devices list", gdk_device_get_name (gdk_device)); g_hash_table_remove (manager->priv->devices, gdk_device); /* Enable this chunk of code if you want to valgrind * test-wacom. It will exit when there are no Wacom devices left */ #if 0 if (g_hash_table_size (manager->priv->devices) == 0) gtk_main_quit (); #endif } static CsdWacomDevice * device_id_to_device (CsdWacomManager *manager, int deviceid) { GList *devices, *l; CsdWacomDevice *ret; ret = NULL; devices = g_hash_table_get_keys (manager->priv->devices); for (l = devices; l != NULL; l = l->next) { GdkDevice *device = l->data; int id; g_object_get (device, "device-id", &id, NULL); if (id == deviceid) { ret = g_hash_table_lookup (manager->priv->devices, device); break; } } g_list_free (devices); return ret; } struct { guint mask; KeySym keysym; } mods_keysyms[] = { { GDK_MOD1_MASK, XK_Alt_L }, { GDK_SHIFT_MASK, XK_Shift_L }, { GDK_CONTROL_MASK, XK_Control_L }, }; static void send_modifiers (Display *display, guint mask, gboolean is_press) { guint i; if (mask == 0) return; for (i = 0; i < G_N_ELEMENTS(mods_keysyms); i++) { if (mask & mods_keysyms[i].mask) { guint keycode; keycode = XKeysymToKeycode (display, mods_keysyms[i].keysym); XTestFakeKeyEvent (display, keycode, is_press ? True : False, 0); } } } static char * get_elevator_shortcut_string (GSettings *settings, GtkDirectionType dir) { char **strv, *str; strv = g_settings_get_strv (settings, KEY_CUSTOM_ELEVATOR_ACTION); if (strv == NULL) return NULL; if (g_strv_length (strv) >= 1 && dir == GTK_DIR_UP) str = g_strdup (strv[0]); else if (g_strv_length (strv) >= 2 && dir == GTK_DIR_DOWN) str = g_strdup (strv[1]); else str = NULL; g_strfreev (strv); return str; } static void generate_key (CsdWacomTabletButton *wbutton, int group, Display *display, GtkDirectionType dir, gboolean is_press) { char *str; guint keyval; guint *keycodes; guint keycode; guint mods; GdkKeymapKey *keys; int n_keys; guint i; if (wbutton->type == WACOM_TABLET_BUTTON_TYPE_STRIP || wbutton->type == WACOM_TABLET_BUTTON_TYPE_RING) str = get_elevator_shortcut_string (wbutton->settings, dir); else str = g_settings_get_string (wbutton->settings, KEY_CUSTOM_ACTION); if (str == NULL) return; gtk_accelerator_parse_with_keycode (str, &keyval, &keycodes, &mods); if (keycodes == NULL) { g_warning ("Failed to find a keycode for shortcut '%s'", str); g_free (str); return; } g_free (keycodes); /* Now look for our own keycode, in the group as us */ if (!gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), keyval, &keys, &n_keys)) { g_warning ("Failed to find a keycode for keyval '%s' (0x%x)", gdk_keyval_name (keyval), keyval); g_free (str); return; } keycode = 0; for (i = 0; i < n_keys; i++) { if (keys[i].group != group) continue; if (keys[i].level > 0) continue; keycode = keys[i].keycode; } /* Couldn't find it in the current group? Look in group 0 */ if (keycode == 0) { for (i = 0; i < n_keys; i++) { if (keys[i].group > 0) continue; keycode = keys[i].keycode; } } g_free (keys); if (keycode == 0) { g_warning ("Not emitting '%s' (keyval: %d, keycode: %d mods: 0x%x), invalid keycode", str, keyval, keycode, mods); g_free (str); return; } else { g_debug ("Emitting '%s' (keyval: %d, keycode: %d mods: 0x%x)", str, keyval, keycode, mods); } /* And send out the keys! */ gdk_x11_display_error_trap_push (gdk_display_get_default ()); if (is_press) send_modifiers (display, mods, TRUE); XTestFakeKeyEvent (display, keycode, is_press ? True : False, 0); if (is_press == FALSE) send_modifiers (display, mods, FALSE); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ())) g_warning ("Failed to generate fake key event '%s'", str); g_free (str); } static void switch_monitor (CsdWacomDevice *device) { gint current_monitor, n_monitors; /* We don't; do that for screen tablets, sorry... */ if (csd_wacom_device_is_screen_tablet (device)) return; n_monitors = gdk_screen_get_n_monitors (gdk_screen_get_default ()); /* There's no point in switching if there just one monitor */ if (n_monitors < 2) return; current_monitor = csd_wacom_device_get_display_monitor (device); /* Select next monitor */ current_monitor++; if (current_monitor >= n_monitors) current_monitor = CSD_WACOM_SET_ALL_MONITORS; csd_wacom_device_set_display (device, current_monitor); } static const char* get_direction_name (CsdWacomTabletButtonType type, GtkDirectionType dir) { if (type == WACOM_TABLET_BUTTON_TYPE_RING) return (dir == GTK_DIR_UP ? " 'CCW'" : " 'CW'"); if (type == WACOM_TABLET_BUTTON_TYPE_STRIP) return (dir == GTK_DIR_UP ? " 'up'" : " 'down'"); return ""; } static GdkFilterReturn filter_button_events (XEvent *xevent, GdkEvent *event, CsdWacomManager *manager) { XIEvent *xiev; XIDeviceEvent *xev; XGenericEventCookie *cookie; guint deviceid; CsdWacomDevice *device; int button; CsdWacomTabletButton *wbutton; GtkDirectionType dir; gboolean emulate; /* verify we have a key event */ if (xevent->type != GenericEvent) return GDK_FILTER_CONTINUE; cookie = &xevent->xcookie; if (cookie->extension != manager->priv->opcode) return GDK_FILTER_CONTINUE; xiev = (XIEvent *) xevent->xcookie.data; if (xiev->evtype != XI_ButtonRelease && xiev->evtype != XI_ButtonPress) return GDK_FILTER_CONTINUE; xev = (XIDeviceEvent *) xiev; deviceid = xev->sourceid; device = device_id_to_device (manager, deviceid); if (csd_wacom_device_get_device_type (device) != WACOM_TYPE_PAD) return GDK_FILTER_CONTINUE; if ((manager->priv->osd_window != NULL) && (device != csd_wacom_osd_window_get_device (CSD_WACOM_OSD_WINDOW(manager->priv->osd_window)))) /* This is a button event from another device while showing OSD window */ osd_window_destroy (manager); button = xev->detail; wbutton = csd_wacom_device_get_button (device, button, &dir); if (wbutton == NULL) { g_warning ("Could not find matching button for '%d' on '%s'", button, csd_wacom_device_get_name (device)); return GDK_FILTER_CONTINUE; } g_debug ("Received event button %s '%s'%s ('%d') on device '%s' ('%d')", xiev->evtype == XI_ButtonPress ? "press" : "release", wbutton->id, get_direction_name (wbutton->type, dir), button, csd_wacom_device_get_name (device), deviceid); if (wbutton->type == WACOM_TABLET_BUTTON_TYPE_HARDCODED) { int new_mode; /* We switch modes on key press */ if (xiev->evtype == XI_ButtonRelease) { osd_window_update_viewable (manager, wbutton, dir, xiev); return GDK_FILTER_REMOVE; } new_mode = csd_wacom_device_set_next_mode (device, wbutton); if (manager->priv->osd_window != NULL) { csd_wacom_osd_window_set_mode (CSD_WACOM_OSD_WINDOW(manager->priv->osd_window), wbutton->group_id, new_mode); osd_window_update_viewable (manager, wbutton, dir, xiev); } return GDK_FILTER_REMOVE; } /* Update OSD window if shown */ emulate = osd_window_update_viewable (manager, wbutton, dir, xiev); /* Nothing to do */ if (g_settings_get_enum (wbutton->settings, KEY_ACTION_TYPE) == CSD_WACOM_ACTION_TYPE_NONE) return GDK_FILTER_REMOVE; /* Show OSD window when requested */ if (g_settings_get_enum (wbutton->settings, KEY_ACTION_TYPE) == CSD_WACOM_ACTION_TYPE_HELP) { if (xiev->evtype == XI_ButtonRelease) osd_window_toggle_visibility (manager, device); return GDK_FILTER_REMOVE; } if (emulate) return GDK_FILTER_REMOVE; /* Switch monitor */ if (g_settings_get_enum (wbutton->settings, KEY_ACTION_TYPE) == CSD_WACOM_ACTION_TYPE_SWITCH_MONITOR) { if (xiev->evtype == XI_ButtonRelease) switch_monitor (device); return GDK_FILTER_REMOVE; } /* Send a key combination out */ generate_key (wbutton, xev->group.effective, xev->display, dir, xiev->evtype == XI_ButtonPress ? True : False); return GDK_FILTER_REMOVE; } static void set_devicepresence_handler (CsdWacomManager *manager) { GdkDeviceManager *device_manager; device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); if (device_manager == NULL) return; manager->priv->device_added_id = g_signal_connect (G_OBJECT (device_manager), "device-added", G_CALLBACK (device_added_cb), manager); manager->priv->device_removed_id = g_signal_connect (G_OBJECT (device_manager), "device-removed", G_CALLBACK (device_removed_cb), manager); manager->priv->device_manager = device_manager; } static void csd_wacom_manager_init (CsdWacomManager *manager) { manager->priv = CSD_WACOM_MANAGER_GET_PRIVATE (manager); } static gboolean csd_wacom_manager_idle_cb (CsdWacomManager *manager) { GList *devices, *l; GSList *ls; cinnamon_settings_profile_start (NULL); manager->priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); set_devicepresence_handler (manager); devices = gdk_device_manager_list_devices (manager->priv->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l ; l = l->next) device_added_cb (manager->priv->device_manager, l->data, manager); g_list_free (devices); /* Start filtering the button events */ for (ls = manager->priv->screens; ls != NULL; ls = ls->next) { gdk_window_add_filter (gdk_screen_get_root_window (ls->data), (GdkFilterFunc) filter_button_events, manager); } cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } /* * The monitors-changed signal is emitted when the number, size or * position of the monitors attached to the screen change. */ static void on_screen_changed_cb (GnomeRRScreen *rr_screen, CsdWacomManager *manager) { GList *devices, *l; /* * A ::changed signal may be received at startup before * the devices get added, in this case simply ignore the * notification */ if (manager->priv->devices == NULL) return; g_debug ("Screen configuration changed"); devices = g_hash_table_get_values (manager->priv->devices); for (l = devices; l != NULL; l = l->next) { CsdWacomDevice *device = l->data; CsdWacomDeviceType type; GSettings *settings; type = csd_wacom_device_get_device_type (device); if (type == WACOM_TYPE_CURSOR || type == WACOM_TYPE_PAD) continue; settings = csd_wacom_device_get_settings (device); /* Ignore touch devices as they do not share the same range of values for area */ if (type != WACOM_TYPE_TOUCH) { if (csd_wacom_device_is_screen_tablet (device) == FALSE) set_keep_aspect (device, g_settings_get_boolean (settings, KEY_KEEP_ASPECT)); set_area (device, g_settings_get_value (settings, KEY_AREA)); } set_display (device, g_settings_get_value (settings, KEY_DISPLAY)); } g_list_free (devices); } static void init_screens (CsdWacomManager *manager) { GdkDisplay *display; int i; display = gdk_display_get_default (); for (i = 0; i < gdk_display_get_n_screens (display); i++) { GError *error = NULL; GdkScreen *screen; GnomeRRScreen *rr_screen; screen = gdk_display_get_screen (display, i); if (screen == NULL) { continue; } manager->priv->screens = g_slist_append (manager->priv->screens, screen); /* * We also keep a list of GnomeRRScreen to monitor changes such as rotation * which are not reported by Gdk's "monitors-changed" callback */ rr_screen = gnome_rr_screen_new (screen, &error); if (rr_screen == NULL) { g_warning ("Failed to create GnomeRRScreen: %s", error->message); g_error_free (error); continue; } manager->priv->rr_screens = g_list_prepend (manager->priv->rr_screens, rr_screen); g_signal_connect (rr_screen, "changed", G_CALLBACK (on_screen_changed_cb), manager); } } gboolean csd_wacom_manager_start (CsdWacomManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); if (supports_xinput2_devices (&manager->priv->opcode) == FALSE) { g_debug ("No Xinput2 support, disabling plugin"); return TRUE; } if (supports_xtest () == FALSE) { g_debug ("No XTest extension support, disabling plugin"); return TRUE; } init_screens (manager); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) csd_wacom_manager_idle_cb, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_wacom_manager_stop (CsdWacomManager *manager) { CsdWacomManagerPrivate *p = manager->priv; GSList *ls; GList *l; g_debug ("Stopping wacom manager"); if (p->device_manager != NULL) { GList *devices; g_signal_handler_disconnect (p->device_manager, p->device_added_id); g_signal_handler_disconnect (p->device_manager, p->device_removed_id); devices = gdk_device_manager_list_devices (p->device_manager, GDK_DEVICE_TYPE_SLAVE); for (l = devices; l != NULL; l = l->next) { CsdWacomDeviceType type; type = csd_wacom_device_get_device_type (l->data); if (type == WACOM_TYPE_PAD) { int id; id = get_device_id (l->data); grab_button (id, FALSE, manager->priv->screens); } } g_list_free (devices); p->device_manager = NULL; } for (ls = p->screens; ls != NULL; ls = ls->next) { gdk_window_remove_filter (gdk_screen_get_root_window (ls->data), (GdkFilterFunc) filter_button_events, manager); } for (l = p->rr_screens; l != NULL; l = l->next) g_signal_handlers_disconnect_by_func (l->data, on_screen_changed_cb, manager); g_clear_pointer (&p->osd_window, gtk_widget_destroy); } static void csd_wacom_manager_finalize (GObject *object) { CsdWacomManager *wacom_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_WACOM_MANAGER (object)); wacom_manager = CSD_WACOM_MANAGER (object); g_return_if_fail (wacom_manager->priv != NULL); if (wacom_manager->priv->devices) { g_hash_table_destroy (wacom_manager->priv->devices); wacom_manager->priv->devices = NULL; } if (wacom_manager->priv->screens != NULL) { g_slist_free (wacom_manager->priv->screens); wacom_manager->priv->screens = NULL; } if (wacom_manager->priv->rr_screens != NULL) { g_list_free_full (wacom_manager->priv->rr_screens, g_object_unref); wacom_manager->priv->rr_screens = NULL; } if (wacom_manager->priv->start_idle_id != 0) { g_source_remove (wacom_manager->priv->start_idle_id); wacom_manager->priv->start_idle_id = 0; } G_OBJECT_CLASS (csd_wacom_manager_parent_class)->finalize (object); } CsdWacomManager * csd_wacom_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_WACOM_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_WACOM_MANAGER (manager_object); } cinnamon-settings-daemon-5.2.0/plugins/wacom/main.c0000664000175000017500000000100514144454032021217 0ustar fabiofabio#define NEW csd_wacom_manager_new #define START csd_wacom_manager_start #define STOP csd_wacom_manager_stop #define MANAGER CsdWacomManager // Setting this to TRUE makes the plugin register // with CSM before starting. // Setting this to FALSE makes CSM wait for the plugin to be started // before initializing the next phase. #define REGISTER_BEFORE_STARTING TRUE // Setting this to TRUE makes the plugin force GDK_SCALE=1 #define FORCE_GDK_SCALE TRUE #include "csd-wacom-manager.h" #include "daemon-skeleton.h" cinnamon-settings-daemon-5.2.0/plugins/wacom/csd-wacom-osd-window.c0000664000175000017500000014253314144454032024254 0ustar fabiofabio/* * Copyright (C) 2012 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Author: Olivier Fourdan * */ #include "config.h" #include #include #include #include #include #include #include "csd-wacom-osd-window.h" #include "csd-wacom-device.h" #include "csd-enums.h" #define ROTATION_KEY "rotation" #define ACTION_TYPE_KEY "action-type" #define CUSTOM_ACTION_KEY "custom-action" #define CUSTOM_ELEVATOR_ACTION_KEY "custom-elevator-action" #define RES_PATH "/org/cinnamon/settings-daemon/plugins/wacom/" #define BACK_OPACITY 0.8 #define INACTIVE_COLOR "#ededed" #define ACTIVE_COLOR "#729fcf" #define STROKE_COLOR "#000000" #define DARK_COLOR "#535353" #define BACK_COLOR "#000000" #define ELEVATOR_TIMEOUT 250 /* ms */ static struct { const gchar *color_name; const gchar *color_value; } css_color_table[] = { { "inactive_color", INACTIVE_COLOR }, { "active_color", ACTIVE_COLOR }, { "stroke_color", STROKE_COLOR }, { "dark_color", DARK_COLOR }, { "back_color", BACK_COLOR } }; static gchar * replace_string (gchar **string, const gchar *search, const char *replacement) { GRegex *regex; gchar *res; g_return_val_if_fail (*string != NULL, NULL); g_return_val_if_fail (string != NULL, NULL); g_return_val_if_fail (search != NULL, *string); g_return_val_if_fail (replacement != NULL, *string); regex = g_regex_new (search, 0, 0, NULL); res = g_regex_replace_literal (regex, *string, -1, 0, replacement, 0, NULL); g_regex_unref (regex); /* The given string is freed and replaced by the resulting replacement */ g_free (*string); *string = res; return res; } static gchar get_last_char (gchar *string) { size_t pos; g_return_val_if_fail (string != NULL, '\0'); pos = strlen (string); g_return_val_if_fail (pos > 0, '\0'); return string[pos - 1]; } static double get_rotation_in_radian (CsdWacomRotation rotation) { switch (rotation) { case CSD_WACOM_ROTATION_NONE: return 0.0; break; case CSD_WACOM_ROTATION_HALF: return G_PI; break; /* We only support left-handed/right-handed */ case CSD_WACOM_ROTATION_CCW: case CSD_WACOM_ROTATION_CW: default: break; } /* Fallback */ return 0.0; } static gboolean get_sub_location (RsvgHandle *handle, const char *sub, cairo_t *cr, double *x, double *y) { RsvgPositionData position; double tx, ty; if (!rsvg_handle_get_position_sub (handle, &position, sub)) { g_warning ("Failed to retrieve '%s' position", sub); return FALSE; } tx = (double) position.x; ty = (double) position.y; cairo_user_to_device (cr, &tx, &ty); if (x) *x = tx; if (y) *y = ty; return TRUE; } static gboolean get_image_size (const char *filename, int *width, int *height) { RsvgHandle *handle; RsvgDimensionData dimensions; GError* error = NULL; if (filename == NULL) return FALSE; handle = rsvg_handle_new_from_file (filename, &error); if (error != NULL) { g_printerr ("%s\n", error->message); g_error_free (error); } if (handle == NULL) return FALSE; /* Compute image size */ rsvg_handle_get_dimensions (handle, &dimensions); g_object_unref (handle); if (dimensions.width == 0 || dimensions.height == 0) return FALSE; if (width) *width = dimensions.width; if (height) *height = dimensions.height; return TRUE; } static int get_pango_vertical_offset (PangoLayout *layout) { const PangoFontDescription *desc; PangoContext *context; PangoLanguage *language; PangoFontMetrics *metrics; int baseline; int strikethrough; int thickness; context = pango_layout_get_context (layout); language = pango_language_get_default (); desc = pango_layout_get_font_description (layout); metrics = pango_context_get_metrics (context, desc, language); baseline = pango_layout_get_baseline (layout); strikethrough = pango_font_metrics_get_strikethrough_position (metrics); thickness = pango_font_metrics_get_underline_thickness (metrics); return PANGO_PIXELS (baseline - strikethrough - thickness / 2); } #define CSD_TYPE_WACOM_OSD_BUTTON (csd_wacom_osd_button_get_type ()) #define CSD_WACOM_OSD_BUTTON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_WACOM_OSD_BUTTON, CsdWacomOSDButton)) #define CSD_WACOM_OSD_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_WACOM_OSD_BUTTON, CsdWacomOSDButtonClass)) #define CSD_IS_WACOM_OSD_BUTTON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_WACOM_OSD_BUTTON)) #define CSD_IS_WACOM_OSD_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_WACOM_OSD_BUTTON)) #define CSD_WACOM_OSD_BUTTON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_WACOM_OSD_BUTTON, CsdWacomOSDButtonClass)) typedef struct CsdWacomOSDButtonPrivate CsdWacomOSDButtonPrivate; typedef struct { GObject parent; CsdWacomOSDButtonPrivate *priv; } CsdWacomOSDButton; typedef struct { GObjectClass parent_class; } CsdWacomOSDButtonClass; GType csd_wacom_osd_button_get_type (void) G_GNUC_CONST; enum { PROP_OSD_BUTTON_0, PROP_OSD_BUTTON_ID, PROP_OSD_BUTTON_CLASS, PROP_OSD_BUTTON_LABEL, PROP_OSD_BUTTON_ACTIVE, PROP_OSD_BUTTON_VISIBLE, PROP_OSD_BUTTON_AUTO_OFF }; #define CSD_WACOM_OSD_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ CSD_TYPE_WACOM_OSD_BUTTON, \ CsdWacomOSDButtonPrivate)) #define MATCH_ID(b,s) (g_strcmp0 (b->priv->id, s) == 0) struct CsdWacomOSDButtonPrivate { GtkWidget *widget; char *id; char *class; char *label; double label_x; double label_y; CsdWacomTabletButtonType type; CsdWacomTabletButtonPos position; gboolean active; gboolean visible; guint auto_off; guint timeout; }; static void csd_wacom_osd_button_class_init (CsdWacomOSDButtonClass *klass); static void csd_wacom_osd_button_init (CsdWacomOSDButton *osd_button); static void csd_wacom_osd_button_finalize (GObject *object); G_DEFINE_TYPE (CsdWacomOSDButton, csd_wacom_osd_button, G_TYPE_OBJECT) static void csd_wacom_osd_button_set_id (CsdWacomOSDButton *osd_button, const gchar *id) { g_return_if_fail (CSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->id = g_strdup (id); } static void csd_wacom_osd_button_set_class (CsdWacomOSDButton *osd_button, const gchar *class) { g_return_if_fail (CSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->class = g_strdup (class); } static gchar* csd_wacom_osd_button_get_label_class (CsdWacomOSDButton *osd_button) { gchar *label_class; label_class = g_strconcat ("#Label", osd_button->priv->class, NULL); return (label_class); } static void csd_wacom_osd_button_set_label (CsdWacomOSDButton *osd_button, const gchar *str) { g_return_if_fail (CSD_IS_WACOM_OSD_BUTTON (osd_button)); g_free (osd_button->priv->label); osd_button->priv->label = g_strdup (str ? str : ""); } static void csd_wacom_osd_button_set_button_type (CsdWacomOSDButton *osd_button, CsdWacomTabletButtonType type) { g_return_if_fail (CSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->type = type; } static void csd_wacom_osd_button_set_position (CsdWacomOSDButton *osd_button, CsdWacomTabletButtonPos position) { g_return_if_fail (CSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->position = position; } static void csd_wacom_osd_button_set_location (CsdWacomOSDButton *osd_button, double x, double y) { g_return_if_fail (CSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->label_x = x; osd_button->priv->label_y = y; } static void csd_wacom_osd_button_set_auto_off (CsdWacomOSDButton *osd_button, guint timeout) { g_return_if_fail (CSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->auto_off = timeout; } static void csd_wacom_osd_button_redraw (CsdWacomOSDButton *osd_button) { GdkWindow *window; g_return_if_fail (GTK_IS_WIDGET (osd_button->priv->widget)); window = gtk_widget_get_window (GTK_WIDGET (osd_button->priv->widget)); gdk_window_invalidate_rect (window, NULL, FALSE); } static gboolean csd_wacom_osd_button_timer (CsdWacomOSDButton *osd_button) { /* Auto de-activate the button */ osd_button->priv->active = FALSE; csd_wacom_osd_button_redraw (osd_button); return FALSE; } static void csd_wacom_osd_button_set_active (CsdWacomOSDButton *osd_button, gboolean active) { gboolean previous_state; g_return_if_fail (CSD_IS_WACOM_OSD_BUTTON (osd_button)); previous_state = osd_button->priv->active; if (osd_button->priv->auto_off > 0) { /* For auto-off buttons, apply only if active, de-activation is done in the timeout */ if (active == TRUE) osd_button->priv->active = active; if (osd_button->priv->timeout) { g_source_remove (osd_button->priv->timeout); osd_button->priv->timeout = 0; } osd_button->priv->timeout = g_timeout_add (osd_button->priv->auto_off, (GSourceFunc) csd_wacom_osd_button_timer, osd_button); } else { /* Whereas for other buttons, apply the change straight away */ osd_button->priv->active = active; } if (previous_state != osd_button->priv->active) csd_wacom_osd_button_redraw (osd_button); } static void csd_wacom_osd_button_set_visible (CsdWacomOSDButton *osd_button, gboolean visible) { g_return_if_fail (CSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->visible = visible; } static CsdWacomOSDButton * csd_wacom_osd_button_new (GtkWidget *widget, gchar *id) { CsdWacomOSDButton *osd_button; osd_button = CSD_WACOM_OSD_BUTTON (g_object_new (CSD_TYPE_WACOM_OSD_BUTTON, "id", id, NULL)); osd_button->priv->widget = widget; return osd_button; } static void csd_wacom_osd_button_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsdWacomOSDButton *osd_button; osd_button = CSD_WACOM_OSD_BUTTON (object); switch (prop_id) { case PROP_OSD_BUTTON_ID: csd_wacom_osd_button_set_id (osd_button, g_value_get_string (value)); break; case PROP_OSD_BUTTON_CLASS: csd_wacom_osd_button_set_class (osd_button, g_value_get_string (value)); break; case PROP_OSD_BUTTON_LABEL: csd_wacom_osd_button_set_label (osd_button, g_value_get_string (value)); break; case PROP_OSD_BUTTON_ACTIVE: csd_wacom_osd_button_set_active (osd_button, g_value_get_boolean (value)); break; case PROP_OSD_BUTTON_VISIBLE: csd_wacom_osd_button_set_visible (osd_button, g_value_get_boolean (value)); break; case PROP_OSD_BUTTON_AUTO_OFF: csd_wacom_osd_button_set_auto_off (osd_button, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_wacom_osd_button_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdWacomOSDButton *osd_button; osd_button = CSD_WACOM_OSD_BUTTON (object); switch (prop_id) { case PROP_OSD_BUTTON_ID: g_value_set_string (value, osd_button->priv->id); break; case PROP_OSD_BUTTON_CLASS: g_value_set_string (value, osd_button->priv->class); break; case PROP_OSD_BUTTON_LABEL: g_value_set_string (value, osd_button->priv->label); break; case PROP_OSD_BUTTON_ACTIVE: g_value_set_boolean (value, osd_button->priv->active); break; case PROP_OSD_BUTTON_VISIBLE: g_value_set_boolean (value, osd_button->priv->visible); break; case PROP_OSD_BUTTON_AUTO_OFF: g_value_set_uint (value, osd_button->priv->auto_off); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_wacom_osd_button_class_init (CsdWacomOSDButtonClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = csd_wacom_osd_button_set_property; object_class->get_property = csd_wacom_osd_button_get_property; object_class->finalize = csd_wacom_osd_button_finalize; g_object_class_install_property (object_class, PROP_OSD_BUTTON_ID, g_param_spec_string ("id", "Button Id", "The Wacom Button ID", "", G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_OSD_BUTTON_CLASS, g_param_spec_string ("class", "Button Class", "The Wacom Button Class", "", G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_OSD_BUTTON_LABEL, g_param_spec_string ("label", "Label", "The button label", "", G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_OSD_BUTTON_ACTIVE, g_param_spec_boolean ("active", "Active", "Whether the button is active", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_OSD_BUTTON_VISIBLE, g_param_spec_boolean ("visible", "Visible", "Whether the button is visible", TRUE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_OSD_BUTTON_AUTO_OFF, g_param_spec_uint ("auto-off", "Auto Off", "Timeout before button disables itself automatically", 0, G_MAXUINT, 0, /* disabled by default */ G_PARAM_READWRITE)); g_type_class_add_private (klass, sizeof (CsdWacomOSDButtonPrivate)); } static void csd_wacom_osd_button_init (CsdWacomOSDButton *osd_button) { osd_button->priv = CSD_WACOM_OSD_BUTTON_GET_PRIVATE (osd_button); } static void csd_wacom_osd_button_finalize (GObject *object) { CsdWacomOSDButton *osd_button; CsdWacomOSDButtonPrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_WACOM_OSD_BUTTON (object)); osd_button = CSD_WACOM_OSD_BUTTON (object); g_return_if_fail (osd_button->priv != NULL); priv = osd_button->priv; if (priv->timeout > 0) { g_source_remove (priv->timeout); priv->timeout = 0; } g_clear_pointer (&priv->id, g_free); g_clear_pointer (&priv->class, g_free); g_clear_pointer (&priv->label, g_free); G_OBJECT_CLASS (csd_wacom_osd_button_parent_class)->finalize (object); } /* Compute the new actual position once rotation is applied */ static CsdWacomTabletButtonPos get_actual_position (CsdWacomTabletButtonPos position, CsdWacomRotation rotation) { switch (rotation) { case CSD_WACOM_ROTATION_NONE: return position; break; case CSD_WACOM_ROTATION_HALF: if (position == WACOM_TABLET_BUTTON_POS_LEFT) return WACOM_TABLET_BUTTON_POS_RIGHT; if (position == WACOM_TABLET_BUTTON_POS_RIGHT) return WACOM_TABLET_BUTTON_POS_LEFT; if (position == WACOM_TABLET_BUTTON_POS_TOP) return WACOM_TABLET_BUTTON_POS_BOTTOM; if (position == WACOM_TABLET_BUTTON_POS_BOTTOM) return WACOM_TABLET_BUTTON_POS_TOP; break; /* We only support left-handed/right-handed */ case CSD_WACOM_ROTATION_CCW: case CSD_WACOM_ROTATION_CW: default: break; } /* fallback */ return position; } static void csd_wacom_osd_button_draw_label (CsdWacomOSDButton *osd_button, GtkStyleContext *style_context, PangoContext *pango_context, cairo_t *cr, CsdWacomRotation rotation) { CsdWacomOSDButtonPrivate *priv; PangoLayout *layout; PangoRectangle logical_rect; CsdWacomTabletButtonPos actual_position; double lx, ly; gchar *markup; g_return_if_fail (CSD_IS_WACOM_OSD_BUTTON (osd_button)); priv = osd_button->priv; if (priv->visible == FALSE) return; actual_position = get_actual_position (priv->position, rotation); layout = pango_layout_new (pango_context); if (priv->active) markup = g_strdup_printf ("%s", priv->label); else markup = g_strdup_printf ("%s", priv->label); pango_layout_set_markup (layout, markup, -1); g_free (markup); pango_layout_get_pixel_extents (layout, NULL, &logical_rect); switch (actual_position) { case WACOM_TABLET_BUTTON_POS_LEFT: pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT); lx = priv->label_x + logical_rect.x; ly = priv->label_y + logical_rect.y - get_pango_vertical_offset (layout); break; case WACOM_TABLET_BUTTON_POS_RIGHT: pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); lx = priv->label_x + logical_rect.x - logical_rect.width; ly = priv->label_y + logical_rect.y - get_pango_vertical_offset (layout); break; case WACOM_TABLET_BUTTON_POS_TOP: pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); lx = priv->label_x + logical_rect.x - logical_rect.width / 2; ly = priv->label_y + logical_rect.y; break; case WACOM_TABLET_BUTTON_POS_BOTTOM: pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); lx = priv->label_x + logical_rect.x - logical_rect.width / 2; ly = priv->label_y + logical_rect.y - logical_rect.height; break; default: g_warning ("Unhandled button position"); pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); lx = priv->label_x + logical_rect.x - logical_rect.width / 2; ly = priv->label_y + logical_rect.y - logical_rect.height / 2; break; } gtk_render_layout (style_context, cr, lx, ly, layout); g_object_unref (layout); } enum { PROP_OSD_WINDOW_0, PROP_OSD_WINDOW_MESSAGE, PROP_OSD_WINDOW_CSD_WACOM_DEVICE }; #define CSD_WACOM_OSD_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ CSD_TYPE_WACOM_OSD_WINDOW, \ CsdWacomOSDWindowPrivate)) struct CsdWacomOSDWindowPrivate { RsvgHandle *handle; CsdWacomDevice *pad; CsdWacomRotation rotation; GdkRectangle screen_area; GdkRectangle monitor_area; GdkRectangle tablet_area; char *message; GList *buttons; }; static void csd_wacom_osd_window_class_init (CsdWacomOSDWindowClass *klass); static void csd_wacom_osd_window_init (CsdWacomOSDWindow *osd_window); static void csd_wacom_osd_window_finalize (GObject *object); G_DEFINE_TYPE (CsdWacomOSDWindow, csd_wacom_osd_window, GTK_TYPE_WINDOW) static RsvgHandle * load_rsvg_with_base (const char *css_string, const char *original_layout_path, GError **error) { RsvgHandle *handle; char *dirname; handle = rsvg_handle_new (); dirname = g_path_get_dirname (original_layout_path); rsvg_handle_set_base_uri (handle, dirname); g_free (dirname); if (!rsvg_handle_write (handle, (guint8 *) css_string, strlen (css_string), error)) { g_object_unref (handle); return NULL; } if (!rsvg_handle_close (handle, error)) { g_object_unref (handle); return NULL; } return handle; } static void csd_wacom_osd_window_update (CsdWacomOSDWindow *osd_window) { GError *error = NULL; gchar *width, *height; gchar *buttons_section; gchar *css_string; const gchar *layout_file; GBytes *css_data; guint i; GList *l; g_return_if_fail (CSD_IS_WACOM_OSD_WINDOW (osd_window)); g_return_if_fail (CSD_IS_WACOM_DEVICE (osd_window->priv->pad)); css_data = g_resources_lookup_data (RES_PATH "tablet-layout.css", 0, &error); if (error != NULL) { g_printerr ("GResource error: %s\n", error->message); g_clear_pointer (&error, g_error_free); } if (css_data == NULL) return; css_string = g_strdup ((gchar *) g_bytes_get_data (css_data, NULL)); g_bytes_unref(css_data); width = g_strdup_printf ("%d", osd_window->priv->tablet_area.width); replace_string (&css_string, "layout_width", width); g_free (width); height = g_strdup_printf ("%d", osd_window->priv->tablet_area.height); replace_string (&css_string, "layout_height", height); g_free (height); /* Build the buttons section */ buttons_section = g_strdup (""); for (l = osd_window->priv->buttons; l != NULL; l = l->next) { CsdWacomOSDButton *osd_button = l->data; if (osd_button->priv->visible == FALSE) continue; if (osd_button->priv->active) { buttons_section = g_strconcat (buttons_section, ".", osd_button->priv->class, " {\n" " stroke: active_color !important;\n" " fill: active_color !important;\n" " }\n", NULL); } } replace_string (&css_string, "buttons_section", buttons_section); g_free (buttons_section); for (i = 0; i < G_N_ELEMENTS (css_color_table); i++) replace_string (&css_string, css_color_table[i].color_name, css_color_table[i].color_value); layout_file = csd_wacom_device_get_layout_path (osd_window->priv->pad); replace_string (&css_string, "layout_file", layout_file); /* Render the SVG with the CSS applied */ g_clear_object (&osd_window->priv->handle); osd_window->priv->handle = load_rsvg_with_base (css_string, layout_file, &error); if (osd_window->priv->handle == NULL) { g_debug ("CSS applied:\n%s\n", css_string); g_printerr ("RSVG error: %s\n", error->message); g_clear_error (&error); } g_free (css_string); } static void csd_wacom_osd_window_draw_message (CsdWacomOSDWindow *osd_window, GtkStyleContext *style_context, PangoContext *pango_context, cairo_t *cr) { GdkRectangle *monitor_area = &osd_window->priv->monitor_area; PangoRectangle logical_rect; PangoLayout *layout; char *markup; double x; double y; if (osd_window->priv->message == NULL) return; layout = pango_layout_new (pango_context); pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); markup = g_strdup_printf ("%s", osd_window->priv->message); pango_layout_set_markup (layout, markup, -1); g_free (markup); pango_layout_get_pixel_extents (layout, NULL, &logical_rect); x = (monitor_area->width - logical_rect.width) / 2 + logical_rect.x; y = (monitor_area->height - logical_rect.height) / 2 + logical_rect.y; gtk_render_layout (style_context, cr, x, y, layout); g_object_unref (layout); } static void csd_wacom_osd_window_draw_labels (CsdWacomOSDWindow *osd_window, GtkStyleContext *style_context, PangoContext *pango_context, cairo_t *cr) { GList *l; for (l = osd_window->priv->buttons; l != NULL; l = l->next) { CsdWacomOSDButton *osd_button = l->data; if (osd_button->priv->visible == FALSE) continue; csd_wacom_osd_button_draw_label (osd_button, style_context, pango_context, cr, osd_window->priv->rotation); } } static void csd_wacom_osd_window_place_buttons (CsdWacomOSDWindow *osd_window, cairo_t *cr) { GList *l; g_return_if_fail (CSD_IS_WACOM_OSD_WINDOW (osd_window)); for (l = osd_window->priv->buttons; l != NULL; l = l->next) { CsdWacomOSDButton *osd_button = l->data; double label_x, label_y; gchar *sub; sub = csd_wacom_osd_button_get_label_class (osd_button); if (!get_sub_location (osd_window->priv->handle, sub, cr, &label_x, &label_y)) { g_warning ("Failed to retrieve %s position", sub); g_free (sub); continue; } g_free (sub); csd_wacom_osd_button_set_location (osd_button, label_x, label_y); } } /* Note: this function does modify the given cairo context */ static void csd_wacom_osd_window_adjust_cairo (CsdWacomOSDWindow *osd_window, cairo_t *cr) { double scale, twidth, theight; GdkRectangle *tablet_area = &osd_window->priv->tablet_area; GdkRectangle *screen_area = &osd_window->priv->screen_area; GdkRectangle *monitor_area = &osd_window->priv->monitor_area; /* Rotate */ cairo_rotate (cr, get_rotation_in_radian (osd_window->priv->rotation)); /* Scale to fit in window */ scale = MIN ((double) monitor_area->width / tablet_area->width, (double) monitor_area->height / tablet_area->height); cairo_scale (cr, scale, scale); /* Center the result in window */ twidth = (double) tablet_area->width; theight = (double) tablet_area->height; cairo_user_to_device_distance (cr, &twidth, &theight); twidth = ((double) monitor_area->width - twidth) / 2.0; theight = ((double) monitor_area->height - theight) / 2.0; cairo_device_to_user_distance (cr, &twidth, &theight); twidth = twidth + (double) (monitor_area->x - screen_area->x); theight = theight + (double) (monitor_area->y - screen_area->y); cairo_translate (cr, twidth, theight); } static gboolean csd_wacom_osd_window_draw (GtkWidget *widget, cairo_t *cr) { CsdWacomOSDWindow *osd_window = CSD_WACOM_OSD_WINDOW (widget); g_return_val_if_fail (CSD_IS_WACOM_OSD_WINDOW (osd_window), FALSE); g_return_val_if_fail (CSD_IS_WACOM_DEVICE (osd_window->priv->pad), FALSE); if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget))) { GtkStyleContext *style_context; PangoContext *pango_context; style_context = gtk_widget_get_style_context (widget); pango_context = gtk_widget_get_pango_context (widget); cairo_set_source_rgba (cr, 0, 0, 0, BACK_OPACITY); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); /* Save original matrix */ cairo_save (cr); /* Apply new cairo transformation matrix */ csd_wacom_osd_window_adjust_cairo (osd_window, cr); /* And render the tablet layout */ csd_wacom_osd_window_update (osd_window); rsvg_handle_render_cairo (osd_window->priv->handle, cr); csd_wacom_osd_window_place_buttons (osd_window, cr); /* Reset to original matrix */ cairo_restore (cr); /* Draw button labels and message */ csd_wacom_osd_window_draw_labels (osd_window, style_context, pango_context, cr); csd_wacom_osd_window_draw_message (osd_window, style_context, pango_context, cr); } return FALSE; } static gchar * get_escaped_accel_shortcut (const gchar *accel) { guint keyval; GdkModifierType mask; gchar *str, *label; if (accel == NULL || accel[0] == '\0') return g_strdup (_("Do Nothing")); gtk_accelerator_parse (accel, &keyval, &mask); str = gtk_accelerator_get_label (keyval, mask); label = g_markup_printf_escaped (_("Send Keystroke %s"), str); g_free (str); return label; } static gchar * get_tablet_button_label_normal (CsdWacomDevice *device, CsdWacomTabletButton *button) { CsdWacomActionType type; gchar *name, *str; type = g_settings_get_enum (button->settings, ACTION_TYPE_KEY); if (type == CSD_WACOM_ACTION_TYPE_NONE) return g_strdup (_("Do Nothing")); if (type == CSD_WACOM_ACTION_TYPE_HELP) return g_strdup (_("Show On-Screen Help")); if (type == CSD_WACOM_ACTION_TYPE_SWITCH_MONITOR) return g_strdup (_("Switch Monitor")); str = g_settings_get_string (button->settings, CUSTOM_ACTION_KEY); if (str == NULL || *str == '\0') { g_free (str); return g_strdup (_("Do Nothing")); } name = get_escaped_accel_shortcut (str); g_free (str); return name; } static gchar * get_tablet_button_label_touch (CsdWacomDevice *device, CsdWacomTabletButton *button, GtkDirectionType dir) { char **strv, *name, *str; strv = g_settings_get_strv (button->settings, CUSTOM_ELEVATOR_ACTION_KEY); name = NULL; if (strv) { if (g_strv_length (strv) >= 1 && dir == GTK_DIR_UP) name = g_strdup (strv[0]); else if (g_strv_length (strv) >= 2 && dir == GTK_DIR_DOWN) name = g_strdup (strv[1]); g_strfreev (strv); } str = get_escaped_accel_shortcut (name); g_free (name); name = str; /* With multiple modes, also show the current mode for that action */ if (csd_wacom_device_get_num_modes (device, button->group_id) > 1) { name = g_strdup_printf (_("Mode %d: %s"), button->idx + 1, str); g_free (str); } return name; } static gchar * get_tablet_button_label (CsdWacomDevice *device, CsdWacomTabletButton *button, GtkDirectionType dir) { g_return_val_if_fail (button, NULL); if (!button->settings) goto out; switch (button->type) { case WACOM_TABLET_BUTTON_TYPE_NORMAL: return get_tablet_button_label_normal (device, button); break; case WACOM_TABLET_BUTTON_TYPE_RING: case WACOM_TABLET_BUTTON_TYPE_STRIP: return get_tablet_button_label_touch (device, button, dir); break; case WACOM_TABLET_BUTTON_TYPE_HARDCODED: default: break; } out: return g_strdup (button->name); } static gchar* get_tablet_button_class_name (CsdWacomTabletButton *tablet_button, GtkDirectionType dir) { gchar *id; gchar c; id = tablet_button->id; switch (tablet_button->type) { case WACOM_TABLET_BUTTON_TYPE_RING: if (id[0] == 'l') /* left-ring */ return g_strdup_printf ("Ring%s", (dir == GTK_DIR_UP ? "CCW" : "CW")); if (id[0] == 'r') /* right-ring */ return g_strdup_printf ("Ring2%s", (dir == GTK_DIR_UP ? "CCW" : "CW")); g_warning ("Unknown ring type '%s'", id); return NULL; break; case WACOM_TABLET_BUTTON_TYPE_STRIP: if (id[0] == 'l') /* left-strip */ return g_strdup_printf ("Strip%s", (dir == GTK_DIR_UP ? "Up" : "Down")); if (id[0] == 'r') /* right-strip */ return g_strdup_printf ("Strip2%s", (dir == GTK_DIR_UP ? "Up" : "Down")); g_warning ("Unknown strip type '%s'", id); return NULL; break; case WACOM_TABLET_BUTTON_TYPE_NORMAL: case WACOM_TABLET_BUTTON_TYPE_HARDCODED: c = get_last_char (id); return g_strdup_printf ("%c", g_ascii_toupper (c)); break; default: g_warning ("Unknown button type '%s'", id); break; } return NULL; } static gchar* get_tablet_button_id_name (CsdWacomTabletButton *tablet_button, GtkDirectionType dir) { gchar *id; gchar c; id = tablet_button->id; switch (tablet_button->type) { case WACOM_TABLET_BUTTON_TYPE_RING: return g_strconcat (id, (dir == GTK_DIR_UP ? "-ccw" : "-cw"), NULL); break; case WACOM_TABLET_BUTTON_TYPE_STRIP: return g_strconcat (id, (dir == GTK_DIR_UP ? "-up" : "-down"), NULL); break; case WACOM_TABLET_BUTTON_TYPE_NORMAL: case WACOM_TABLET_BUTTON_TYPE_HARDCODED: c = get_last_char (id); return g_strdup_printf ("%c", g_ascii_toupper (c)); break; default: g_warning ("Unknown button type '%s'", id); break; } return NULL; } static gint get_elevator_current_mode (CsdWacomOSDWindow *osd_window, CsdWacomTabletButton *elevator_button) { GList *list, *l; gint mode; mode = 1; /* Search in the list of buttons the corresponding * mode-switch button and get the current mode */ list = csd_wacom_device_get_buttons (osd_window->priv->pad); for (l = list; l != NULL; l = l->next) { CsdWacomTabletButton *tablet_button = l->data; if (tablet_button->type != WACOM_TABLET_BUTTON_TYPE_HARDCODED) continue; if (elevator_button->group_id != tablet_button->group_id) continue; mode = csd_wacom_device_get_current_mode (osd_window->priv->pad, tablet_button->group_id); break; } g_list_free (list); return mode; } static CsdWacomOSDButton * csd_wacom_osd_window_add_button_with_dir (CsdWacomOSDWindow *osd_window, CsdWacomTabletButton *tablet_button, guint timeout, GtkDirectionType dir) { CsdWacomOSDButton *osd_button; gchar *str; str = get_tablet_button_id_name (tablet_button, dir); osd_button = csd_wacom_osd_button_new (GTK_WIDGET (osd_window), str); g_free (str); str = get_tablet_button_class_name (tablet_button, dir); csd_wacom_osd_button_set_class (osd_button, str); g_free (str); str = get_tablet_button_label (osd_window->priv->pad, tablet_button, dir); csd_wacom_osd_button_set_label (osd_button, str); g_free (str); csd_wacom_osd_button_set_button_type (osd_button, tablet_button->type); csd_wacom_osd_button_set_position (osd_button, tablet_button->pos); csd_wacom_osd_button_set_auto_off (osd_button, timeout); osd_window->priv->buttons = g_list_append (osd_window->priv->buttons, osd_button); return osd_button; } static void csd_wacom_osd_window_add_tablet_button (CsdWacomOSDWindow *osd_window, CsdWacomTabletButton *tablet_button) { CsdWacomOSDButton *osd_button; gint mode; switch (tablet_button->type) { case WACOM_TABLET_BUTTON_TYPE_NORMAL: case WACOM_TABLET_BUTTON_TYPE_HARDCODED: osd_button = csd_wacom_osd_window_add_button_with_dir (osd_window, tablet_button, 0, 0); csd_wacom_osd_button_set_visible (osd_button, TRUE); break; case WACOM_TABLET_BUTTON_TYPE_RING: case WACOM_TABLET_BUTTON_TYPE_STRIP: mode = get_elevator_current_mode (osd_window, tablet_button) - 1; /* Add 2 buttons per elevator, one "Up"... */ osd_button = csd_wacom_osd_window_add_button_with_dir (osd_window, tablet_button, ELEVATOR_TIMEOUT, GTK_DIR_UP); csd_wacom_osd_button_set_visible (osd_button, tablet_button->idx == mode); /* ... and one "Down" */ osd_button = csd_wacom_osd_window_add_button_with_dir (osd_window, tablet_button, ELEVATOR_TIMEOUT, GTK_DIR_DOWN); csd_wacom_osd_button_set_visible (osd_button, tablet_button->idx == mode); break; default: g_warning ("Unknown button type"); break; } } /* * Returns the rotation to apply a device to get a representation relative to * the current rotation of the output. * (This function is _not_ the same as in csd-wacom-manager.c) */ static CsdWacomRotation display_relative_rotation (CsdWacomRotation device_rotation, CsdWacomRotation output_rotation) { CsdWacomRotation rotations[] = { CSD_WACOM_ROTATION_HALF, CSD_WACOM_ROTATION_CW, CSD_WACOM_ROTATION_NONE, CSD_WACOM_ROTATION_CCW }; guint i; if (device_rotation == output_rotation) return CSD_WACOM_ROTATION_NONE; if (output_rotation == CSD_WACOM_ROTATION_NONE) return device_rotation; for (i = 0; i < G_N_ELEMENTS (rotations); i++) { if (device_rotation == rotations[i]) break; } if (output_rotation == CSD_WACOM_ROTATION_HALF) return rotations[(i + G_N_ELEMENTS (rotations) - 2) % G_N_ELEMENTS (rotations)]; if (output_rotation == CSD_WACOM_ROTATION_CW) return rotations[(i + 1) % G_N_ELEMENTS (rotations)]; if (output_rotation == CSD_WACOM_ROTATION_CCW) return rotations[(i + G_N_ELEMENTS (rotations) - 1) % G_N_ELEMENTS (rotations)]; /* fallback */ return CSD_WACOM_ROTATION_NONE; } static void csd_wacom_osd_window_mapped (GtkWidget *widget, gpointer data) { CsdWacomOSDWindow *osd_window = CSD_WACOM_OSD_WINDOW (widget); g_return_if_fail (CSD_IS_WACOM_OSD_WINDOW (osd_window)); /* Position the window at its expected position before moving * to fullscreen, so the window will be on the right monitor. */ gtk_window_move (GTK_WINDOW (osd_window), osd_window->priv->screen_area.x, osd_window->priv->screen_area.y); gtk_window_fullscreen (GTK_WINDOW (osd_window)); gtk_window_set_keep_above (GTK_WINDOW (osd_window), TRUE); } static void csd_wacom_osd_window_realized (GtkWidget *widget, gpointer data) { CsdWacomOSDWindow *osd_window = CSD_WACOM_OSD_WINDOW (widget); GdkWindow *gdk_window; GdkRGBA transparent; GdkScreen *screen; GdkCursor *cursor; gint monitor; gboolean status; g_return_if_fail (CSD_IS_WACOM_OSD_WINDOW (osd_window)); g_return_if_fail (CSD_IS_WACOM_DEVICE (osd_window->priv->pad)); if (!gtk_widget_get_realized (widget)) return; screen = gtk_widget_get_screen (widget); gdk_window = gtk_widget_get_window (widget); transparent.red = transparent.green = transparent.blue = 0.0; transparent.alpha = BACK_OPACITY; gdk_window_set_background_rgba (gdk_window, &transparent); cursor = gdk_cursor_new (GDK_BLANK_CURSOR); gdk_window_set_cursor (gdk_window, cursor); g_object_unref (cursor); /* Determine the monitor for that device and set appropriate fullscreen mode*/ monitor = csd_wacom_device_get_display_monitor (osd_window->priv->pad); if (monitor == CSD_WACOM_SET_ALL_MONITORS) { /* Covers the entire screen */ osd_window->priv->screen_area.x = 0; osd_window->priv->screen_area.y = 0; osd_window->priv->screen_area.width = gdk_screen_get_width (screen); osd_window->priv->screen_area.height = gdk_screen_get_height (screen); gdk_screen_get_monitor_geometry (screen, 0, &osd_window->priv->monitor_area); gdk_window_set_fullscreen_mode (gdk_window, GDK_FULLSCREEN_ON_ALL_MONITORS); } else { gdk_screen_get_monitor_geometry (screen, monitor, &osd_window->priv->screen_area); osd_window->priv->monitor_area = osd_window->priv->screen_area; gdk_window_set_fullscreen_mode (gdk_window, GDK_FULLSCREEN_ON_CURRENT_MONITOR); } gtk_window_set_default_size (GTK_WINDOW (osd_window), osd_window->priv->screen_area.width, osd_window->priv->screen_area.height); status = get_image_size (csd_wacom_device_get_layout_path (osd_window->priv->pad), &osd_window->priv->tablet_area.width, &osd_window->priv->tablet_area.height); if (status == FALSE) osd_window->priv->tablet_area = osd_window->priv->monitor_area; } static void csd_wacom_osd_window_set_device (CsdWacomOSDWindow *osd_window, CsdWacomDevice *device) { CsdWacomRotation device_rotation; CsdWacomRotation output_rotation; GSettings *settings; GList *list, *l; g_return_if_fail (CSD_IS_WACOM_OSD_WINDOW (osd_window)); g_return_if_fail (CSD_IS_WACOM_DEVICE (device)); /* If we had a layout previously handled, get rid of it */ if (osd_window->priv->handle) g_object_unref (osd_window->priv->handle); osd_window->priv->handle = NULL; /* Bind the device with the OSD window */ if (osd_window->priv->pad) g_object_weak_unref (G_OBJECT(osd_window->priv->pad), (GWeakNotify) gtk_widget_destroy, osd_window); osd_window->priv->pad = device; g_object_weak_ref (G_OBJECT(osd_window->priv->pad), (GWeakNotify) gtk_widget_destroy, osd_window); /* Capture current rotation, we do not update that later, OSD window is meant to be short lived */ settings = csd_wacom_device_get_settings (osd_window->priv->pad); device_rotation = g_settings_get_enum (settings, ROTATION_KEY); output_rotation = csd_wacom_device_get_display_rotation (osd_window->priv->pad); osd_window->priv->rotation = display_relative_rotation (device_rotation, output_rotation); /* Create the buttons */ list = csd_wacom_device_get_buttons (device); for (l = list; l != NULL; l = l->next) { CsdWacomTabletButton *tablet_button = l->data; csd_wacom_osd_window_add_tablet_button (osd_window, tablet_button); } g_list_free (list); } CsdWacomDevice * csd_wacom_osd_window_get_device (CsdWacomOSDWindow *osd_window) { g_return_val_if_fail (CSD_IS_WACOM_OSD_WINDOW (osd_window), NULL); return osd_window->priv->pad; } void csd_wacom_osd_window_set_message (CsdWacomOSDWindow *osd_window, const gchar *str) { g_return_if_fail (CSD_IS_WACOM_OSD_WINDOW (osd_window)); g_free (osd_window->priv->message); osd_window->priv->message = g_strdup (str); } const char * csd_wacom_osd_window_get_message (CsdWacomOSDWindow *osd_window) { g_return_val_if_fail (CSD_IS_WACOM_OSD_WINDOW (osd_window), NULL); return osd_window->priv->message; } static void csd_wacom_osd_window_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsdWacomOSDWindow *osd_window; osd_window = CSD_WACOM_OSD_WINDOW (object); switch (prop_id) { case PROP_OSD_WINDOW_MESSAGE: csd_wacom_osd_window_set_message (osd_window, g_value_get_string (value)); break; case PROP_OSD_WINDOW_CSD_WACOM_DEVICE: csd_wacom_osd_window_set_device (osd_window, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_wacom_osd_window_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdWacomOSDWindow *osd_window; osd_window = CSD_WACOM_OSD_WINDOW (object); switch (prop_id) { case PROP_OSD_WINDOW_MESSAGE: g_value_set_string (value, osd_window->priv->message); break; case PROP_OSD_WINDOW_CSD_WACOM_DEVICE: g_value_set_object (value, (GObject*) osd_window->priv->pad); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } void csd_wacom_osd_window_set_active (CsdWacomOSDWindow *osd_window, CsdWacomTabletButton *button, GtkDirectionType dir, gboolean active) { GList *l; gchar *id; g_return_if_fail (CSD_IS_WACOM_OSD_WINDOW (osd_window)); g_return_if_fail (button != NULL); id = get_tablet_button_id_name (button, dir); for (l = osd_window->priv->buttons; l != NULL; l = l->next) { CsdWacomOSDButton *osd_button = l->data; if (MATCH_ID (osd_button, id)) csd_wacom_osd_button_set_active (osd_button, active); } g_free (id); } void csd_wacom_osd_window_set_mode (CsdWacomOSDWindow *osd_window, gint group_id, gint mode) { GList *list, *l; list = csd_wacom_device_get_buttons (osd_window->priv->pad); for (l = list; l != NULL; l = l->next) { CsdWacomTabletButton *tablet_button = l->data; GList *l2; gchar *id_up, *id_down; if (tablet_button->type != WACOM_TABLET_BUTTON_TYPE_STRIP && tablet_button->type != WACOM_TABLET_BUTTON_TYPE_RING) continue; if (tablet_button->group_id != group_id) continue; id_up = get_tablet_button_id_name (tablet_button, GTK_DIR_UP); id_down = get_tablet_button_id_name (tablet_button, GTK_DIR_DOWN); for (l2 = osd_window->priv->buttons; l2 != NULL; l2 = l2->next) { CsdWacomOSDButton *osd_button = l2->data; gboolean visible = (tablet_button->idx == mode - 1); if (MATCH_ID (osd_button, id_up) || MATCH_ID (osd_button, id_down)) csd_wacom_osd_button_set_visible (osd_button, visible); } g_free (id_up); g_free (id_down); } g_list_free (list); } GtkWidget * csd_wacom_osd_window_new (CsdWacomDevice *pad, const gchar *message) { CsdWacomOSDWindow *osd_window; GdkScreen *screen; GdkVisual *visual; osd_window = CSD_WACOM_OSD_WINDOW (g_object_new (CSD_TYPE_WACOM_OSD_WINDOW, "type", GTK_WINDOW_TOPLEVEL, "skip-pager-hint", TRUE, "skip-taskbar-hint", TRUE, "focus-on-map", TRUE, "decorated", FALSE, "deletable", FALSE, "accept-focus", TRUE, "wacom-device", pad, "message", message, NULL)); /* Must set the visual before realizing the window */ gtk_widget_set_app_paintable (GTK_WIDGET (osd_window), TRUE); screen = gdk_screen_get_default (); visual = gdk_screen_get_rgba_visual (screen); if (visual == NULL) visual = gdk_screen_get_system_visual (screen); gtk_widget_set_visual (GTK_WIDGET (osd_window), visual); g_signal_connect (GTK_WIDGET (osd_window), "realize", G_CALLBACK (csd_wacom_osd_window_realized), NULL); g_signal_connect (GTK_WIDGET (osd_window), "map", G_CALLBACK (csd_wacom_osd_window_mapped), NULL); return GTK_WIDGET (osd_window); } static void csd_wacom_osd_window_class_init (CsdWacomOSDWindowClass *klass) { GObjectClass *gobject_class; GtkWidgetClass *widget_class; gobject_class = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); gobject_class->set_property = csd_wacom_osd_window_set_property; gobject_class->get_property = csd_wacom_osd_window_get_property; gobject_class->finalize = csd_wacom_osd_window_finalize; widget_class->draw = csd_wacom_osd_window_draw; g_object_class_install_property (gobject_class, PROP_OSD_WINDOW_MESSAGE, g_param_spec_string ("message", "Window message", "The message shown in the OSD window", "", G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_OSD_WINDOW_CSD_WACOM_DEVICE, g_param_spec_object ("wacom-device", "Wacom device", "The Wacom device represented by the OSD window", CSD_TYPE_WACOM_DEVICE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_type_class_add_private (klass, sizeof (CsdWacomOSDWindowPrivate)); } static void csd_wacom_osd_window_init (CsdWacomOSDWindow *osd_window) { osd_window->priv = CSD_WACOM_OSD_WINDOW_GET_PRIVATE (osd_window); } static void csd_wacom_osd_window_finalize (GObject *object) { CsdWacomOSDWindow *osd_window; CsdWacomOSDWindowPrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_WACOM_OSD_WINDOW (object)); osd_window = CSD_WACOM_OSD_WINDOW (object); g_return_if_fail (osd_window->priv != NULL); priv = osd_window->priv; g_clear_object (&priv->handle); g_clear_pointer (&priv->message, g_free); if (priv->buttons) { g_list_free_full (priv->buttons, g_object_unref); priv->buttons = NULL; } G_OBJECT_CLASS (csd_wacom_osd_window_parent_class)->finalize (object); } cinnamon-settings-daemon-5.2.0/plugins/wacom/test-osd-window.c0000664000175000017500000000733614144454032023357 0ustar fabiofabio/* * Copyright (C) 2012 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Author: Olivier Fourdan * */ #include "config.h" #include #include #include #include #include #include "csd-wacom-osd-window.h" static gboolean option_debug = FALSE; static CsdWacomDevice * search_pad_device (void) { GdkDeviceManager *mgr; GList *list, *l; mgr = gdk_display_get_device_manager (gdk_display_get_default ()); list = gdk_device_manager_list_devices (mgr, GDK_DEVICE_TYPE_SLAVE); for (l = list; l ; l = l->next) { CsdWacomDevice *device; device = csd_wacom_device_new (l->data); if (csd_wacom_device_get_device_type (device) == WACOM_TYPE_PAD) return (device); g_object_unref (device); } g_list_free (list); return NULL; } static CsdWacomDevice * create_fake_device (const char *tablet) { CsdWacomDevice *device; gchar *tool; tool = g_strdup_printf ("%s pad", tablet); device = csd_wacom_device_create_fake (WACOM_TYPE_PAD, tablet, tool); g_free (tool); return device; } static gboolean on_key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { gtk_main_quit(); return FALSE; } int main(int argc, char** argv) { GtkWidget *widget; GError *error = NULL; GOptionContext *context; CsdWacomDevice *device = NULL; gchar *message; gchar *tablet = NULL; const GOptionEntry entries[] = { { "tablet", 't', 0, G_OPTION_ARG_STRING, &tablet, "Name of the tablet to show", ""}, { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug, "Debug output", NULL }, { NULL } }; gtk_init (&argc, &argv); context = g_option_context_new ("- test functions"); g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); g_option_context_add_group (context, gtk_get_option_group (TRUE)); g_option_context_set_help_enabled (context, TRUE); if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) { g_print ("%s\n", error->message); g_option_context_free (context); return 1; } g_option_context_free (context); if (option_debug) g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); if (tablet) device = create_fake_device (tablet); else device = search_pad_device (); if (device == NULL) { g_print ("No pad device found, consider using --tablet\n"); return 1; } if (csd_wacom_device_get_layout_path (device) == NULL) { g_print ("This device has not layout available in libwacom\n"); return 1; } message = g_strdup_printf ("%s\n(Press a key to exit)", csd_wacom_device_get_name (device)); widget = csd_wacom_osd_window_new (device, message); g_free (message); g_signal_connect (widget, "key-release-event", G_CALLBACK(on_key_release_event), NULL); g_signal_connect (widget, "delete-event", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect (widget, "unmap", G_CALLBACK (gtk_main_quit), NULL); gtk_widget_show (widget); gtk_main (); g_free (tablet); if (device) { g_object_unref (device); } return 0; } cinnamon-settings-daemon-5.2.0/plugins/wacom/wacom.gresource.xml0000664000175000017500000000027014144454032023757 0ustar fabiofabio tablet-layout.css cinnamon-settings-daemon-5.2.0/plugins/wacom/org.cinnamon.settings-daemon.plugins.wacom.policy.in0000664000175000017500000000216214144454032032237 0ustar fabiofabio CINNAMON Settings Daemon http://git.gnome.org/browse/gnome-settings-daemon input-tablet Modify the lit LED for a Wacom tablet Authentication is required to modify the lit LED for a Wacom tablet no no yes @libexecdir@/csd-wacom-led-helper cinnamon-settings-daemon-5.2.0/plugins/wacom/csd-wacom-device.c0000664000175000017500000017167414144454032023431 0ustar fabiofabio/* * Copyright (C) 2011 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Author: Bastien Nocera * */ #include "config.h" #include #include #include #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include #include #include #include "csd-input-helper.h" #include "csd-enums.h" #include "csd-wacom-device.h" #define CSD_WACOM_STYLUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_WACOM_STYLUS, CsdWacomStylusPrivate)) #define WACOM_TABLET_SCHEMA "org.cinnamon.settings-daemon.peripherals.wacom" #define WACOM_DEVICE_CONFIG_BASE "/org/cinnamon/settings-daemon/peripherals/wacom/%s-%s/" #define WACOM_STYLUS_SCHEMA "org.cinnamon.settings-daemon.peripherals.wacom.stylus" #define WACOM_ERASER_SCHEMA "org.cinnamon.settings-daemon.peripherals.wacom.eraser" #define WACOM_BUTTON_SCHEMA "org.cinnamon.settings-daemon.peripherals.wacom.tablet-button" static struct { GnomeRRRotation rotation; CsdWacomRotation rotation_wacom; const gchar *rotation_string; } rotation_table[] = { { GNOME_RR_ROTATION_0, CSD_WACOM_ROTATION_NONE, "none" }, { GNOME_RR_ROTATION_90, CSD_WACOM_ROTATION_CCW, "ccw" }, { GNOME_RR_ROTATION_180, CSD_WACOM_ROTATION_HALF, "half" }, { GNOME_RR_ROTATION_270, CSD_WACOM_ROTATION_CW, "cw" } }; static WacomDeviceDatabase *db = NULL; struct CsdWacomStylusPrivate { CsdWacomDevice *device; int id; WacomStylusType type; char *name; const char *icon_name; GSettings *settings; gboolean has_eraser; int num_buttons; }; static void csd_wacom_stylus_class_init (CsdWacomStylusClass *klass); static void csd_wacom_stylus_init (CsdWacomStylus *wacom_stylus); static void csd_wacom_stylus_finalize (GObject *object); G_DEFINE_TYPE (CsdWacomStylus, csd_wacom_stylus, G_TYPE_OBJECT) static void csd_wacom_stylus_class_init (CsdWacomStylusClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_wacom_stylus_finalize; g_type_class_add_private (klass, sizeof (CsdWacomStylusPrivate)); } static void csd_wacom_stylus_init (CsdWacomStylus *stylus) { stylus->priv = CSD_WACOM_STYLUS_GET_PRIVATE (stylus); } static void csd_wacom_stylus_finalize (GObject *object) { CsdWacomStylus *stylus; CsdWacomStylusPrivate *p; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_WACOM_STYLUS (object)); stylus = CSD_WACOM_STYLUS (object); g_return_if_fail (stylus->priv != NULL); p = stylus->priv; if (p->settings != NULL) { g_object_unref (p->settings); p->settings = NULL; } g_free (p->name); p->name = NULL; G_OBJECT_CLASS (csd_wacom_stylus_parent_class)->finalize (object); } static const char * get_icon_name_from_type (WacomStylusType type) { switch (type) { case WSTYLUS_INKING: case WSTYLUS_STROKE: /* The stroke pen is the same as the inking pen with * a different nib */ return "wacom-stylus-inking"; case WSTYLUS_AIRBRUSH: return "wacom-stylus-airbrush"; case WSTYLUS_MARKER: return "wacom-stylus-art-pen"; case WSTYLUS_CLASSIC: return "wacom-stylus-classic"; default: return "wacom-stylus"; } } static CsdWacomStylus * csd_wacom_stylus_new (CsdWacomDevice *device, const WacomStylus *wstylus, GSettings *settings) { CsdWacomStylus *stylus; g_return_val_if_fail (G_IS_SETTINGS (settings), NULL); g_return_val_if_fail (wstylus != NULL, NULL); stylus = CSD_WACOM_STYLUS (g_object_new (CSD_TYPE_WACOM_STYLUS, NULL)); stylus->priv->device = device; stylus->priv->id = libwacom_stylus_get_id (wstylus); stylus->priv->name = g_strdup (libwacom_stylus_get_name (wstylus)); stylus->priv->settings = settings; stylus->priv->type = libwacom_stylus_get_type (wstylus); stylus->priv->icon_name = get_icon_name_from_type (stylus->priv->type); stylus->priv->has_eraser = libwacom_stylus_has_eraser (wstylus); stylus->priv->num_buttons = libwacom_stylus_get_num_buttons (wstylus); return stylus; } GSettings * csd_wacom_stylus_get_settings (CsdWacomStylus *stylus) { g_return_val_if_fail (CSD_IS_WACOM_STYLUS (stylus), NULL); return stylus->priv->settings; } const char * csd_wacom_stylus_get_name (CsdWacomStylus *stylus) { g_return_val_if_fail (CSD_IS_WACOM_STYLUS (stylus), NULL); return stylus->priv->name; } const char * csd_wacom_stylus_get_icon_name (CsdWacomStylus *stylus) { g_return_val_if_fail (CSD_IS_WACOM_STYLUS (stylus), NULL); return stylus->priv->icon_name; } CsdWacomDevice * csd_wacom_stylus_get_device (CsdWacomStylus *stylus) { g_return_val_if_fail (CSD_IS_WACOM_STYLUS (stylus), NULL); return stylus->priv->device; } gboolean csd_wacom_stylus_get_has_eraser (CsdWacomStylus *stylus) { g_return_val_if_fail (CSD_IS_WACOM_STYLUS (stylus), FALSE); return stylus->priv->has_eraser; } guint csd_wacom_stylus_get_num_buttons (CsdWacomStylus *stylus) { g_return_val_if_fail (CSD_IS_WACOM_STYLUS (stylus), -1); return stylus->priv->num_buttons; } CsdWacomStylusType csd_wacom_stylus_get_stylus_type (CsdWacomStylus *stylus) { g_return_val_if_fail (CSD_IS_WACOM_STYLUS (stylus), WACOM_STYLUS_TYPE_UNKNOWN); switch (stylus->priv->type) { case WSTYLUS_UNKNOWN: return WACOM_STYLUS_TYPE_UNKNOWN; case WSTYLUS_GENERAL: return WACOM_STYLUS_TYPE_GENERAL; case WSTYLUS_INKING: return WACOM_STYLUS_TYPE_INKING; case WSTYLUS_AIRBRUSH: return WACOM_STYLUS_TYPE_AIRBRUSH; case WSTYLUS_CLASSIC: return WACOM_STYLUS_TYPE_CLASSIC; case WSTYLUS_MARKER: return WACOM_STYLUS_TYPE_MARKER; case WSTYLUS_STROKE: return WACOM_STYLUS_TYPE_STROKE; case WSTYLUS_PUCK: return WACOM_STYLUS_TYPE_PUCK; default: g_assert_not_reached (); } return WACOM_STYLUS_TYPE_UNKNOWN; } int csd_wacom_stylus_get_id (CsdWacomStylus *stylus) { g_return_val_if_fail (CSD_IS_WACOM_STYLUS (stylus), -1); return stylus->priv->id; } /* Tablet buttons */ static CsdWacomTabletButton * csd_wacom_tablet_button_new (const char *name, const char *id, const char *settings_path, CsdWacomTabletButtonType type, CsdWacomTabletButtonPos pos, int group_id, int idx, int status_led) { CsdWacomTabletButton *ret; ret = g_new0 (CsdWacomTabletButton, 1); ret->name = g_strdup (name); ret->id = g_strdup (id); if (type != WACOM_TABLET_BUTTON_TYPE_HARDCODED) { char *button_settings_path; button_settings_path = g_strdup_printf ("%s%s/", settings_path, id); ret->settings = g_settings_new_with_path (WACOM_BUTTON_SCHEMA, button_settings_path); g_free (button_settings_path); } ret->group_id = group_id; ret->idx = idx; ret->type = type; ret->pos = pos; ret->status_led = status_led; return ret; } void csd_wacom_tablet_button_free (CsdWacomTabletButton *button) { g_return_if_fail (button != NULL); if (button->settings != NULL) g_object_unref (button->settings); g_free (button->name); g_free (button->id); g_free (button); } CsdWacomTabletButton * csd_wacom_tablet_button_copy (CsdWacomTabletButton *button) { CsdWacomTabletButton *ret; g_return_val_if_fail (button != NULL, NULL); ret = g_new0 (CsdWacomTabletButton, 1); ret->name = g_strdup (button->name); if (button->settings != NULL) ret->settings = g_object_ref (button->settings); ret->id = button->id; ret->type = button->type; ret->group_id = button->group_id; return ret; } #define CSD_WACOM_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_WACOM_DEVICE, CsdWacomDevicePrivate)) /* we support two types of settings: * Tablet-wide settings: applied to each tool on the tablet. e.g. rotation * Tool-specific settings: applied to one tool only. */ #define SETTINGS_WACOM_DIR "org.cinnamon.settings-daemon.peripherals.wacom" #define SETTINGS_STYLUS_DIR "stylus" #define SETTINGS_ERASER_DIR "eraser" struct CsdWacomDevicePrivate { GdkDevice *gdk_device; int device_id; int opcode; CsdWacomDeviceType type; char *name; char *path; char *machine_id; const char *icon_name; char *layout_path; char *tool_name; gboolean reversible; gboolean is_screen_tablet; gboolean is_isd; /* integrated system device */ gboolean is_fallback; GList *styli; CsdWacomStylus *last_stylus; GList *buttons; gint num_rings; gint num_strips; GHashTable *modes; /* key = int (group), value = int (index) */ GHashTable *num_modes; /* key = int (group), value = int (index) */ GSettings *wacom_settings; }; enum { PROP_0, PROP_GDK_DEVICE, PROP_LAST_STYLUS }; static void csd_wacom_device_class_init (CsdWacomDeviceClass *klass); static void csd_wacom_device_init (CsdWacomDevice *wacom_device); static void csd_wacom_device_finalize (GObject *object); G_DEFINE_TYPE (CsdWacomDevice, csd_wacom_device, G_TYPE_OBJECT) static GdkFilterReturn filter_events (XEvent *xevent, GdkEvent *event, CsdWacomDevice *device) { XIEvent *xiev; XIPropertyEvent *pev; XGenericEventCookie *cookie; char *name; int tool_id; /* verify we have a property event */ if (xevent->type != GenericEvent) return GDK_FILTER_CONTINUE; cookie = &xevent->xcookie; if (cookie->extension != device->priv->opcode) return GDK_FILTER_CONTINUE; xiev = (XIEvent *) xevent->xcookie.data; if (xiev->evtype != XI_PropertyEvent) return GDK_FILTER_CONTINUE; pev = (XIPropertyEvent *) xiev; /* Is the event for us? */ if (pev->deviceid != device->priv->device_id) return GDK_FILTER_CONTINUE; name = XGetAtomName (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), pev->property); if (name == NULL || g_strcmp0 (name, WACOM_SERIAL_IDS_PROP) != 0) { if (name) XFree (name); return GDK_FILTER_CONTINUE; } XFree (name); tool_id = xdevice_get_last_tool_id (device->priv->device_id); if (tool_id == -1) { g_warning ("Failed to get value for changed stylus ID on device '%d'", device->priv->device_id); return GDK_FILTER_CONTINUE; } csd_wacom_device_set_current_stylus (device, tool_id); return GDK_FILTER_CONTINUE; } static gboolean setup_property_notify (CsdWacomDevice *device) { Display *dpy; XIEventMask evmask; int tool_id; evmask.deviceid = device->priv->device_id; evmask.mask_len = XIMaskLen (XI_PropertyEvent); evmask.mask = g_new0 (guchar, evmask.mask_len); XISetMask (evmask.mask, XI_PropertyEvent); dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); XISelectEvents (dpy, DefaultRootWindow (dpy), &evmask, 1); g_free (evmask.mask); gdk_window_add_filter (NULL, (GdkFilterFunc) filter_events, device); tool_id = xdevice_get_last_tool_id (device->priv->device_id); if (tool_id == -1) { g_warning ("Failed to get value for changed stylus ID on device '%d", device->priv->device_id); return TRUE; } csd_wacom_device_set_current_stylus (device, tool_id); return TRUE; } static CsdWacomDeviceType get_device_type (XDeviceInfo *dev) { CsdWacomDeviceType ret; static Atom stylus, cursor, eraser, pad, touch, prop; XDevice *device; Atom realtype; int realformat; unsigned long nitems, bytes_after; unsigned char *data = NULL; int rc; ret = WACOM_TYPE_INVALID; if ((dev->use == IsXPointer) || (dev->use == IsXKeyboard)) return ret; if (!stylus) stylus = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "STYLUS", False); if (!eraser) eraser = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "ERASER", False); if (!cursor) cursor = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "CURSOR", False); if (!pad) pad = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "PAD", False); if (!touch) touch = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "TOUCH", False); if (!prop) prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Wacom Tool Type", False); if (dev->type == stylus) ret = WACOM_TYPE_STYLUS; else if (dev->type == eraser) ret = WACOM_TYPE_ERASER; else if (dev->type == cursor) ret = WACOM_TYPE_CURSOR; else if (dev->type == pad) ret = WACOM_TYPE_PAD; else if (dev->type == touch) ret = WACOM_TYPE_TOUCH; if (ret == WACOM_TYPE_INVALID) return ret; /* There is currently no good way of detecting the driver for a device * other than checking for a driver-specific property. * Wacom Tool Type exists on all tools */ gdk_x11_display_error_trap_push (gdk_display_get_default ()); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), dev->id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) || (device == NULL)) return ret; gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device, prop, 0, 1, False, XA_ATOM, &realtype, &realformat, &nitems, &bytes_after, &data); xdevice_close (device); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) || rc != Success || realtype == None) ret = WACOM_TYPE_INVALID; XFree (data); return ret; } /* Finds an output which matches the given EDID information. Any NULL * parameter will be interpreted to match any value. */ static GnomeRROutput * find_output_by_edid (GnomeRRScreen *rr_screen, const gchar *vendor, const gchar *product, const gchar *serial) { GnomeRROutput **rr_outputs; GnomeRROutput *retval = NULL; guint i; rr_outputs = gnome_rr_screen_list_outputs (rr_screen); for (i = 0; rr_outputs[i] != NULL; i++) { gchar *o_vendor_s; gchar *o_product_s; int o_product; gchar *o_serial_s; int o_serial; gboolean match; if (!gnome_rr_output_is_connected (rr_outputs[i])) continue; if (!gnome_rr_output_get_ids_from_edid (rr_outputs[i], &o_vendor_s, &o_product, &o_serial)) continue; o_product_s = g_strdup_printf ("%d", o_product); o_serial_s = g_strdup_printf ("%d", o_serial); g_debug ("Checking for match between '%s','%s','%s' and '%s','%s','%s'", \ vendor, product, serial, o_vendor_s, o_product_s, o_serial_s); match = (vendor == NULL || g_strcmp0 (vendor, o_vendor_s) == 0) && \ (product == NULL || g_strcmp0 (product, o_product_s) == 0) && \ (serial == NULL || g_strcmp0 (serial, o_serial_s) == 0); g_free (o_vendor_s); g_free (o_product_s); g_free (o_serial_s); if (match) { retval = rr_outputs[i]; break; } } if (retval == NULL) g_debug ("Did not find a matching output for EDID '%s,%s,%s'", vendor, product, serial); return retval; } static GnomeRROutput* find_builtin_output (GnomeRRScreen *rr_screen) { GnomeRROutput **rr_outputs; GnomeRROutput *retval = NULL; guint i; rr_outputs = gnome_rr_screen_list_outputs (rr_screen); for (i = 0; rr_outputs[i] != NULL; i++) { if (!gnome_rr_output_is_connected (rr_outputs[i])) continue; if (gnome_rr_output_is_laptop(rr_outputs[i])) { retval = rr_outputs[i]; break; } } if (retval == NULL) g_debug ("Did not find a built-in monitor"); return retval; } static GnomeRROutput * find_output_by_heuristic (GnomeRRScreen *rr_screen, CsdWacomDevice *device) { GnomeRROutput *rr_output; /* TODO: This heuristic will fail for non-Wacom display * tablets and may give the wrong result if multiple Wacom * display tablets are connected. */ rr_output = find_output_by_edid (rr_screen, "WAC", NULL, NULL); if (!rr_output) rr_output = find_builtin_output (rr_screen); return rr_output; } static GnomeRROutput * find_output_by_display (GnomeRRScreen *rr_screen, CsdWacomDevice *device) { gsize n; GSettings *tablet; GVariant *display; const gchar **edid; GnomeRROutput *ret; if (device == NULL) return NULL; ret = NULL; tablet = device->priv->wacom_settings; display = g_settings_get_value (tablet, "display"); edid = g_variant_get_strv (display, &n); if (n != 3) { g_critical ("Expected 'display' key to store %d values; got %"G_GSIZE_FORMAT".", 3, n); goto out; } if (strlen (edid[0]) == 0 || strlen (edid[1]) == 0 || strlen (edid[2]) == 0) goto out; ret = find_output_by_edid (rr_screen, edid[0], edid[1], edid[2]); out: g_free (edid); g_variant_unref (display); return ret; } static gboolean is_on (GnomeRROutput *output) { GnomeRRCrtc *crtc; crtc = gnome_rr_output_get_crtc (output); if (!crtc) return FALSE; return gnome_rr_crtc_get_current_mode (crtc) != NULL; } static GnomeRROutput * find_output_by_monitor (GnomeRRScreen *rr_screen, GdkScreen *screen, int monitor) { GnomeRROutput **rr_outputs; GnomeRROutput *ret; guint i; ret = NULL; rr_outputs = gnome_rr_screen_list_outputs (rr_screen); for (i = 0; rr_outputs[i] != NULL; i++) { GnomeRROutput *rr_output; GnomeRRCrtc *crtc; int x, y; rr_output = rr_outputs[i]; if (!is_on (rr_output)) continue; crtc = gnome_rr_output_get_crtc (rr_output); if (!crtc) continue; gnome_rr_crtc_get_position (crtc, &x, &y); if (monitor == gdk_screen_get_monitor_at_point (screen, x, y)) { ret = rr_output; break; } } if (ret == NULL) g_warning ("No output found for monitor %d.", monitor); return ret; } static void set_display_by_output (CsdWacomDevice *device, GnomeRROutput *rr_output) { GSettings *tablet; GVariant *c_array; GVariant *n_array; gsize nvalues; gchar *o_vendor_s, *o_product_s, *o_serial_s; int o_product, o_serial; const gchar *values[3]; const gchar **unused_variant; tablet = csd_wacom_device_get_settings (device); c_array = g_settings_get_value (tablet, "display"); unused_variant = g_variant_get_strv (c_array, &nvalues); /* these arrays aren't used, only nvalues is */ g_free (unused_variant); g_variant_unref (c_array); if (nvalues != 3) { g_warning ("Unable set set display property. Got %"G_GSIZE_FORMAT" items; expected %d items.\n", nvalues, 4); return; } if (rr_output == NULL || !gnome_rr_output_get_ids_from_edid (rr_output, &o_vendor_s, &o_product, &o_serial)) { o_vendor_s = g_strdup (""); o_product_s = g_strdup (""); o_serial_s = g_strdup (""); } else { o_product_s = g_strdup_printf ("%d", o_product); o_serial_s = g_strdup_printf ("%d", o_serial); } values[0] = o_vendor_s; values[1] = o_product_s; values[2] = o_serial_s; n_array = g_variant_new_strv ((const gchar * const *) &values, 3); g_settings_set_value (tablet, "display", n_array); g_free (o_vendor_s); g_free (o_product_s); g_free (o_serial_s); } static CsdWacomRotation get_rotation_wacom (GnomeRRRotation rotation) { guint i; for (i = 0; i < G_N_ELEMENTS (rotation_table); i++) { if (rotation_table[i].rotation & rotation) return (rotation_table[i].rotation_wacom); } g_assert_not_reached (); } void csd_wacom_device_set_display (CsdWacomDevice *device, int monitor) { GError *error = NULL; GnomeRRScreen *rr_screen; GnomeRROutput *output = NULL; g_return_if_fail (CSD_IS_WACOM_DEVICE (device)); rr_screen = gnome_rr_screen_new (gdk_screen_get_default (), &error); if (rr_screen == NULL) { g_warning ("Failed to create GnomeRRScreen: %s", error->message); g_error_free (error); return; } if (monitor > CSD_WACOM_SET_ALL_MONITORS) output = find_output_by_monitor (rr_screen, gdk_screen_get_default (), monitor); set_display_by_output (device, output); g_object_unref (rr_screen); } static GnomeRROutput * find_output (GnomeRRScreen *rr_screen, CsdWacomDevice *device) { GnomeRROutput *rr_output; rr_output = find_output_by_display (rr_screen, device); if (rr_output == NULL) { if (csd_wacom_device_is_screen_tablet (device)) { rr_output = find_output_by_heuristic (rr_screen, device); if (rr_output == NULL) g_warning ("No fuzzy match based on heuristics was found."); else g_warning ("Automatically mapping tablet to heuristically-found display."); } } return rr_output; } static void calculate_transformation_matrix (const GdkRectangle mapped, const GdkRectangle desktop, float matrix[NUM_ELEMS_MATRIX]) { float x_scale = (float)mapped.x / desktop.width; float y_scale = (float)mapped.y / desktop.height; float width_scale = (float)mapped.width / desktop.width; float height_scale = (float)mapped.height / desktop.height; matrix[0] = width_scale; matrix[1] = 0.0f; matrix[2] = x_scale; matrix[3] = 0.0f; matrix[4] = height_scale; matrix[5] = y_scale; matrix[6] = 0.0f; matrix[7] = 0.0f; matrix[8] = 1.0f; g_debug ("Matrix is %f,%f,%f,%f,%f,%f,%f,%f,%f.", matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6], matrix[7], matrix[8]); return; } int csd_wacom_device_get_display_monitor (CsdWacomDevice *device) { GError *error = NULL; GnomeRRScreen *rr_screen; GnomeRROutput *rr_output; GnomeRRMode *mode; GnomeRRCrtc *crtc; gint area[4]; g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), CSD_WACOM_SET_ALL_MONITORS); rr_screen = gnome_rr_screen_new (gdk_screen_get_default (), &error); if (rr_screen == NULL) { g_warning ("Failed to create GnomeRRScreen: %s", error->message); g_error_free (error); return CSD_WACOM_SET_ALL_MONITORS; } rr_output = find_output (rr_screen, device); if (rr_output == NULL) { g_object_unref (rr_screen); return CSD_WACOM_SET_ALL_MONITORS; } if (!is_on (rr_output)) { g_warning ("Output is not active."); g_object_unref (rr_screen); return CSD_WACOM_SET_ALL_MONITORS; } crtc = gnome_rr_output_get_crtc (rr_output); gnome_rr_crtc_get_position (crtc, &area[0], &area[1]); mode = gnome_rr_crtc_get_current_mode (crtc); area[2] = gnome_rr_mode_get_width (mode); area[3] = gnome_rr_mode_get_height (mode); g_object_unref (rr_screen); if (area[2] <= 0 || area[3] <= 0) { g_warning ("Output has non-positive area."); return CSD_WACOM_SET_ALL_MONITORS; } g_debug ("Area: %d,%d %dx%d", area[0], area[1], area[2], area[3]); return gdk_screen_get_monitor_at_point (gdk_screen_get_default (), area[0], area[1]); } gboolean csd_wacom_device_get_display_matrix (CsdWacomDevice *device, float matrix[NUM_ELEMS_MATRIX]) { int monitor; GdkRectangle display; GdkRectangle desktop; GdkScreen *screen = gdk_screen_get_default (); matrix[0] = 1.0f; matrix[1] = 0.0f; matrix[2] = 0.0f; matrix[3] = 0.0f; matrix[4] = 1.0f; matrix[5] = 0.0f; matrix[6] = 0.0f; matrix[7] = 0.0f; matrix[8] = 1.0f; monitor = csd_wacom_device_get_display_monitor (device); if (monitor < 0) return FALSE; desktop.x = 0; desktop.y = 0; desktop.width = gdk_screen_get_width (screen); desktop.height = gdk_screen_get_height (screen); gdk_screen_get_monitor_geometry (screen, monitor, &display); calculate_transformation_matrix (display, desktop, matrix); return TRUE; } CsdWacomRotation csd_wacom_device_get_display_rotation (CsdWacomDevice *device) { GError *error = NULL; GnomeRRScreen *rr_screen; GnomeRROutput *rr_output; GnomeRRRotation rotation = GNOME_RR_ROTATION_0; rr_screen = gnome_rr_screen_new (gdk_screen_get_default (), &error); if (rr_screen == NULL) { g_warning ("Failed to create GnomeRRScreen: %s", error->message); g_error_free (error); return CSD_WACOM_ROTATION_NONE; } rr_output = find_output (rr_screen, device); if (rr_output) { GnomeRRCrtc *crtc = gnome_rr_output_get_crtc (rr_output); if (crtc) rotation = gnome_rr_crtc_get_current_rotation (crtc); } g_object_unref (rr_screen); return get_rotation_wacom (rotation); } static void add_stylus_to_device (CsdWacomDevice *device, const char *settings_path, int id) { const WacomStylus *wstylus; wstylus = libwacom_stylus_get_for_id (db, id); if (wstylus) { CsdWacomStylus *stylus; char *stylus_settings_path; GSettings *settings; if (device->priv->type == WACOM_TYPE_STYLUS && libwacom_stylus_is_eraser (wstylus)) return; if (device->priv->type == WACOM_TYPE_ERASER && libwacom_stylus_is_eraser (wstylus) == FALSE) return; stylus_settings_path = g_strdup_printf ("%s0x%x/", settings_path, id); if (device->priv->type == WACOM_TYPE_STYLUS) { settings = g_settings_new_with_path (WACOM_STYLUS_SCHEMA, stylus_settings_path); stylus = csd_wacom_stylus_new (device, wstylus, settings); } else { settings = g_settings_new_with_path (WACOM_ERASER_SCHEMA, stylus_settings_path); stylus = csd_wacom_stylus_new (device, wstylus, settings); } g_free (stylus_settings_path); device->priv->styli = g_list_prepend (device->priv->styli, stylus); } } int csd_wacom_device_get_num_modes (CsdWacomDevice *device, int group_id) { int num_modes; g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), -1); num_modes = GPOINTER_TO_INT (g_hash_table_lookup (device->priv->num_modes, GINT_TO_POINTER(group_id))); return num_modes; } int csd_wacom_device_get_current_mode (CsdWacomDevice *device, int group_id) { int current_idx; g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), -1); current_idx = GPOINTER_TO_INT (g_hash_table_lookup (device->priv->modes, GINT_TO_POINTER(group_id))); /* That means that the mode doesn't exist, see csd_wacom_device_add_modes() */ g_return_val_if_fail (current_idx != 0, -1); return current_idx; } int csd_wacom_device_set_next_mode (CsdWacomDevice *device, CsdWacomTabletButton *button) { GList *l; int current_idx; int num_modes; int num_switches; int group_id; g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), -1); group_id = button->group_id; current_idx = 0; num_switches = 0; num_modes = GPOINTER_TO_INT (g_hash_table_lookup (device->priv->num_modes, GINT_TO_POINTER(group_id))); /* * Check if we have multiple mode-switch buttons for that * group, and if so, compute the current index based on * the position in the list... */ for (l = device->priv->buttons; l != NULL; l = l->next) { CsdWacomTabletButton *b = l->data; if (b->type != WACOM_TABLET_BUTTON_TYPE_HARDCODED) continue; if (button->group_id == b->group_id) num_switches++; if (g_strcmp0 (button->id, b->id) == 0) current_idx = num_switches; } /* We should at least have found the current mode-switch button... * If not, then it means that the given button is not a valid * mode-switch. */ g_return_val_if_fail (num_switches != 0, -1); /* Only one mode-switch? cycle through the modes */ if (num_switches == 1) { current_idx = csd_wacom_device_get_current_mode (device, group_id); /* csd_wacom_device_get_current_mode() returns -1 when the mode doesn't exist */ g_return_val_if_fail (current_idx > 0, -1); current_idx++; } if (current_idx > num_modes) current_idx = 1; g_hash_table_insert (device->priv->modes, GINT_TO_POINTER (group_id), GINT_TO_POINTER (current_idx)); return current_idx; } static int flags_to_group (WacomButtonFlags flags) { if (flags & WACOM_BUTTON_RING_MODESWITCH) return 1; if (flags & WACOM_BUTTON_RING2_MODESWITCH) return 2; if (flags & WACOM_BUTTON_TOUCHSTRIP_MODESWITCH) return 3; if (flags & WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH) return 4; return 0; } static GList * csd_wacom_device_add_ring_modes (WacomDevice *wacom_device, const char *settings_path, WacomButtonFlags direction) { GList *l; guint num_modes; guint group; guint i; char *name, *id; l = NULL; if ((direction & WACOM_BUTTON_POSITION_LEFT) && libwacom_has_ring (wacom_device)) { num_modes = libwacom_get_ring_num_modes (wacom_device); group = flags_to_group (WACOM_BUTTON_RING_MODESWITCH); if (num_modes == 0) { /* If no mode is available, we use "left-ring-mode-1" for backward compat */ l = g_list_append (l, csd_wacom_tablet_button_new (_("Left Ring"), "left-ring-mode-1", settings_path, WACOM_TABLET_BUTTON_TYPE_RING, WACOM_TABLET_BUTTON_POS_LEFT, group, 0, CSD_WACOM_NO_LED)); } else { for (i = 1; i <= num_modes; i++) { name = g_strdup_printf (_("Left Ring Mode #%d"), i); id = g_strdup_printf ("left-ring-mode-%d", i); l = g_list_append (l, csd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_RING, WACOM_TABLET_BUTTON_POS_LEFT, group, i - 1, CSD_WACOM_NO_LED)); g_free (name); g_free (id); } } } else if ((direction & WACOM_BUTTON_POSITION_RIGHT) && libwacom_has_ring2 (wacom_device)) { num_modes = libwacom_get_ring2_num_modes (wacom_device); group = flags_to_group (WACOM_BUTTON_RING2_MODESWITCH); if (num_modes == 0) { /* If no mode is available, we use "right-ring-mode-1" for backward compat */ l = g_list_append (l, csd_wacom_tablet_button_new (_("Right Ring"), "right-ring-mode-1", settings_path, WACOM_TABLET_BUTTON_TYPE_RING, WACOM_TABLET_BUTTON_POS_RIGHT, group, 0, CSD_WACOM_NO_LED)); } else { for (i = 1; i <= num_modes; i++) { name = g_strdup_printf (_("Right Ring Mode #%d"), i); id = g_strdup_printf ("right-ring-mode-%d", i); l = g_list_append (l, csd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_RING, WACOM_TABLET_BUTTON_POS_RIGHT, group, i - 1, CSD_WACOM_NO_LED)); g_free (name); g_free (id); } } } return l; } static GList * csd_wacom_device_add_strip_modes (WacomDevice *wacom_device, const char *settings_path, WacomButtonFlags direction) { GList *l; guint num_modes; guint num_strips; guint group; guint i; char *name, *id; l = NULL; num_strips = libwacom_get_num_strips (wacom_device); if (num_strips > 2) g_warning ("Unhandled number of touchstrips: %d", num_strips); if ((direction & WACOM_BUTTON_POSITION_LEFT) && num_strips >= 1) { num_modes = libwacom_get_strips_num_modes (wacom_device); group = flags_to_group (WACOM_BUTTON_TOUCHSTRIP_MODESWITCH); if (num_modes == 0) { /* If no mode is available, we use "left-strip-mode-1" for backward compat */ l = g_list_append (l, csd_wacom_tablet_button_new (_("Left Touchstrip"), "left-strip-mode-1", settings_path, WACOM_TABLET_BUTTON_TYPE_STRIP, WACOM_TABLET_BUTTON_POS_LEFT, group, 0, CSD_WACOM_NO_LED)); } else { for (i = 1; i <= num_modes; i++) { name = g_strdup_printf (_("Left Touchstrip Mode #%d"), i); id = g_strdup_printf ("left-strip-mode-%d", i); l = g_list_append (l, csd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_STRIP, WACOM_TABLET_BUTTON_POS_LEFT, group, i - 1, CSD_WACOM_NO_LED)); g_free (name); g_free (id); } } } else if ((direction & WACOM_BUTTON_POSITION_RIGHT) && num_strips >= 2) { num_modes = libwacom_get_strips_num_modes (wacom_device); group = flags_to_group (WACOM_BUTTON_TOUCHSTRIP2_MODESWITCH); if (num_modes == 0) { /* If no mode is available, we use "right-strip-mode-1" for backward compat */ l = g_list_append (l, csd_wacom_tablet_button_new (_("Right Touchstrip"), "right-strip-mode-1", settings_path, WACOM_TABLET_BUTTON_TYPE_STRIP, WACOM_TABLET_BUTTON_POS_RIGHT, group, 0, CSD_WACOM_NO_LED)); } else { for (i = 1; i <= num_modes; i++) { name = g_strdup_printf (_("Right Touchstrip Mode #%d"), i); id = g_strdup_printf ("right-strip-mode-%d", i); l = g_list_append (l, csd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_STRIP, WACOM_TABLET_BUTTON_POS_RIGHT, group, i - 1, CSD_WACOM_NO_LED)); g_free (name); g_free (id); } } } return l; } static char * csd_wacom_device_modeswitch_name (WacomButtonFlags flags, guint button_num) { if (flags & WACOM_BUTTON_RINGS_MODESWITCH) { if (flags & WACOM_BUTTON_POSITION_LEFT) return g_strdup_printf (_("Left Touchring Mode Switch")); else return g_strdup_printf (_("Right Touchring Mode Switch")); } else if (flags & WACOM_BUTTON_TOUCHSTRIPS_MODESWITCH) { if (flags & WACOM_BUTTON_POSITION_LEFT) return g_strdup_printf (_("Left Touchstrip Mode Switch")); else return g_strdup_printf (_("Right Touchstrip Mode Switch")); } g_warning ("Unhandled modeswitch and direction combination"); return g_strdup_printf (_("Mode Switch #%d"), button_num); } static CsdWacomTabletButtonType csd_wacom_device_button_pos (WacomButtonFlags flags) { if (flags & WACOM_BUTTON_POSITION_LEFT) return WACOM_TABLET_BUTTON_POS_LEFT; else if (flags & WACOM_BUTTON_POSITION_RIGHT) return WACOM_TABLET_BUTTON_POS_RIGHT; else if (flags & WACOM_BUTTON_POSITION_TOP) return WACOM_TABLET_BUTTON_POS_TOP; else if (flags & WACOM_BUTTON_POSITION_BOTTOM) return WACOM_TABLET_BUTTON_POS_BOTTOM; g_warning ("Unhandled button position"); return WACOM_TABLET_BUTTON_POS_UNDEF; } static GList * csd_wacom_device_add_buttons_dir (WacomDevice *wacom_device, const char *settings_path, WacomButtonFlags direction, const char *button_str, const char *button_str_id) { GList *l; guint num_buttons, i, button_num; char *name, *id; l = NULL; button_num = 1; num_buttons = libwacom_get_num_buttons (wacom_device); for (i = 'A'; i < 'A' + num_buttons; i++) { WacomButtonFlags flags; flags = libwacom_get_button_flag (wacom_device, i); if (!(flags & direction)) continue; /* Ignore mode switches */ if (flags & WACOM_BUTTON_MODESWITCH) continue; name = g_strdup_printf (button_str, button_num++); id = g_strdup_printf ("%s%c", button_str_id, i); l = g_list_append (l, csd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_NORMAL, csd_wacom_device_button_pos (flags), flags_to_group (flags), -1, CSD_WACOM_NO_LED)); g_free (name); g_free (id); } /* Handle modeswitches */ for (i = 'A'; i < 'A' + num_buttons; i++) { WacomButtonFlags flags; char *name, *id; int status_led; flags = libwacom_get_button_flag (wacom_device, i); if (!(flags & direction)) continue; /* Ignore non-mode switches */ if (!(flags & WACOM_BUTTON_MODESWITCH)) continue; name = csd_wacom_device_modeswitch_name (flags, button_num++); id = g_strdup_printf ("%s%c", button_str_id, i); status_led = libwacom_get_button_led_group (wacom_device, i); l = g_list_append (l, csd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_HARDCODED, csd_wacom_device_button_pos (flags), flags_to_group (flags), -1, status_led)); g_free (name); g_free (id); } /* Handle touch{strips,rings} */ if (libwacom_has_ring2 (wacom_device) || libwacom_has_ring (wacom_device)) l = g_list_concat (l, csd_wacom_device_add_ring_modes (wacom_device, settings_path, direction)); if (libwacom_get_num_strips (wacom_device) > 0) l = g_list_concat (l, csd_wacom_device_add_strip_modes (wacom_device, settings_path, direction)); return l; } static void csd_wacom_device_add_buttons (CsdWacomDevice *device, WacomDevice *wacom_device, const char *settings_path) { GList *l, *ret; ret = NULL; l = csd_wacom_device_add_buttons_dir (wacom_device, settings_path, WACOM_BUTTON_POSITION_LEFT, _("Left Button #%d"), "button"); if (l) ret = l; l = csd_wacom_device_add_buttons_dir (wacom_device, settings_path, WACOM_BUTTON_POSITION_RIGHT, _("Right Button #%d"), "button"); if (l) ret = g_list_concat (ret, l); l = csd_wacom_device_add_buttons_dir (wacom_device, settings_path, WACOM_BUTTON_POSITION_TOP, _("Top Button #%d"), "button"); if (l) ret = g_list_concat (ret, l); l = csd_wacom_device_add_buttons_dir (wacom_device, settings_path, WACOM_BUTTON_POSITION_BOTTOM, _("Bottom Button #%d"), "button"); if (l) ret = g_list_concat (ret, l); device->priv->buttons = ret; } static void csd_wacom_device_get_modeswitches (WacomDevice *wacom_device, gint *num_rings, gint *num_strips) { *num_strips = libwacom_get_num_strips (wacom_device); if (libwacom_has_ring2 (wacom_device)) *num_rings = 2; else if (libwacom_has_ring (wacom_device)) *num_rings = 1; else *num_rings = 0; } static void csd_wacom_device_add_modes (CsdWacomDevice *device, WacomDevice *wacom_device) { GList *l; device->priv->modes = g_hash_table_new (g_direct_hash, g_direct_equal); device->priv->num_modes = g_hash_table_new (g_direct_hash, g_direct_equal); for (l = device->priv->buttons; l != NULL; l = l->next) { CsdWacomTabletButton *button = l->data; if (button->group_id > 0) g_hash_table_insert (device->priv->modes, GINT_TO_POINTER (button->group_id), GINT_TO_POINTER (1)); /* See flags_to_group() for group ID/button type matches */ if (button->group_id == 1) { g_hash_table_insert (device->priv->num_modes, GINT_TO_POINTER (button->group_id), GINT_TO_POINTER (libwacom_get_ring_num_modes (wacom_device))); } else if (button->group_id == 2) { g_hash_table_insert (device->priv->num_modes, GINT_TO_POINTER (button->group_id), GINT_TO_POINTER (libwacom_get_ring2_num_modes (wacom_device))); } else if (button->group_id == 3 || button->group_id == 4) { g_hash_table_insert (device->priv->num_modes, GINT_TO_POINTER (button->group_id), GINT_TO_POINTER (libwacom_get_strips_num_modes (wacom_device))); } } } static void csd_wacom_device_update_from_db (CsdWacomDevice *device, WacomDevice *wacom_device, const char *identifier) { char *settings_path; WacomIntegrationFlags integration_flags; settings_path = g_strdup_printf (WACOM_DEVICE_CONFIG_BASE, device->priv->machine_id, libwacom_get_match (wacom_device)); device->priv->wacom_settings = g_settings_new_with_path (WACOM_TABLET_SCHEMA, settings_path); device->priv->name = g_strdup (libwacom_get_name (wacom_device)); device->priv->layout_path = g_strdup (libwacom_get_layout_filename (wacom_device)); device->priv->reversible = libwacom_is_reversible (wacom_device); integration_flags = libwacom_get_integration_flags (wacom_device); device->priv->is_screen_tablet = (integration_flags & WACOM_DEVICE_INTEGRATED_DISPLAY); device->priv->is_isd = (integration_flags & WACOM_DEVICE_INTEGRATED_SYSTEM); if (device->priv->is_screen_tablet) { if (!device->priv->is_isd) device->priv->icon_name = "wacom-tablet-cintiq"; else device->priv->icon_name = "wacom-tablet-pc"; } else { device->priv->icon_name = "wacom-tablet"; } if (device->priv->type == WACOM_TYPE_PAD) { csd_wacom_device_get_modeswitches (wacom_device, &device->priv->num_rings, &device->priv->num_strips); csd_wacom_device_add_buttons (device, wacom_device, settings_path); csd_wacom_device_add_modes (device, wacom_device); } if (device->priv->type == WACOM_TYPE_STYLUS || device->priv->type == WACOM_TYPE_ERASER) { const int *ids; int num_styli; guint i; ids = libwacom_get_supported_styli (wacom_device, &num_styli); g_assert (num_styli >= 1); for (i = 0; i < num_styli; i++) add_stylus_to_device (device, settings_path, ids[i]); device->priv->styli = g_list_reverse (device->priv->styli); } g_free (settings_path); } static GObject * csd_wacom_device_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdWacomDevice *device; GdkDeviceManager *device_manager; XDeviceInfo *device_info; WacomDevice *wacom_device; int n_devices; guint i; device = CSD_WACOM_DEVICE (G_OBJECT_CLASS (csd_wacom_device_parent_class)->constructor (type, n_construct_properties, construct_properties)); if (device->priv->gdk_device == NULL) return G_OBJECT (device); device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); g_object_get (device_manager, "opcode", &device->priv->opcode, NULL); g_object_get (device->priv->gdk_device, "device-id", &device->priv->device_id, NULL); device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) { g_warning ("Could not list any input devices through XListInputDevices()"); goto end; } for (i = 0; i < n_devices; i++) { if (device_info[i].id == device->priv->device_id) { device->priv->type = get_device_type (&device_info[i]); device->priv->tool_name = g_strdup (device_info[i].name); break; } } XFreeDeviceList (device_info); if (device->priv->type == WACOM_TYPE_INVALID) goto end; device->priv->path = xdevice_get_device_node (device->priv->device_id); if (device->priv->path == NULL) { g_warning ("Could not get the device node path for ID '%d'", device->priv->device_id); device->priv->type = WACOM_TYPE_INVALID; goto end; } if (db == NULL) db = libwacom_database_new (); wacom_device = libwacom_new_from_path (db, device->priv->path, FALSE, NULL); if (!wacom_device) { WacomError *wacom_error; g_debug ("Creating fallback driver for wacom tablet '%s' ('%s')", gdk_device_get_name (device->priv->gdk_device), device->priv->path); device->priv->is_fallback = TRUE; wacom_error = libwacom_error_new (); wacom_device = libwacom_new_from_path (db, device->priv->path, TRUE, wacom_error); if (wacom_device == NULL) { g_warning ("Failed to create fallback wacom device for '%s': %s (%d)", device->priv->path, libwacom_error_get_message (wacom_error), libwacom_error_get_code (wacom_error)); libwacom_error_free (&wacom_error); device->priv->type = WACOM_TYPE_INVALID; goto end; } } csd_wacom_device_update_from_db (device, wacom_device, device->priv->path); libwacom_destroy (wacom_device); if (device->priv->type == WACOM_TYPE_STYLUS || device->priv->type == WACOM_TYPE_ERASER) { setup_property_notify (device); } end: return G_OBJECT (device); } static void csd_wacom_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsdWacomDevice *device; device = CSD_WACOM_DEVICE (object); switch (prop_id) { case PROP_GDK_DEVICE: device->priv->gdk_device = g_value_get_pointer (value); break; case PROP_LAST_STYLUS: device->priv->last_stylus = g_value_get_pointer (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_wacom_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdWacomDevice *device; device = CSD_WACOM_DEVICE (object); switch (prop_id) { case PROP_GDK_DEVICE: g_value_set_pointer (value, device->priv->gdk_device); break; case PROP_LAST_STYLUS: g_value_set_pointer (value, device->priv->last_stylus); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_wacom_device_class_init (CsdWacomDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_wacom_device_constructor; object_class->finalize = csd_wacom_device_finalize; object_class->set_property = csd_wacom_device_set_property; object_class->get_property = csd_wacom_device_get_property; g_type_class_add_private (klass, sizeof (CsdWacomDevicePrivate)); g_object_class_install_property (object_class, PROP_GDK_DEVICE, g_param_spec_pointer ("gdk-device", "gdk-device", "gdk-device", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_LAST_STYLUS, g_param_spec_pointer ("last-stylus", "last-stylus", "last-stylus", G_PARAM_READWRITE)); } static void csd_wacom_device_init (CsdWacomDevice *device) { device->priv = CSD_WACOM_DEVICE_GET_PRIVATE (device); device->priv->type = WACOM_TYPE_INVALID; if (g_file_get_contents ("/etc/machine-id", &device->priv->machine_id, NULL, NULL) == FALSE) if (g_file_get_contents ("/var/lib/dbus/machine-id", &device->priv->machine_id, NULL, NULL) == FALSE) device->priv->machine_id = g_strdup ("00000000000000000000000000000000"); device->priv->machine_id = g_strstrip (device->priv->machine_id); } static void csd_wacom_device_finalize (GObject *object) { CsdWacomDevice *device; CsdWacomDevicePrivate *p; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_WACOM_DEVICE (object)); device = CSD_WACOM_DEVICE (object); g_return_if_fail (device->priv != NULL); p = device->priv; if (p->wacom_settings != NULL) { g_object_unref (p->wacom_settings); p->wacom_settings = NULL; } g_list_foreach (p->styli, (GFunc) g_object_unref, NULL); g_list_free (p->styli); g_list_foreach (p->buttons, (GFunc) csd_wacom_tablet_button_free, NULL); g_list_free (p->buttons); g_free (p->name); p->name = NULL; g_free (p->tool_name); p->tool_name = NULL; g_free (p->path); p->path = NULL; g_free (p->machine_id); p->machine_id = NULL; if (p->modes) { g_hash_table_destroy (p->modes); p->modes = NULL; } if (p->num_modes) { g_hash_table_destroy (p->num_modes); p->num_modes = NULL; } g_clear_pointer (&p->layout_path, g_free); gdk_window_remove_filter (NULL, (GdkFilterFunc) filter_events, device); G_OBJECT_CLASS (csd_wacom_device_parent_class)->finalize (object); } CsdWacomDevice * csd_wacom_device_new (GdkDevice *device) { return CSD_WACOM_DEVICE (g_object_new (CSD_TYPE_WACOM_DEVICE, "gdk-device", device, NULL)); } GList * csd_wacom_device_list_styli (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), NULL); return g_list_copy (device->priv->styli); } CsdWacomStylus * csd_wacom_device_get_stylus_for_type (CsdWacomDevice *device, CsdWacomStylusType type) { GList *l; g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), NULL); for (l = device->priv->styli; l != NULL; l = l->next) { CsdWacomStylus *stylus = l->data; if (csd_wacom_stylus_get_stylus_type (stylus) == type) return stylus; } return NULL; } const char * csd_wacom_device_get_name (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), NULL); return device->priv->name; } const char * csd_wacom_device_get_layout_path (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), NULL); return device->priv->layout_path; } const char * csd_wacom_device_get_path (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), NULL); return device->priv->path; } const char * csd_wacom_device_get_icon_name (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), NULL); return device->priv->icon_name; } const char * csd_wacom_device_get_tool_name (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), NULL); return device->priv->tool_name; } gboolean csd_wacom_device_reversible (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), FALSE); return device->priv->reversible; } gboolean csd_wacom_device_is_screen_tablet (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), FALSE); return device->priv->is_screen_tablet; } gboolean csd_wacom_device_is_isd (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), FALSE); return device->priv->is_isd; } gboolean csd_wacom_device_is_fallback (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), FALSE); return device->priv->is_fallback; } gint csd_wacom_device_get_num_strips (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), 0); return device->priv->num_strips; } gint csd_wacom_device_get_num_rings (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), 0); return device->priv->num_rings; } GSettings * csd_wacom_device_get_settings (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), NULL); return device->priv->wacom_settings; } void csd_wacom_device_set_current_stylus (CsdWacomDevice *device, int stylus_id) { GList *l; CsdWacomStylus *stylus; g_return_if_fail (CSD_IS_WACOM_DEVICE (device)); /* Don't change anything if the stylus is already set */ if (device->priv->last_stylus != NULL) { CsdWacomStylus *stylus = device->priv->last_stylus; if (stylus->priv->id == stylus_id) return; } for (l = device->priv->styli; l; l = l->next) { stylus = l->data; /* Set a nice default if 0x0 */ if (stylus_id == 0x0 && stylus->priv->type == WSTYLUS_GENERAL) { g_object_set (device, "last-stylus", stylus, NULL); return; } if (stylus->priv->id == stylus_id) { g_object_set (device, "last-stylus", stylus, NULL); return; } } /* Setting the default stylus to be the generic one */ for (l = device->priv->styli; l; l = l->next) { stylus = l->data; /* Set a nice default if 0x0 */ if (stylus->priv->type == WSTYLUS_GENERAL) { g_debug ("Could not find stylus ID 0x%x for tablet '%s', setting general pen ID 0x%x instead", stylus_id, device->priv->name, stylus->priv->id); g_object_set (device, "last-stylus", stylus, NULL); return; } } g_warning ("Could not set the current stylus ID 0x%x for tablet '%s', no general pen found", stylus_id, device->priv->name); /* Setting the default stylus to be the first one */ g_return_if_fail (device->priv->styli != NULL); stylus = device->priv->styli->data; g_object_set (device, "last-stylus", stylus, NULL); } CsdWacomDeviceType csd_wacom_device_get_device_type (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), WACOM_TYPE_INVALID); return device->priv->type; } gint * csd_wacom_device_get_area (CsdWacomDevice *device) { int i, id; XDevice *xdevice; Atom area, realtype; int rc, realformat; unsigned long nitems, bytes_after; unsigned char *data = NULL; gint *device_area; g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), NULL); g_object_get (device->priv->gdk_device, "device-id", &id, NULL); area = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Wacom Tablet Area", False); gdk_x11_display_error_trap_push (gdk_display_get_default ()); xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) || (device == NULL)) return NULL; gdk_x11_display_error_trap_push (gdk_display_get_default ()); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, area, 0, 4, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data); if (gdk_x11_display_error_trap_pop (gdk_display_get_default ()) || rc != Success || realtype == None || bytes_after != 0 || nitems != 4) { xdevice_close (xdevice); return NULL; } device_area = g_new0 (int, nitems); for (i = 0; i < nitems; i++) device_area[i] = ((long *)data)[i]; XFree (data); xdevice_close (xdevice); return device_area; } const char * csd_wacom_device_type_to_string (CsdWacomDeviceType type) { switch (type) { case WACOM_TYPE_INVALID: return "Invalid"; case WACOM_TYPE_STYLUS: return "Stylus"; case WACOM_TYPE_ERASER: return "Eraser"; case WACOM_TYPE_CURSOR: return "Cursor"; case WACOM_TYPE_PAD: return "Pad"; case WACOM_TYPE_TOUCH: return "Touch"; default: return "Unknown type"; } } GList * csd_wacom_device_get_buttons (CsdWacomDevice *device) { g_return_val_if_fail (CSD_IS_WACOM_DEVICE (device), NULL); return g_list_copy (device->priv->buttons); } static CsdWacomTabletButton * find_button_with_id (CsdWacomDevice *device, const char *id) { GList *l; for (l = device->priv->buttons; l != NULL; l = l->next) { CsdWacomTabletButton *button = l->data; if (g_strcmp0 (button->id, id) == 0) return button; } return NULL; } static CsdWacomTabletButton * find_button_with_index (CsdWacomDevice *device, const char *id, int index) { CsdWacomTabletButton *button; char *str; str = g_strdup_printf ("%s-mode-%d", id, index); button = find_button_with_id (device, str); g_free (str); return button; } CsdWacomTabletButton * csd_wacom_device_get_button (CsdWacomDevice *device, int button, GtkDirectionType *dir) { int index; if (button <= 26) { char *id; CsdWacomTabletButton *ret; int physical_button; /* mouse_button = physical_button < 4 ? physical_button : physical_button + 4 */ if (button > 4) physical_button = button - 4; else physical_button = button; id = g_strdup_printf ("button%c", 'A' + physical_button - 1); ret = find_button_with_id (device, id); g_free (id); return ret; } switch (button) { case 90: case 92: case 94: case 96: *dir = GTK_DIR_UP; break; case 91: case 93: case 95: case 97: *dir = GTK_DIR_DOWN; break; default: ;; } /* The group ID is implied by the button number */ switch (button) { case 90: case 91: index = GPOINTER_TO_INT (g_hash_table_lookup (device->priv->modes, GINT_TO_POINTER (1))); return find_button_with_index (device, "left-ring", index); case 92: case 93: index = GPOINTER_TO_INT (g_hash_table_lookup (device->priv->modes, GINT_TO_POINTER (2))); return find_button_with_index (device, "right-ring", index); case 94: case 95: index = GPOINTER_TO_INT (g_hash_table_lookup (device->priv->modes, GINT_TO_POINTER (3))); return find_button_with_index (device, "left-strip", index); case 96: case 97: index = GPOINTER_TO_INT (g_hash_table_lookup (device->priv->modes, GINT_TO_POINTER (4))); return find_button_with_index (device, "right-strip", index); default: return NULL; } } CsdWacomRotation csd_wacom_device_rotation_name_to_type (const char *rotation) { guint i; g_return_val_if_fail (rotation != NULL, CSD_WACOM_ROTATION_NONE); for (i = 0; i < G_N_ELEMENTS (rotation_table); i++) { if (strcmp (rotation_table[i].rotation_string, rotation) == 0) return (rotation_table[i].rotation_wacom); } return CSD_WACOM_ROTATION_NONE; } const char * csd_wacom_device_rotation_type_to_name (CsdWacomRotation type) { guint i; for (i = 0; i < G_N_ELEMENTS (rotation_table); i++) { if (rotation_table[i].rotation_wacom == type) return (rotation_table[i].rotation_string); } return "none"; } CsdWacomDevice * csd_wacom_device_create_fake (CsdWacomDeviceType type, const char *name, const char *tool_name) { CsdWacomDevice *device; CsdWacomDevicePrivate *priv; WacomDevice *wacom_device; device = CSD_WACOM_DEVICE (g_object_new (CSD_TYPE_WACOM_DEVICE, NULL)); if (db == NULL) db = libwacom_database_new (); wacom_device = libwacom_new_from_name (db, name, NULL); if (wacom_device == NULL) return NULL; priv = device->priv; priv->type = type; priv->tool_name = g_strdup (tool_name); csd_wacom_device_update_from_db (device, wacom_device, name); libwacom_destroy (wacom_device); return device; } GList * csd_wacom_device_create_fake_cintiq (void) { CsdWacomDevice *device; GList *devices; device = csd_wacom_device_create_fake (WACOM_TYPE_STYLUS, "Wacom Cintiq 21UX2", "Wacom Cintiq 21UX2 stylus"); devices = g_list_prepend (NULL, device); device = csd_wacom_device_create_fake (WACOM_TYPE_ERASER, "Wacom Cintiq 21UX2", "Wacom Cintiq 21UX2 eraser"); devices = g_list_prepend (devices, device); device = csd_wacom_device_create_fake (WACOM_TYPE_PAD, "Wacom Cintiq 21UX2", "Wacom Cintiq 21UX2 pad"); devices = g_list_prepend (devices, device); return devices; } GList * csd_wacom_device_create_fake_bt (void) { CsdWacomDevice *device; GList *devices; device = csd_wacom_device_create_fake (WACOM_TYPE_STYLUS, "Wacom Graphire Wireless", "Graphire Wireless stylus"); devices = g_list_prepend (NULL, device); device = csd_wacom_device_create_fake (WACOM_TYPE_ERASER, "Wacom Graphire Wireless", "Graphire Wireless eraser"); devices = g_list_prepend (devices, device); device = csd_wacom_device_create_fake (WACOM_TYPE_PAD, "Wacom Graphire Wireless", "Graphire Wireless pad"); devices = g_list_prepend (devices, device); device = csd_wacom_device_create_fake (WACOM_TYPE_CURSOR, "Wacom Graphire Wireless", "Graphire Wireless cursor"); devices = g_list_prepend (devices, device); return devices; } GList * csd_wacom_device_create_fake_x201 (void) { CsdWacomDevice *device; GList *devices; device = csd_wacom_device_create_fake (WACOM_TYPE_STYLUS, "Wacom Serial Tablet WACf004", "Wacom Serial Tablet WACf004 stylus"); devices = g_list_prepend (NULL, device); device = csd_wacom_device_create_fake (WACOM_TYPE_ERASER, "Wacom Serial Tablet WACf004", "Wacom Serial Tablet WACf004 eraser"); devices = g_list_prepend (devices, device); return devices; } GList * csd_wacom_device_create_fake_intuos4 (void) { CsdWacomDevice *device; GList *devices; device = csd_wacom_device_create_fake (WACOM_TYPE_STYLUS, "Wacom Intuos4 6x9", "Wacom Intuos4 6x9 stylus"); devices = g_list_prepend (NULL, device); device = csd_wacom_device_create_fake (WACOM_TYPE_ERASER, "Wacom Intuos4 6x9", "Wacom Intuos4 6x9 eraser"); devices = g_list_prepend (devices, device); device = csd_wacom_device_create_fake (WACOM_TYPE_PAD, "Wacom Intuos4 6x9", "Wacom Intuos4 6x9 pad"); devices = g_list_prepend (devices, device); device = csd_wacom_device_create_fake (WACOM_TYPE_CURSOR, "Wacom Intuos4 6x9", "Wacom Intuos4 6x9 cursor"); devices = g_list_prepend (devices, device); return devices; } cinnamon-settings-daemon-5.2.0/plugins/wacom/csd-wacom-device.h0000664000175000017500000002041514144454032023420 0ustar fabiofabio/* * Copyright (C) 2011 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Author: Bastien Nocera * */ #ifndef __CSD_WACOM_DEVICE_MANAGER_H #define __CSD_WACOM_DEVICE_MANAGER_H #include #include "csd-enums.h" G_BEGIN_DECLS #define NUM_ELEMS_MATRIX 9 #define CSD_TYPE_WACOM_DEVICE (csd_wacom_device_get_type ()) #define CSD_WACOM_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_WACOM_DEVICE, CsdWacomDevice)) #define CSD_WACOM_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_WACOM_DEVICE, CsdWacomDeviceClass)) #define CSD_IS_WACOM_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_WACOM_DEVICE)) #define CSD_IS_WACOM_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_WACOM_DEVICE)) #define CSD_WACOM_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_WACOM_DEVICE, CsdWacomDeviceClass)) typedef struct CsdWacomDevicePrivate CsdWacomDevicePrivate; typedef struct { GObject parent; CsdWacomDevicePrivate *priv; } CsdWacomDevice; typedef struct { GObjectClass parent_class; } CsdWacomDeviceClass; #define CSD_TYPE_WACOM_STYLUS (csd_wacom_stylus_get_type ()) #define CSD_WACOM_STYLUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_WACOM_STYLUS, CsdWacomStylus)) #define CSD_WACOM_STYLUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_WACOM_STYLUS, CsdWacomStylusClass)) #define CSD_IS_WACOM_STYLUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_WACOM_STYLUS)) #define CSD_IS_WACOM_STYLUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_WACOM_STYLUS)) #define CSD_WACOM_STYLUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_WACOM_STYLUS, CsdWacomStylusClass)) typedef struct CsdWacomStylusPrivate CsdWacomStylusPrivate; typedef struct { GObject parent; CsdWacomStylusPrivate *priv; } CsdWacomStylus; typedef struct { GObjectClass parent_class; } CsdWacomStylusClass; typedef enum { WACOM_STYLUS_TYPE_UNKNOWN, WACOM_STYLUS_TYPE_GENERAL, WACOM_STYLUS_TYPE_INKING, WACOM_STYLUS_TYPE_AIRBRUSH, WACOM_STYLUS_TYPE_CLASSIC, WACOM_STYLUS_TYPE_MARKER, WACOM_STYLUS_TYPE_STROKE, WACOM_STYLUS_TYPE_PUCK } CsdWacomStylusType; GType csd_wacom_stylus_get_type (void); GSettings * csd_wacom_stylus_get_settings (CsdWacomStylus *stylus); const char * csd_wacom_stylus_get_name (CsdWacomStylus *stylus); const char * csd_wacom_stylus_get_icon_name (CsdWacomStylus *stylus); CsdWacomDevice * csd_wacom_stylus_get_device (CsdWacomStylus *stylus); gboolean csd_wacom_stylus_get_has_eraser (CsdWacomStylus *stylus); guint csd_wacom_stylus_get_num_buttons(CsdWacomStylus *stylus); int csd_wacom_stylus_get_id (CsdWacomStylus *stylus); CsdWacomStylusType csd_wacom_stylus_get_stylus_type (CsdWacomStylus *stylus); /* Tablet Buttons */ typedef enum { WACOM_TABLET_BUTTON_TYPE_NORMAL, WACOM_TABLET_BUTTON_TYPE_STRIP, WACOM_TABLET_BUTTON_TYPE_RING, WACOM_TABLET_BUTTON_TYPE_HARDCODED } CsdWacomTabletButtonType; /* * Positions of the buttons on the tablet in default right-handed mode * (ie with no rotation applied). */ typedef enum { WACOM_TABLET_BUTTON_POS_UNDEF = 0, WACOM_TABLET_BUTTON_POS_LEFT, WACOM_TABLET_BUTTON_POS_RIGHT, WACOM_TABLET_BUTTON_POS_TOP, WACOM_TABLET_BUTTON_POS_BOTTOM } CsdWacomTabletButtonPos; #define MAX_GROUP_ID 4 #define CSD_WACOM_NO_LED -1 typedef struct { char *name; char *id; GSettings *settings; CsdWacomTabletButtonType type; CsdWacomTabletButtonPos pos; int group_id, idx; int status_led; } CsdWacomTabletButton; void csd_wacom_tablet_button_free (CsdWacomTabletButton *button); CsdWacomTabletButton *csd_wacom_tablet_button_copy (CsdWacomTabletButton *button); /* Device types to apply a setting to */ typedef enum { WACOM_TYPE_INVALID = 0, WACOM_TYPE_STYLUS = (1 << 1), WACOM_TYPE_ERASER = (1 << 2), WACOM_TYPE_CURSOR = (1 << 3), WACOM_TYPE_PAD = (1 << 4), WACOM_TYPE_TOUCH = (1 << 5), WACOM_TYPE_ALL = WACOM_TYPE_STYLUS | WACOM_TYPE_ERASER | WACOM_TYPE_CURSOR | WACOM_TYPE_PAD | WACOM_TYPE_TOUCH } CsdWacomDeviceType; /* We use -1 for entire screen when setting/getting monitor value */ #define CSD_WACOM_SET_ALL_MONITORS -1 GType csd_wacom_device_get_type (void); void csd_wacom_device_set_display (CsdWacomDevice *device, int monitor); gint csd_wacom_device_get_display_monitor (CsdWacomDevice *device); gboolean csd_wacom_device_get_display_matrix (CsdWacomDevice *device, float matrix[NUM_ELEMS_MATRIX]); CsdWacomRotation csd_wacom_device_get_display_rotation (CsdWacomDevice *device); CsdWacomDevice * csd_wacom_device_new (GdkDevice *device); GList * csd_wacom_device_list_styli (CsdWacomDevice *device); const char * csd_wacom_device_get_name (CsdWacomDevice *device); const char * csd_wacom_device_get_layout_path (CsdWacomDevice *device); const char * csd_wacom_device_get_path (CsdWacomDevice *device); const char * csd_wacom_device_get_icon_name (CsdWacomDevice *device); const char * csd_wacom_device_get_tool_name (CsdWacomDevice *device); gboolean csd_wacom_device_reversible (CsdWacomDevice *device); gboolean csd_wacom_device_is_screen_tablet (CsdWacomDevice *device); gboolean csd_wacom_device_is_isd (CsdWacomDevice *device); gboolean csd_wacom_device_is_fallback (CsdWacomDevice *device); gint csd_wacom_device_get_num_strips (CsdWacomDevice *device); gint csd_wacom_device_get_num_rings (CsdWacomDevice *device); GSettings * csd_wacom_device_get_settings (CsdWacomDevice *device); void csd_wacom_device_set_current_stylus (CsdWacomDevice *device, int stylus_id); CsdWacomStylus * csd_wacom_device_get_stylus_for_type (CsdWacomDevice *device, CsdWacomStylusType type); CsdWacomDeviceType csd_wacom_device_get_device_type (CsdWacomDevice *device); gint * csd_wacom_device_get_area (CsdWacomDevice *device); const char * csd_wacom_device_type_to_string (CsdWacomDeviceType type); GList * csd_wacom_device_get_buttons (CsdWacomDevice *device); CsdWacomTabletButton *csd_wacom_device_get_button (CsdWacomDevice *device, int button, GtkDirectionType *dir); int csd_wacom_device_get_num_modes (CsdWacomDevice *device, int group_id); int csd_wacom_device_get_current_mode (CsdWacomDevice *device, int group_id); int csd_wacom_device_set_next_mode (CsdWacomDevice *device, CsdWacomTabletButton *button); CsdWacomRotation csd_wacom_device_rotation_name_to_type (const char *rotation); const char * csd_wacom_device_rotation_type_to_name (CsdWacomRotation type); /* Helper and debug functions */ CsdWacomDevice * csd_wacom_device_create_fake (CsdWacomDeviceType type, const char *name, const char *tool_name); GList * csd_wacom_device_create_fake_cintiq (void); GList * csd_wacom_device_create_fake_bt (void); GList * csd_wacom_device_create_fake_x201 (void); GList * csd_wacom_device_create_fake_intuos4 (void); G_END_DECLS #endif /* __CSD_WACOM_DEVICE_MANAGER_H */ cinnamon-settings-daemon-5.2.0/plugins/wacom/tablet-layout.css0000664000175000017500000000162514144454032023437 0ustar fabiofabio cinnamon-settings-daemon-5.2.0/plugins/wacom/README.config-storage0000664000175000017500000000326214144454032023724 0ustar fabiofabioConfiguration storage for Wacom tablets and styli Tablets ------- Configuration is stored on a per-device model basis, meaning that it's possible to use the same device, with same configuration on 2 machines with a shared home directory, or replace a malfunctioning device with the same model and have the same configuration. It does not allow having 2 separate tablets of the same model to have different configurations, whether on a single machine, or using a shared home directory. The configuration scheme is: schema: org.cinnamon.settings-daemon.peripherals.wacom path: /org/cinnamon/settings-daemon/peripherals/wacom/-/ where is the D-Bus machine-id for the machine, and is a unique identifier for the tablet. Stylus ------ Styli use a similar configuration scheme. The identifier for each stylus is the tool ID, for professional ranges, and a generic identifier for the consumer ranges that do not support tool ID. schema: org.cinnamon.settings-daemon.peripherals.wacom.stylus or: org.cinnamon.settings-daemon.peripherals.wacom.eraser path: /org/cinnamon/settings-daemon/peripherals/wacom/// So each tool can be configured per tablet (so the compatible airbrush stylus will have different configurations on a Cintiq and an Intuos tablet) Buttons ------- schema: org.cinnamon.settings-daemon.peripherals.wacom.tablet-button path: /org/cinnamon/settings-daemon/peripherals/wacom//