cinnamon-settings-daemon-2.8.3/0000775000175000017500000000000012625665665015374 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/COPYING0000664000175000017500000004312212625665665016431 0ustar fabiofabio GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. cinnamon-settings-daemon-2.8.3/plugins/0000775000175000017500000000000012625665665017055 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/keyboard/0000775000175000017500000000000012625665665020655 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/keyboard/csd-keyboard-xkb.c0000664000175000017500000003461512625665665024163 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2001 Udaltsoft * * Written by Sergey V. Oudaltsov * * 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 #include #include #include #include #include #include #include #include #include #include "csd-keyboard-xkb.h" #include "delayed-dialog.h" #include "cinnamon-settings-profile.h" #define SETTINGS_KEYBOARD_DIR "org.cinnamon.settings-daemon.plugins.keyboard" static CsdKeyboardManager *manager = NULL; static XklEngine *xkl_engine; static XklConfigRegistry *xkl_registry = NULL; static GkbdDesktopConfig current_config; static GkbdKeyboardConfig current_kbd_config; /* never terminated */ static GkbdKeyboardConfig initial_sys_kbd_config; static gboolean inited_ok = FALSE; static GSettings *settings_desktop = NULL; static GSettings *settings_keyboard = NULL; static PostActivationCallback pa_callback = NULL; static void *pa_callback_user_data = NULL; static GtkStatusIcon *icon = NULL; static GHashTable *preview_dialogs = NULL; static void activation_error (void) { char const *vendor; GtkWidget *dialog; vendor = ServerVendor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); /* VNC viewers will not work, do not barrage them with warnings */ if (NULL != vendor && NULL != strstr (vendor, "VNC")) return; dialog = gtk_message_dialog_new_with_markup (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _ ("Error activating XKB configuration.\n" "There can be various reasons for that.\n\n" "If you report this situation as a bug, include the results of\n" " • %s\n" " • %s\n" " • %s\n" " • %s"), "xprop -root | grep XKB", "gsettings get org.gnome.libgnomekbd.keyboard model", "gsettings get org.gnome.libgnomekbd.keyboard layouts", "gsettings get org.gnome.libgnomekbd.keyboard options"); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); csd_delayed_show_dialog (dialog); } static gboolean ensure_xkl_registry (void) { if (!xkl_registry) { xkl_registry = xkl_config_registry_get_instance (xkl_engine); /* load all materials, unconditionally! */ if (!xkl_config_registry_load (xkl_registry, TRUE)) { g_object_unref (xkl_registry); xkl_registry = NULL; return FALSE; } } return TRUE; } static void apply_desktop_settings (void) { if (!inited_ok) return; csd_keyboard_manager_apply_settings (manager); gkbd_desktop_config_load (¤t_config); /* again, probably it would be nice to compare things before activating them */ gkbd_desktop_config_activate (¤t_config); } static void popup_menu_launch_capplet () { GAppInfo *info; GdkAppLaunchContext *ctx; GError *error = NULL; info = g_app_info_create_from_commandline ("cinnamon-settings region", NULL, 0, &error); if (info != NULL) { ctx = gdk_display_get_app_launch_context (gdk_display_get_default ()); if (g_app_info_launch (info, NULL, G_APP_LAUNCH_CONTEXT (ctx), &error) == FALSE) { g_warning ("Could not execute keyboard properties capplet: [%s]\n", error->message); g_error_free (error); } g_object_unref (info); g_object_unref (ctx); } } static void show_layout_destroy (GtkWidget * dialog, gint group) { g_hash_table_remove (preview_dialogs, GINT_TO_POINTER (group)); } static void popup_menu_show_layout () { GtkWidget *dialog; XklEngine *engine = xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); XklState *xkl_state = xkl_engine_get_current_state (engine); gchar **group_names = gkbd_status_get_group_names (); gpointer p = g_hash_table_lookup (preview_dialogs, GINT_TO_POINTER (xkl_state->group)); if (xkl_state->group < 0 || xkl_state->group >= g_strv_length (group_names)) { return; } if (p != NULL) { /* existing window */ gtk_window_present (GTK_WINDOW (p)); return; } if (!ensure_xkl_registry ()) return; dialog = gkbd_keyboard_drawing_dialog_new (); gkbd_keyboard_drawing_dialog_set_group (dialog, xkl_registry, xkl_state->group); g_signal_connect (dialog, "destroy", G_CALLBACK (show_layout_destroy), GINT_TO_POINTER (xkl_state->group)); g_hash_table_insert (preview_dialogs, GINT_TO_POINTER (xkl_state->group), dialog); gtk_widget_show_all (dialog); } static void popup_menu_set_group (gint group_number, gboolean only_menu) { XklEngine *engine = gkbd_status_get_xkl_engine (); XklState *st = xkl_engine_get_current_state(engine); Window cur; st->group = group_number; xkl_engine_allow_one_switch_to_secondary_group (engine); cur = xkl_engine_get_current_window (engine); if (cur != (Window) NULL) { xkl_debug (150, "Enforcing the state %d for window %lx\n", st->group, cur); xkl_engine_save_state (engine, xkl_engine_get_current_window (engine), st); /* XSetInputFocus( GDK_DISPLAY(), cur, RevertToNone, CurrentTime );*/ } else { xkl_debug (150, "??? Enforcing the state %d for unknown window\n", st->group); /* strange situation - bad things can happen */ } if (!only_menu) xkl_engine_lock_group (engine, st->group); } static void popup_menu_set_group_cb (GtkMenuItem * item, gpointer param) { gint group_number = GPOINTER_TO_INT (param); popup_menu_set_group(group_number, FALSE); } static GtkMenu * create_status_menu (void) { GtkMenu *popup_menu = GTK_MENU (gtk_menu_new ()); int i = 0; GtkMenu *groups_menu = GTK_MENU (gtk_menu_new ()); gchar **current_name = gkbd_status_get_group_names (); GtkWidget *item = gtk_menu_item_new_with_mnemonic (_("_Layouts")); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), GTK_WIDGET (groups_menu)); item = gtk_menu_item_new_with_mnemonic (_("Show _Keyboard Layout...")); gtk_widget_show (item); g_signal_connect (item, "activate", popup_menu_show_layout, NULL); gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item); /* translators note: * This is the name of the cinnamon-settings "region" panel */ item = gtk_menu_item_new_with_mnemonic (_("Region and Language Settings")); gtk_widget_show (item); g_signal_connect (item, "activate", popup_menu_launch_capplet, NULL); gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), item); for (i = 0; current_name && *current_name; i++, current_name++) { gchar *image_file = gkbd_status_get_image_filename (i); if (image_file == NULL) { item = gtk_menu_item_new_with_label (*current_name); } else { GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size (image_file, 24, 24, NULL); GtkWidget *img = gtk_image_new_from_pixbuf (pixbuf); item = gtk_image_menu_item_new_with_label (*current_name); gtk_widget_show (img); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img); gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (item), TRUE); g_free (image_file); } gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (groups_menu), item); g_signal_connect (item, "activate", G_CALLBACK (popup_menu_set_group_cb), GINT_TO_POINTER (i)); } return popup_menu; } static void status_icon_popup_menu_cb (GtkStatusIcon * icon, guint button, guint time) { GtkMenu *popup_menu = create_status_menu (); gtk_menu_popup (popup_menu, NULL, NULL, gtk_status_icon_position_menu, (gpointer) icon, button, time); } static gboolean try_activating_xkb_config_if_new (GkbdKeyboardConfig * current_sys_kbd_config) { /* Activate - only if different! */ if (!gkbd_keyboard_config_equals (¤t_kbd_config, current_sys_kbd_config)) { if (gkbd_keyboard_config_activate (¤t_kbd_config)) { if (pa_callback != NULL) { (*pa_callback) (pa_callback_user_data); return TRUE; } } else { return FALSE; } } return TRUE; } static gboolean filter_xkb_config (void) { XklConfigItem *item; gchar *lname; gchar *vname; gchar **lv; gboolean any_change = FALSE; xkl_debug (100, "Filtering configuration against the registry\n"); if (!ensure_xkl_registry ()) return FALSE; lv = current_kbd_config.layouts_variants; item = xkl_config_item_new (); while (*lv) { xkl_debug (100, "Checking [%s]\n", *lv); if (gkbd_keyboard_config_split_items (*lv, &lname, &vname)) { gboolean should_be_dropped = FALSE; g_snprintf (item->name, sizeof (item->name), "%s", lname); if (!xkl_config_registry_find_layout (xkl_registry, item)) { xkl_debug (100, "Bad layout [%s]\n", lname); should_be_dropped = TRUE; } else if (vname) { g_snprintf (item->name, sizeof (item->name), "%s", vname); if (!xkl_config_registry_find_variant (xkl_registry, lname, item)) { xkl_debug (100, "Bad variant [%s(%s)]\n", lname, vname); should_be_dropped = TRUE; } } if (should_be_dropped) { gkbd_strv_behead (lv); any_change = TRUE; continue; } } lv++; } g_object_unref (item); return any_change; } static void apply_xkb_settings (void) { GkbdKeyboardConfig current_sys_kbd_config; if (!inited_ok) return; gkbd_keyboard_config_init (¤t_sys_kbd_config, xkl_engine); gkbd_keyboard_config_load (¤t_kbd_config, &initial_sys_kbd_config); gkbd_keyboard_config_load_from_x_current (¤t_sys_kbd_config, NULL); if (!try_activating_xkb_config_if_new (¤t_sys_kbd_config)) { if (filter_xkb_config ()) { if (!try_activating_xkb_config_if_new (¤t_sys_kbd_config)) { g_warning ("Could not activate the filtered XKB configuration"); activation_error (); } } else { g_warning ("Could not activate the XKB configuration"); activation_error (); } } else xkl_debug (100, "Actual KBD configuration was not changed: redundant notification\n"); gkbd_keyboard_config_term (¤t_sys_kbd_config); //show_hide_icon (); } static void csd_keyboard_xkb_analyze_sysconfig (void) { if (!inited_ok) return; gkbd_keyboard_config_init (&initial_sys_kbd_config, xkl_engine); gkbd_keyboard_config_load_from_x_initial (&initial_sys_kbd_config, NULL); } void csd_keyboard_xkb_set_post_activation_callback (PostActivationCallback fun, void *user_data) { pa_callback = fun; pa_callback_user_data = user_data; } static GdkFilterReturn csd_keyboard_xkb_evt_filter (GdkXEvent * xev, GdkEvent * event) { XEvent *xevent = (XEvent *) xev; xkl_engine_filter_events (xkl_engine, xevent); return GDK_FILTER_CONTINUE; } /* When new Keyboard is plugged in - reload the settings */ static void csd_keyboard_new_device (XklEngine * engine) { apply_desktop_settings (); apply_xkb_settings (); } void csd_keyboard_xkb_init (CsdKeyboardManager * kbd_manager) { Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); cinnamon_settings_profile_start (NULL); gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), DATADIR G_DIR_SEPARATOR_S "icons"); manager = kbd_manager; cinnamon_settings_profile_start ("xkl_engine_get_instance"); xkl_engine = xkl_engine_get_instance (display); cinnamon_settings_profile_end ("xkl_engine_get_instance"); if (xkl_engine) { inited_ok = TRUE; gkbd_desktop_config_init (¤t_config, xkl_engine); gkbd_keyboard_config_init (¤t_kbd_config, xkl_engine); xkl_engine_backup_names_prop (xkl_engine); csd_keyboard_xkb_analyze_sysconfig (); settings_desktop = g_settings_new (GKBD_DESKTOP_SCHEMA); settings_keyboard = g_settings_new (GKBD_KEYBOARD_SCHEMA); g_signal_connect (settings_desktop, "changed", (GCallback) apply_desktop_settings, NULL); g_signal_connect (settings_keyboard, "changed", (GCallback) apply_xkb_settings, NULL); gdk_window_add_filter (NULL, (GdkFilterFunc) csd_keyboard_xkb_evt_filter, NULL); if (xkl_engine_get_features (xkl_engine) & XKLF_DEVICE_DISCOVERY) g_signal_connect (xkl_engine, "X-new-device", G_CALLBACK (csd_keyboard_new_device), NULL); cinnamon_settings_profile_start ("xkl_engine_start_listen"); xkl_engine_start_listen (xkl_engine, XKLL_MANAGE_LAYOUTS | XKLL_MANAGE_WINDOW_STATES); cinnamon_settings_profile_end ("xkl_engine_start_listen"); cinnamon_settings_profile_start ("apply_desktop_settings"); apply_desktop_settings (); cinnamon_settings_profile_end ("apply_desktop_settings"); cinnamon_settings_profile_start ("apply_xkb_settings"); apply_xkb_settings (); cinnamon_settings_profile_end ("apply_xkb_settings"); } preview_dialogs = g_hash_table_new (g_direct_hash, g_direct_equal); cinnamon_settings_profile_end (NULL); } void csd_keyboard_xkb_shutdown (void) { if (!inited_ok) return; pa_callback = NULL; pa_callback_user_data = NULL; manager = NULL; if (preview_dialogs != NULL) g_hash_table_destroy (preview_dialogs); if (!inited_ok) return; xkl_engine_stop_listen (xkl_engine, XKLL_MANAGE_LAYOUTS | XKLL_MANAGE_WINDOW_STATES); gdk_window_remove_filter (NULL, (GdkFilterFunc) csd_keyboard_xkb_evt_filter, NULL); g_object_unref (settings_desktop); settings_desktop = NULL; g_object_unref (settings_keyboard); settings_keyboard = NULL; if (xkl_registry) { g_object_unref (xkl_registry); } g_object_unref (xkl_engine); xkl_engine = NULL; inited_ok = FALSE; } cinnamon-settings-daemon-2.8.3/plugins/keyboard/gkbd-configuration.h0000664000175000017500000000464512625665665024613 0ustar fabiofabio/* * Copyright (C) 2010 Canonical Ltd. * * Authors: Jan Arne Petersen * * Based on gkbd-status.h by Sergey V. Udaltsov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef __GKBD_CONFIGURATION_H__ #define __GKBD_CONFIGURATION_H__ #include #include G_BEGIN_DECLS typedef struct _GkbdConfiguration GkbdConfiguration; typedef struct _GkbdConfigurationPrivate GkbdConfigurationPrivate; typedef struct _GkbdConfigurationClass GkbdConfigurationClass; #define GKBD_TYPE_CONFIGURATION (gkbd_configuration_get_type ()) #define GKBD_CONFIGURATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKBD_TYPE_CONFIGURATION, GkbdConfiguration)) #define GKBD_INDCATOR_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GKBD_TYPE_CONFIGURATION, GkbdConfigurationClass)) #define GKBD_IS_CONFIGURATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKBD_TYPE_CONFIGURATION)) #define GKBD_IS_CONFIGURATION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), GKBD_TYPE_CONFIGURATION)) #define GKBD_CONFIGURATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKBD_TYPE_CONFIGURATION, GkbdConfigurationClass)) struct _GkbdConfiguration { GObject parent; GkbdConfigurationPrivate *priv; }; struct _GkbdConfigurationClass { GObjectClass parent_class; }; extern GType gkbd_configuration_get_type (void); extern GkbdConfiguration *gkbd_configuration_get (void); extern XklEngine *gkbd_configuration_get_xkl_engine (GkbdConfiguration *configuration); extern const char * const *gkbd_configuration_get_group_names (GkbdConfiguration *configuration); extern const char * const *gkbd_configuration_get_short_group_names (GkbdConfiguration *configuration); G_END_DECLS #endif cinnamon-settings-daemon-2.8.3/plugins/keyboard/kbd-numlock-off.png0000664000175000017500000000331612625665665024344 0ustar fabiofabio‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsœœn›¡NtEXtSoftwarewww.inkscape.org›î<KIDATxœå›[ˆVUÇÿûÓò6b7‡¼<ˆƒÝL!)Ó A³DˆÞ²Ë” ^ÀÀÔ$"¢—Jò!z”Šz)S¼¥ˆ¥‰—ˆFÇÅq2Éy˜"c&uæ×Ã>£gö¬óÍ÷}gãàüá{8笵þkíoŸ}Y{§*¨‘4GÒdIãŸ$µ¿&I{s—ªíctã€eÀ6 ƒÊÑl–nt\E V‡®Ag¡ 8 ¬FÞèx¯(õÀ¹*…óÀb ×—3øù’6Hš^†Ú%õ|×¥žcBM¶%½áœÛQ†N~Ý%üSÀ`0 ]‚íщìºD·³ž=ÀÄþˆ]ÀlàBí–µøj[;úà¼ÌŽc1gê)>ªïfV‘f‘… ¾ÄC€Eˆщ³ýYpfa#0$Ù`sÑU` Fã ü*$ÜW3|Û¥ŠüómÀܱäõonâ‹Ùò¯Ï0|˜)†Ü¦$>Y¨lLÀöÖ€·9†ÜÆ$¾…è ÜÙ?Ï[SÝÉ|7’F°zÂÊY'`/rÚR·ÏBò:XcžR cð*p0k&åõ!ñ#ÜJw‘Î1KVZ8ÜGœÉ|ȚׇÄö#¾åi­ÁÃNr&3ðƒÞé ÕWö¡38›Òùx0‰]«‡oï~8ŠÞïá¤ó›‡(a:6zïåõ%±{ °ÛÔä-†òßFà|(¸>åœë*A¯!¸~,‚/RIšSTgïŒ@Îç-¦To–Ô™ºžJœs+¦É]?žJ£9á­ÁuG‰zmì]’̳L4÷Æ[ pÉ9÷OÂ0à»KÔ{XÒ¨àÞ´¼Î$1…çŒf”ÚUûÂÅàºÔ³½Œ{·çô¥alUm€-êÙ ÂÑÂBãÞˆ8.õc8çš$íOݺMÒ[@æq~ñõ¤ñ¨ª PM|"érêú9Iß`uoJúP’åS®3Ìb*ß*÷¦îY³BEpÎ}̓Խ¬v’ž•48-éwù÷»NÒýºh“|AE7bIôêíUm€+åZÏëú¿›® ±SÒo’V§îU­ 2Þ‹Hd’$çÜeçÜ‹’VH:¢ž‹œ4ÎJz_~ 3DáŒR)2{@5ÀèHkkpÎm’´ ˜%é ùÎHIÉwù/œsÿIpOJµ]ÒwyùñGóaíÙ’4IÒñ¼¤œs‡$ÊzÜ)é¾Ô­Sιó¨'÷Z ’ÎæG ¬ËÔsás0’]+¦¦ªm‡+>1{4åG;‘ê ²¶ÃÝ£'D*tò£À­‘ìZ ‘mi+e”;%–ØžE‰ÀïÒó0öO œâ«bö­ø–¥Æ-¥ò Ÿìl>^¦â»ú-@ð:½Ou/ëcð'>XIÑq¡Ð~£•b¤Å0È[‹Àƒó ‘Ò` ¿•?l ®0÷Ep l€bhVåå ø­ƒ‘Õ–à­‰!r/Ÿ¿b×ü]~€Qký°ÆÎ×r .PX$éËÀÎ IÓKLhsÆÉ/p¦Jª•߈µJ:áœ;–Çv_AÒ±„/WœsŸe: ül´ÚÍr<Þ@_©y`ž¡x³H”¶Âåæ,‘Ù]Ž‘Á]$•¼er)£õ†Áîž0`^ªQ(™2>xKe‚Á], Þrù€¸žÁøÁDàÄàýd&åÔ@ûhj7n¤ò~67OÒê] R 1?›k´Þ9·« ¸Ào ao¥«…f|Yo¿Ï>™ÀçVà3K¥tÛrщ/æ\ »Ññ>ǸØ‚] Z*Úñë¥T)K]µcçn£ä+ÑêTÞçógä?Ÿÿ·šþý|wÙUú‘&IEND®B`‚cinnamon-settings-daemon-2.8.3/plugins/keyboard/gkbd-configuration.c0000664000175000017500000002340512625665665024601 0ustar fabiofabio/* * Copyright (C) 2010 Canonical Ltd. * * Authors: Jan Arne Petersen * * Based on gkbd-status.c by Sergey V. Udaltsov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; 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 "gkbd-configuration.h" struct _GkbdConfigurationPrivate { XklEngine *engine; XklConfigRegistry *registry; GkbdDesktopConfig cfg; GkbdIndicatorConfig ind_cfg; GkbdKeyboardConfig kbd_cfg; gchar **full_group_names; gchar **short_group_names; gulong state_changed_handler; gulong config_changed_handler; }; enum { SIGNAL_CHANGED, SIGNAL_GROUP_CHANGED, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0, }; #define GKBD_CONFIGURATION_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), GKBD_TYPE_CONFIGURATION, GkbdConfigurationPrivate)) G_DEFINE_TYPE (GkbdConfiguration, gkbd_configuration, G_TYPE_OBJECT) /* Should be called once for all widgets */ static void gkbd_configuration_cfg_changed (GSettings *settings, const char *key, GkbdConfiguration * configuration) { GkbdConfigurationPrivate *priv = configuration->priv; xkl_debug (100, "General configuration changed in GSettings - reiniting...\n"); gkbd_desktop_config_load (&priv->cfg); gkbd_desktop_config_activate (&priv->cfg); g_signal_emit (configuration, signals[SIGNAL_CHANGED], 0); } /* Should be called once for all widgets */ static void gkbd_configuration_ind_cfg_changed (GSettings *settings, const char *key, GkbdConfiguration * configuration) { GkbdConfigurationPrivate *priv = configuration->priv; xkl_debug (100, "Applet configuration changed in GSettings - reiniting...\n"); gkbd_indicator_config_load (&priv->ind_cfg); gkbd_indicator_config_free_image_filenames (&priv->ind_cfg); gkbd_indicator_config_load_image_filenames (&priv->ind_cfg, &priv->kbd_cfg); gkbd_indicator_config_activate (&priv->ind_cfg); g_signal_emit (configuration, signals[SIGNAL_CHANGED], 0); } static void gkbd_configuration_load_group_names (GkbdConfiguration * configuration, XklConfigRec * xklrec) { GkbdConfigurationPrivate *priv = configuration->priv; if (!gkbd_desktop_config_load_group_descriptions (&priv->cfg, priv->registry, (const char **) xklrec->layouts, (const char **) xklrec->variants, &priv->short_group_names, &priv->full_group_names)) { /* We just populate no short names (remain NULL) - * full names are going to be used anyway */ gint i, total_groups = xkl_engine_get_num_groups (priv->engine); xkl_debug (150, "group descriptions loaded: %d!\n", total_groups); priv->full_group_names = g_new0 (char *, total_groups + 1); if (xkl_engine_get_features (priv->engine) & XKLF_MULTIPLE_LAYOUTS_SUPPORTED) { for (i = 0; priv->kbd_cfg.layouts_variants[i]; i++) { priv->full_group_names[i] = g_strdup ((char *) priv->kbd_cfg.layouts_variants[i]); } } else { for (i = total_groups; --i >= 0;) { priv->full_group_names[i] = g_strdup_printf ("Group %d", i); } } } } /* Should be called once for all widgets */ static void gkbd_configuration_kbd_cfg_callback (XklEngine *engine, GkbdConfiguration *configuration) { GkbdConfigurationPrivate *priv = configuration->priv; XklConfigRec *xklrec = xkl_config_rec_new (); xkl_debug (100, "XKB configuration changed on X Server - reiniting...\n"); gkbd_keyboard_config_load_from_x_current (&priv->kbd_cfg, xklrec); gkbd_indicator_config_free_image_filenames (&priv->ind_cfg); gkbd_indicator_config_load_image_filenames (&priv->ind_cfg, &priv->kbd_cfg); g_strfreev (priv->full_group_names); priv->full_group_names = NULL; g_strfreev (priv->short_group_names); priv->short_group_names = NULL; gkbd_configuration_load_group_names (configuration, xklrec); g_signal_emit (configuration, signals[SIGNAL_CHANGED], 0); g_object_unref (G_OBJECT (xklrec)); } /* Should be called once for all applets */ static void gkbd_configuration_state_callback (XklEngine * engine, XklEngineStateChange changeType, gint group, gboolean restore, GkbdConfiguration * configuration) { xkl_debug (150, "group is now %d, restore: %d\n", group, restore); if (changeType == GROUP_CHANGED) { g_signal_emit (configuration, signals[SIGNAL_GROUP_CHANGED], 0, group); } } static void gkbd_configuration_init (GkbdConfiguration *configuration) { GkbdConfigurationPrivate *priv; XklConfigRec *xklrec = xkl_config_rec_new (); priv = GKBD_CONFIGURATION_GET_PRIVATE (configuration); configuration->priv = priv; priv->engine = xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); if (priv->engine == NULL) { xkl_debug (0, "Libxklavier initialization error"); return; } priv->state_changed_handler = g_signal_connect (priv->engine, "X-state-changed", G_CALLBACK (gkbd_configuration_state_callback), configuration); priv->config_changed_handler = g_signal_connect (priv->engine, "X-config-changed", G_CALLBACK (gkbd_configuration_kbd_cfg_callback), configuration); gkbd_desktop_config_init (&priv->cfg, priv->engine); gkbd_keyboard_config_init (&priv->kbd_cfg, priv->engine); gkbd_indicator_config_init (&priv->ind_cfg, priv->engine); gkbd_desktop_config_load (&priv->cfg); gkbd_desktop_config_activate (&priv->cfg); priv->registry = xkl_config_registry_get_instance (priv->engine); xkl_config_registry_load (priv->registry, priv->cfg.load_extra_items); gkbd_keyboard_config_load_from_x_current (&priv->kbd_cfg, xklrec); gkbd_indicator_config_load (&priv->ind_cfg); gkbd_indicator_config_load_image_filenames (&priv->ind_cfg, &priv->kbd_cfg); gkbd_indicator_config_activate (&priv->ind_cfg); gkbd_configuration_load_group_names (configuration, xklrec); g_object_unref (G_OBJECT (xklrec)); gkbd_desktop_config_start_listen (&priv->cfg, G_CALLBACK (gkbd_configuration_cfg_changed), configuration); gkbd_indicator_config_start_listen (&priv->ind_cfg, G_CALLBACK (gkbd_configuration_ind_cfg_changed), configuration); xkl_engine_start_listen (priv->engine, XKLL_TRACK_KEYBOARD_STATE); xkl_debug (100, "Initiating the widget startup process for %p\n", configuration); } static void gkbd_configuration_finalize (GObject * obj) { GkbdConfiguration *configuration = GKBD_CONFIGURATION (obj); GkbdConfigurationPrivate *priv = configuration->priv; xkl_debug (100, "Starting the gnome-kbd-configuration widget shutdown process for %p\n", configuration); xkl_engine_stop_listen (priv->engine, XKLL_TRACK_KEYBOARD_STATE); gkbd_desktop_config_stop_listen (&priv->cfg); gkbd_indicator_config_stop_listen (&priv->ind_cfg); gkbd_indicator_config_term (&priv->ind_cfg); gkbd_keyboard_config_term (&priv->kbd_cfg); gkbd_desktop_config_term (&priv->cfg); if (g_signal_handler_is_connected (priv->engine, priv->state_changed_handler)) { g_signal_handler_disconnect (priv->engine, priv->state_changed_handler); priv->state_changed_handler = 0; } if (g_signal_handler_is_connected (priv->engine, priv->config_changed_handler)) { g_signal_handler_disconnect (priv->engine, priv->config_changed_handler); priv->config_changed_handler = 0; } g_object_unref (priv->registry); priv->registry = NULL; g_object_unref (priv->engine); priv->engine = NULL; G_OBJECT_CLASS (gkbd_configuration_parent_class)->finalize (obj); } static void gkbd_configuration_class_init (GkbdConfigurationClass * klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); /* Initing vtable */ object_class->finalize = gkbd_configuration_finalize; /* Signals */ signals[SIGNAL_CHANGED] = g_signal_new ("changed", GKBD_TYPE_CONFIGURATION, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[SIGNAL_GROUP_CHANGED] = g_signal_new ("group-changed", GKBD_TYPE_CONFIGURATION, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); g_type_class_add_private (klass, sizeof (GkbdConfigurationPrivate)); } GkbdConfiguration * gkbd_configuration_get (void) { static gpointer instance = NULL; if (!instance) { instance = g_object_new (GKBD_TYPE_CONFIGURATION, NULL); g_object_add_weak_pointer (instance, &instance); } else { g_object_ref (instance); } return instance; } XklEngine * gkbd_configuration_get_xkl_engine (GkbdConfiguration *configuration) { return configuration->priv->engine; } const char * const * gkbd_configuration_get_group_names (GkbdConfiguration *configuration) { return configuration->priv->full_group_names; } const char * const * gkbd_configuration_get_short_group_names (GkbdConfiguration *configuration) { return configuration->priv->short_group_names; } cinnamon-settings-daemon-2.8.3/plugins/keyboard/delayed-dialog.h0000664000175000017500000000163412625665665023676 0ustar fabiofabio/* * Copyright © 2006 Novell, 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. */ #ifndef __DELAYED_DIALOG_H #define __DELAYED_DIALOG_H #include G_BEGIN_DECLS void csd_delayed_show_dialog (GtkWidget *dialog); G_END_DECLS #endif cinnamon-settings-daemon-2.8.3/plugins/keyboard/delayed-dialog.c0000664000175000017500000000755412625665665023700 0ustar fabiofabio/* * Copyright © 2006 Novell, 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 "delayed-dialog.h" static gboolean delayed_show_timeout (gpointer data); static GdkFilterReturn message_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data); static GSList *dialogs = NULL; /** * csd_delayed_show_dialog: * @dialog: the dialog * * Shows the dialog as with gtk_widget_show(), unless a window manager * hasn't been started yet, in which case it will wait up to 5 seconds * for that to happen before showing the dialog. **/ void csd_delayed_show_dialog (GtkWidget *dialog) { GdkDisplay *display = gtk_widget_get_display (dialog); Display *xdisplay = GDK_DISPLAY_XDISPLAY (display); GdkScreen *screen = gtk_widget_get_screen (dialog); char selection_name[10]; Atom selection_atom; /* We can't use gdk_selection_owner_get() for this, because * it's an unknown out-of-process window. */ snprintf (selection_name, sizeof (selection_name), "WM_S%d", gdk_screen_get_number (screen)); selection_atom = XInternAtom (xdisplay, selection_name, True); if (selection_atom && XGetSelectionOwner (xdisplay, selection_atom) != None) { gtk_widget_show (dialog); return; } dialogs = g_slist_prepend (dialogs, dialog); gdk_window_add_filter (NULL, message_filter, NULL); g_timeout_add (5000, delayed_show_timeout, NULL); } static gboolean delayed_show_timeout (gpointer data) { GSList *l; for (l = dialogs; l; l = l->next) gtk_widget_show (l->data); g_slist_free (dialogs); dialogs = NULL; /* FIXME: There's no gdk_display_remove_client_message_filter */ return FALSE; } static GdkFilterReturn message_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data) { XClientMessageEvent *evt; char *selection_name; int screen; GSList *l, *next; if (((XEvent *)xevent)->type != ClientMessage) return GDK_FILTER_CONTINUE; evt = (XClientMessageEvent *)xevent; if (evt->message_type != XInternAtom (evt->display, "MANAGER", FALSE)) return GDK_FILTER_CONTINUE; selection_name = XGetAtomName (evt->display, evt->data.l[1]); if (strncmp (selection_name, "WM_S", 4) != 0) { XFree (selection_name); return GDK_FILTER_CONTINUE; } screen = atoi (selection_name + 4); for (l = dialogs; l; l = next) { GtkWidget *dialog = l->data; next = l->next; if (gdk_screen_get_number (gtk_widget_get_screen (dialog)) == screen) { gtk_widget_show (dialog); dialogs = g_slist_remove (dialogs, dialog); } } if (!dialogs) { gdk_window_remove_filter (NULL, message_filter, NULL); } XFree (selection_name); return GDK_FILTER_CONTINUE; } cinnamon-settings-daemon-2.8.3/plugins/keyboard/keyboard.cinnamon-settings-plugin.in0000664000175000017500000000021412625665665027735 0ustar fabiofabio[Cinnamon Settings Plugin] Module=keyboard IAge=0 _Name=Keyboard _Description=Keyboard plugin Authors= Copyright=Copyright © 2007 Website= cinnamon-settings-daemon-2.8.3/plugins/keyboard/csd-keyboard-manager.c0000664000175000017500000003161412625665665025005 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 * Written by Sergey V. Oudaltsov * * 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 "cinnamon-settings-profile.h" #include "csd-keyboard-manager.h" #include "csd-enums.h" #include "csd-keyboard-xkb.h" #define CSD_KEYBOARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_KEYBOARD_MANAGER, CsdKeyboardManagerPrivate)) #ifndef HOST_NAME_MAX # define HOST_NAME_MAX 255 #endif #define CSD_KEYBOARD_DIR "org.cinnamon.settings-daemon.peripherals.keyboard" #define KEY_REPEAT "repeat" #define KEY_CLICK "click" #define KEY_INTERVAL "repeat-interval" #define KEY_DELAY "delay" #define KEY_CLICK_VOLUME "click-volume" #define KEY_NUMLOCK_STATE "numlock-state" #define KEY_BELL_VOLUME "bell-volume" #define KEY_BELL_PITCH "bell-pitch" #define KEY_BELL_DURATION "bell-duration" #define KEY_BELL_MODE "bell-mode" struct CsdKeyboardManagerPrivate { guint start_idle_id; GSettings *settings; gboolean have_xkb; gint xkb_event_base; CsdNumLockState old_state; }; static void csd_keyboard_manager_class_init (CsdKeyboardManagerClass *klass); static void csd_keyboard_manager_init (CsdKeyboardManager *keyboard_manager); static void csd_keyboard_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdKeyboardManager, csd_keyboard_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static gboolean xkb_set_keyboard_autorepeat_rate (guint delay, guint interval) { return XkbSetAutoRepeatRate (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbUseCoreKbd, delay, interval); } static void numlock_xkb_init (CsdKeyboardManager *manager) { Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); gboolean have_xkb; int opcode, error_base, major, minor; have_xkb = XkbQueryExtension (dpy, &opcode, &manager->priv->xkb_event_base, &error_base, &major, &minor) && XkbUseExtension (dpy, &major, &minor); if (have_xkb) { XkbSelectEventDetails (dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbModifierLockMask, XkbModifierLockMask); } else { g_warning ("XKB extension not available"); } manager->priv->have_xkb = have_xkb; } static unsigned numlock_NumLock_modifier_mask (void) { Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); return XkbKeysymToModifiers (dpy, XK_Num_Lock); } static void numlock_set_xkb_state (CsdNumLockState new_state) { unsigned int num_mask; Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); if (new_state != CSD_NUM_LOCK_STATE_ON && new_state != CSD_NUM_LOCK_STATE_OFF) return; num_mask = numlock_NumLock_modifier_mask (); XkbLockModifiers (dpy, XkbUseCoreKbd, num_mask, new_state == CSD_NUM_LOCK_STATE_ON ? num_mask : 0); } static GdkFilterReturn numlock_xkb_callback (GdkXEvent *xev_, GdkEvent *gdkev_, gpointer user_data) { XEvent *xev = (XEvent *) xev_; XkbEvent *xkbev = (XkbEvent *) xev; CsdKeyboardManager *manager = (CsdKeyboardManager *) user_data; if (xev->type != manager->priv->xkb_event_base) return GDK_FILTER_CONTINUE; if (xkbev->any.xkb_type != XkbStateNotify) return GDK_FILTER_CONTINUE; if (xkbev->state.changed & XkbModifierLockMask) { unsigned num_mask = numlock_NumLock_modifier_mask (); unsigned locked_mods = xkbev->state.locked_mods; CsdNumLockState numlock_state; numlock_state = (num_mask & locked_mods) ? CSD_NUM_LOCK_STATE_ON : CSD_NUM_LOCK_STATE_OFF; if (numlock_state != manager->priv->old_state) { g_settings_set_enum (manager->priv->settings, KEY_NUMLOCK_STATE, numlock_state); manager->priv->old_state = numlock_state; } } return GDK_FILTER_CONTINUE; } static void numlock_install_xkb_callback (CsdKeyboardManager *manager) { if (!manager->priv->have_xkb) return; gdk_window_add_filter (NULL, numlock_xkb_callback, manager); } static guint _csd_settings_get_uint (GSettings *settings, const char *key) { guint value; g_settings_get (settings, key, "u", &value); return value; } static void apply_settings (GSettings *settings, const char *key, CsdKeyboardManager *manager) { XKeyboardControl kbdcontrol; gboolean repeat; gboolean click; guint interval; guint delay; int click_volume; int bell_volume; int bell_pitch; int bell_duration; CsdBellMode bell_mode; gboolean rnumlock; if (g_strcmp0 (key, KEY_NUMLOCK_STATE) == 0) return; repeat = g_settings_get_boolean (settings, KEY_REPEAT); click = g_settings_get_boolean (settings, KEY_CLICK); interval = _csd_settings_get_uint (settings, KEY_INTERVAL); delay = _csd_settings_get_uint (settings, KEY_DELAY); click_volume = g_settings_get_int (settings, KEY_CLICK_VOLUME); bell_pitch = g_settings_get_int (settings, KEY_BELL_PITCH); bell_duration = g_settings_get_int (settings, KEY_BELL_DURATION); bell_mode = g_settings_get_enum (settings, KEY_BELL_MODE); bell_volume = (bell_mode == CSD_BELL_MODE_ON) ? 50 : 0; gdk_error_trap_push (); if (repeat) { gboolean rate_set = FALSE; XAutoRepeatOn (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); /* Use XKB in preference */ rate_set = xkb_set_keyboard_autorepeat_rate (delay, interval); if (!rate_set) g_warning ("Neither XKeyboard not Xfree86's keyboard extensions are available,\n" "no way to support keyboard autorepeat rate settings"); } else { XAutoRepeatOff (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())); } /* as percentage from 0..100 inclusive */ if (click_volume < 0) { click_volume = 0; } else if (click_volume > 100) { click_volume = 100; } kbdcontrol.key_click_percent = click ? click_volume : 0; kbdcontrol.bell_percent = bell_volume; kbdcontrol.bell_pitch = bell_pitch; kbdcontrol.bell_duration = bell_duration; XChangeKeyboardControl (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), KBKeyClickPercent | KBBellPercent | KBBellPitch | KBBellDuration, &kbdcontrol); if (g_strcmp0 (key, "remember-numlock-state") == 0 || key == NULL) { rnumlock = g_settings_get_boolean (settings, "remember-numlock-state"); manager->priv->old_state = g_settings_get_enum (manager->priv->settings, KEY_NUMLOCK_STATE); if (manager->priv->have_xkb && rnumlock) numlock_set_xkb_state (manager->priv->old_state); } XSync (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), FALSE); gdk_error_trap_pop_ignored (); } void csd_keyboard_manager_apply_settings (CsdKeyboardManager *manager) { apply_settings (manager->priv->settings, NULL, manager); } static gboolean start_keyboard_idle_cb (CsdKeyboardManager *manager) { cinnamon_settings_profile_start (NULL); g_debug ("Starting keyboard manager"); manager->priv->have_xkb = 0; manager->priv->settings = g_settings_new (CSD_KEYBOARD_DIR); /* Essential - xkb initialization should happen before */ csd_keyboard_xkb_init (manager); numlock_xkb_init (manager); /* apply current settings before we install the callback */ csd_keyboard_manager_apply_settings (manager); g_signal_connect (G_OBJECT (manager->priv->settings), "changed", G_CALLBACK (apply_settings), manager); numlock_install_xkb_callback (manager); cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } gboolean csd_keyboard_manager_start (CsdKeyboardManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_keyboard_idle_cb, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_keyboard_manager_stop (CsdKeyboardManager *manager) { CsdKeyboardManagerPrivate *p = manager->priv; g_debug ("Stopping keyboard manager"); if (p->settings != NULL) { g_object_unref (p->settings); p->settings = NULL; } if (p->have_xkb) { gdk_window_remove_filter (NULL, numlock_xkb_callback, manager); } csd_keyboard_xkb_shutdown (); } static GObject * csd_keyboard_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdKeyboardManager *keyboard_manager; keyboard_manager = CSD_KEYBOARD_MANAGER (G_OBJECT_CLASS (csd_keyboard_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (keyboard_manager); } static void csd_keyboard_manager_class_init (CsdKeyboardManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_keyboard_manager_constructor; object_class->finalize = csd_keyboard_manager_finalize; g_type_class_add_private (klass, sizeof (CsdKeyboardManagerPrivate)); } static void csd_keyboard_manager_init (CsdKeyboardManager *manager) { manager->priv = CSD_KEYBOARD_MANAGER_GET_PRIVATE (manager); } static void csd_keyboard_manager_finalize (GObject *object) { CsdKeyboardManager *keyboard_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_KEYBOARD_MANAGER (object)); keyboard_manager = CSD_KEYBOARD_MANAGER (object); g_return_if_fail (keyboard_manager->priv != NULL); if (keyboard_manager->priv->start_idle_id != 0) { g_source_remove (keyboard_manager->priv->start_idle_id); keyboard_manager->priv->start_idle_id = 0; } G_OBJECT_CLASS (csd_keyboard_manager_parent_class)->finalize (object); } CsdKeyboardManager * csd_keyboard_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_KEYBOARD_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_KEYBOARD_MANAGER (manager_object); } cinnamon-settings-daemon-2.8.3/plugins/keyboard/csd-keyboard-xkb.h0000664000175000017500000000254112625665665024161 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * cinnamon-settings-keyboard-xkb.h * * Copyright (C) 2001 Udaltsoft * * Written by Sergey V. Oudaltsov * * 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_KEYBOARD_XKB_H #define __CSD_KEYBOARD_XKB_H #include #include "csd-keyboard-manager.h" void csd_keyboard_xkb_init (CsdKeyboardManager *manager); void csd_keyboard_xkb_shutdown (void); typedef void (*PostActivationCallback) (void *userData); void csd_keyboard_xkb_set_post_activation_callback (PostActivationCallback fun, void *userData); #endif cinnamon-settings-daemon-2.8.3/plugins/keyboard/csd-input-sources-switcher.c0000664000175000017500000003762512625665665026253 0ustar fabiofabio/* * Copyright (C) 2012 Red Hat, Inc. * * Written by: Rui Matos * * 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, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include #include #include #include #include "csd-enums.h" #include "csd-keygrab.h" #define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.cinnamon.desktop.input-sources" #define KEY_CURRENT_INPUT_SOURCE "current" #define KEY_INPUT_SOURCES "sources" #define CSD_KEYBOARD_DIR "org.cinnamon.settings-daemon.peripherals.keyboard" #define KEY_SWITCHER "input-sources-switcher" static GSettings *input_sources_settings; static Key *the_keys = NULL; static guint n_keys = 0; static guint master_keyboard_id = 0; static gboolean includes_caps = FALSE; static void do_switch (void) { GVariant *sources; gint i, n; /* FIXME: this is racy with the g-s-d media-keys plugin. Instead we should have a DBus API on g-s-d and poke it from here.*/ sources = g_settings_get_value (input_sources_settings, KEY_INPUT_SOURCES); n = g_variant_n_children (sources); if (n < 2) goto out; i = g_settings_get_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE) + 1; if (i >= n) i = 0; g_settings_set_uint (input_sources_settings, KEY_CURRENT_INPUT_SOURCE, i); out: g_variant_unref (sources); } static void init_keys (void) { GSettings *settings; settings = g_settings_new (CSD_KEYBOARD_DIR); switch (g_settings_get_enum (settings, KEY_SWITCHER)) { case CSD_INPUT_SOURCES_SWITCHER_SHIFT_L: n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_L: n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Alt_L; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_L: n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Control_L; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_SHIFT_R: n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_R; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_R: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Alt_R; the_keys[0].state = 0; the_keys[1].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[1].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_R: n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Control_R; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_SHIFT_L: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Alt_L; the_keys[1].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_SHIFT_R: n_keys = 4; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_R; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Alt_R; the_keys[1].state = GDK_SHIFT_MASK; the_keys[2].keysym = GDK_KEY_Shift_R; the_keys[2].state = GDK_MOD5_MASK; the_keys[3].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[3].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_SHIFT_L: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = GDK_CONTROL_MASK; the_keys[1].keysym = GDK_KEY_Control_L; the_keys[1].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_SHIFT_R: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_R; the_keys[0].state = GDK_CONTROL_MASK; the_keys[1].keysym = GDK_KEY_Control_R; the_keys[1].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_SHIFT_L_SHIFT_R: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = GDK_SHIFT_MASK; the_keys[1].keysym = GDK_KEY_Shift_R; the_keys[1].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_L_ALT_R: n_keys = 4; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Alt_L; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Alt_R; the_keys[1].state = GDK_MOD1_MASK; the_keys[2].keysym = GDK_KEY_Alt_L; the_keys[2].state = GDK_MOD5_MASK; the_keys[3].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[3].state = GDK_MOD1_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_L_CTRL_R: n_keys = 2; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Control_L; the_keys[0].state = GDK_CONTROL_MASK; the_keys[1].keysym = GDK_KEY_Control_R; the_keys[1].state = GDK_CONTROL_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_SHIFT: n_keys = 7; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Shift_L; the_keys[1].state = GDK_MOD5_MASK; the_keys[2].keysym = GDK_KEY_Shift_R; the_keys[2].state = GDK_MOD1_MASK; the_keys[3].keysym = GDK_KEY_Shift_R; the_keys[3].state = GDK_MOD5_MASK; the_keys[4].keysym = GDK_KEY_Alt_L; the_keys[4].state = GDK_SHIFT_MASK; the_keys[5].keysym = GDK_KEY_Alt_R; the_keys[5].state = GDK_SHIFT_MASK; the_keys[6].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[6].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_SHIFT: n_keys = 4; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Shift_L; the_keys[0].state = GDK_CONTROL_MASK; the_keys[1].keysym = GDK_KEY_Shift_R; the_keys[1].state = GDK_CONTROL_MASK; the_keys[2].keysym = GDK_KEY_Control_L; the_keys[2].state = GDK_SHIFT_MASK; the_keys[3].keysym = GDK_KEY_Control_R; the_keys[3].state = GDK_SHIFT_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_CTRL: n_keys = 7; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Control_L; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Control_L; the_keys[1].state = GDK_MOD5_MASK; the_keys[2].keysym = GDK_KEY_Control_R; the_keys[2].state = GDK_MOD1_MASK; the_keys[3].keysym = GDK_KEY_Control_R; the_keys[3].state = GDK_MOD5_MASK; the_keys[4].keysym = GDK_KEY_Alt_L; the_keys[4].state = GDK_CONTROL_MASK; the_keys[5].keysym = GDK_KEY_Alt_R; the_keys[5].state = GDK_CONTROL_MASK; the_keys[6].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[6].state = GDK_CONTROL_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CAPS: includes_caps = TRUE; n_keys = 1; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Caps_Lock; the_keys[0].state = 0; break; case CSD_INPUT_SOURCES_SWITCHER_SHIFT_CAPS: includes_caps = TRUE; n_keys = 3; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Caps_Lock; the_keys[0].state = GDK_SHIFT_MASK; the_keys[1].keysym = GDK_KEY_Shift_L; the_keys[1].state = GDK_LOCK_MASK; the_keys[2].keysym = GDK_KEY_Shift_R; the_keys[2].state = GDK_LOCK_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_ALT_CAPS: includes_caps = TRUE; n_keys = 5; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Caps_Lock; the_keys[0].state = GDK_MOD1_MASK; the_keys[1].keysym = GDK_KEY_Caps_Lock; the_keys[1].state = GDK_MOD5_MASK; the_keys[2].keysym = GDK_KEY_Alt_L; the_keys[2].state = GDK_LOCK_MASK; the_keys[3].keysym = GDK_KEY_Alt_R; the_keys[3].state = GDK_LOCK_MASK; the_keys[4].keysym = GDK_KEY_ISO_Level3_Shift; the_keys[4].state = GDK_LOCK_MASK; break; case CSD_INPUT_SOURCES_SWITCHER_CTRL_CAPS: includes_caps = TRUE; n_keys = 3; the_keys = g_new0 (Key, n_keys); the_keys[0].keysym = GDK_KEY_Caps_Lock; the_keys[0].state = GDK_CONTROL_MASK; the_keys[1].keysym = GDK_KEY_Control_L; the_keys[1].state = GDK_LOCK_MASK; the_keys[2].keysym = GDK_KEY_Control_R; the_keys[2].state = GDK_LOCK_MASK; break; } g_object_unref (settings); } static void free_keys (void) { gint i; for (i = 0; i < n_keys; ++i) g_free (the_keys[i].keycodes); g_free (the_keys); } static gboolean match_caps_locked (const Key *key, XIDeviceEvent *xev) { if (key->state & xev->mods.effective && key->keysym == XkbKeycodeToKeysym (xev->display, xev->detail, 0, 0)) return TRUE; return FALSE; } static gboolean match_modifier (const Key *key, XIEvent *xiev) { Key meta; /* When the grab is established with Caps Lock as the modifier (i.e. key->state == GDK_LOCK_MASK) we can't use match_xi2_key() as this modifier is black listed there, so we do the match ourselves. */ if (key->state == GDK_LOCK_MASK) return match_caps_locked (key, (XIDeviceEvent *) xiev); meta = *key; switch (key->keysym) { case GDK_KEY_Shift_L: case GDK_KEY_Shift_R: if (xiev->evtype == XI_KeyRelease) meta.state |= GDK_SHIFT_MASK; break; case GDK_KEY_Control_L: case GDK_KEY_Control_R: if (xiev->evtype == XI_KeyRelease) meta.state |= GDK_CONTROL_MASK; break; case GDK_KEY_ISO_Level3_Shift: if (xiev->evtype == XI_KeyRelease) meta.state |= GDK_MOD5_MASK; break; case GDK_KEY_Alt_L: case GDK_KEY_Alt_R: if (key->state == GDK_SHIFT_MASK) meta.keysym = key->keysym == GDK_KEY_Alt_L ? GDK_KEY_Meta_L : GDK_KEY_Meta_R; if (xiev->evtype == XI_KeyRelease) meta.state |= GDK_MOD1_MASK; break; } return match_xi2_key (&meta, (XIDeviceEvent *) xiev); } static gboolean matches_key (XIEvent *xiev) { gint i; for (i = 0; i < n_keys; ++i) if (match_modifier (&the_keys[i], xiev)) return TRUE; return FALSE; } /* Owen magic, ported to XI2 */ static GdkFilterReturn filter (XEvent *xevent, GdkEvent *event, gpointer data) { XIEvent *xiev; XIDeviceEvent *xev; XIGrabModifiers mods; XIEventMask evmask; unsigned char mask[(XI_LASTEVENT + 7)/8] = { 0 }; if (xevent->type != GenericEvent) return GDK_FILTER_CONTINUE; xiev = (XIEvent *) xevent->xcookie.data; if (xiev->evtype != XI_ButtonPress && xiev->evtype != XI_KeyPress && xiev->evtype != XI_KeyRelease) return GDK_FILTER_CONTINUE; xev = (XIDeviceEvent *) xiev; mods.modifiers = XIAnyModifier; XISetMask (mask, XI_ButtonPress); evmask.deviceid = XIAllMasterDevices; evmask.mask_len = sizeof (mask); evmask.mask = mask; if (xiev->evtype != XI_ButtonPress && matches_key (xiev)) { if (xiev->evtype == XI_KeyPress) { if (includes_caps) { do_switch (); XIUngrabDevice (xev->display, master_keyboard_id, xev->time); XkbLockModifiers (xev->display, XkbUseCoreKbd, LockMask, 0); } else { XIAllowEvents (xev->display, xev->deviceid, XISyncDevice, xev->time); XIGrabButton (xev->display, XIAllMasterDevices, XIAnyButton, xev->root, None, GrabModeSync, GrabModeSync, False, &evmask, 1, &mods); } } else { do_switch (); XIUngrabDevice (xev->display, master_keyboard_id, xev->time); XIUngrabButton (xev->display, XIAllMasterDevices, XIAnyButton, xev->root, 1, &mods); } } else { XIAllowEvents (xev->display, xev->deviceid, XIReplayDevice, xev->time); XIUngrabDevice (xev->display, master_keyboard_id, xev->time); XIUngrabButton (xev->display, XIAllMasterDevices, XIAnyButton, xev->root, 1, &mods); } return GDK_FILTER_CONTINUE; } static void grab_key (Key *key, GdkDisplay *display, GSList *screens) { GdkKeymapKey *keys; gboolean has_entries; GArray *keycodes; gint n, i; has_entries = gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), key->keysym, &keys, &n); if (!has_entries) return; keycodes = g_array_sized_new (TRUE, TRUE, sizeof (guint), n); for (i = 0; i < n; ++i) g_array_append_val (keycodes, keys[i].keycode); key->keycodes = (guint *) g_array_free (keycodes, FALSE); gdk_x11_display_error_trap_push (display); grab_key_unsafe (key, CSD_KEYGRAB_ALLOW_UNMODIFIED | CSD_KEYGRAB_SYNCHRONOUS, screens); gdk_x11_display_error_trap_pop_ignored (display); g_free (keys); } static guint get_master_keyboard_id (GdkDisplay *display) { XIDeviceInfo *info; guint id; int i, n; id = 0; info = XIQueryDevice (GDK_DISPLAY_XDISPLAY (display), XIAllMasterDevices, &n); for (i = 0; i < n; ++i) if (info[i].use == XIMasterKeyboard && info[i].enabled) { id = info[i].deviceid; break; } XIFreeDeviceInfo (info); return id; } static void set_input_sources_switcher (void) { GdkDisplay *display; gint n_screens; GSList *screens, *l; gint i; display = gdk_display_get_default (); n_screens = gdk_display_get_n_screens (display); screens = NULL; for (i = 0; i < n_screens; ++i) screens = g_slist_prepend (screens, gdk_display_get_screen (display, i)); for (i = 0; i < n_keys; ++i) grab_key (&the_keys[i], display, screens); for (l = screens; l; l = l->next) { GdkScreen *screen; screen = (GdkScreen *) l->data; gdk_window_add_filter (gdk_screen_get_root_window (screen), (GdkFilterFunc) filter, screen); } g_slist_free (screens); master_keyboard_id = get_master_keyboard_id (display); } int main (int argc, char *argv[]) { gtk_init (&argc, &argv); init_keys (); if (n_keys == 0) { g_warning ("No shortcut defined, exiting"); return -1; } input_sources_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR); set_input_sources_switcher (); gtk_main (); g_object_unref (input_sources_settings); free_keys (); return 0; } cinnamon-settings-daemon-2.8.3/plugins/keyboard/kbd-capslock-off.png0000664000175000017500000000316212625665665024472 0ustar fabiofabio‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsœœn›¡NtEXtSoftwarewww.inkscape.org›î<ïIDATxœå›MŒEÇÿ5‹|È.‰D‘ÁàM#HÀ„(ÊW<¨¬9p °šOz‘ˆGãA=iL< DÀ€»$‚ Q? +Á]I0a•Øýy蚥¦¦fvº»&;ÿd’éž÷Þÿ½šªêªW¯ Ð.i±¤Ù’f>’Ôøœ—ÔmŒ(ÚÇèî6ŸƒdÇ °x ¸ÿvÇUÀD`p Ît- ÇÀ·;Þ% ¸P@еpØ”òúor¿\ÒNI§PPåX—*ç„ö¶NKzÙ³?…N~3ƒ üSCÀ  xèhÀv‡•í²ºC ðfÞŠØ,úGqh?°˜oºµµÎ~`AŒë9ÓIýYý00¿@þù–£Î"ˆÛ€]uˆO+£×ög¥å¬…]@[,²6`w ¢Àv"ÌÆü*Yî5|Û¥êüó—%bÉëßëK°'ä5ÞYÃðY`N¤r˜c} !Ûœ@2Û‡&¼n`jär˜j}ó1HÚ§És>ô¨;ÛŒÁ—a!ÔúI³N ¼È¹ÜLݾìpÍ ‡5°, |ƒ&˜ðÉÄz:¬M±|PÜ~‹|’G¤SÔ{dëJ§ë*5)ìŸZ,m¨¥0è (D_ᑬäxŸ§ âñq‘P>Ø>Û)ËõQ€ë“‚¸B{‡!Á£ÁèànàÏ×_DØ=øæ¸ŽûBÓ©Þw’d^ 8TÆkqú[éalޱ<¹­v¾—ñiÎHZê|ÿ]Ò9çzyAœ~,FÒª‘+`¯×BCuÇ…ÀÏÀ{Îõ5`Q¼¡¾¯üãdàª÷ã‘ØNX®w¼F^ [Òóð‡bš]ÒÍã)½8ð”óý_I:×ïKºRC6z÷f„`Às% œÀ,I9·ŽcΔ/Œ1¿IrçE@¨gf†É?g 6@Ÿâc“$7p0 ãÞ›"ic~ø±ÍÕ „žØ¬$gzeôwdÚIÖéU“dD?z¼XÏÞH6Sóœ[=Ƙ¿}9{ î6þ#r+qPÕnÅ6÷9U®2÷Ö‘Ý-©üd(Iz¦(§FPä 9çs»õÔÉÕ“ìápäÿ¦Dô'8ª'†xØ$É-lè6Æ Õ6Æ Kêö|ÙÑŸªá>NÅ6€Ÿƒ› ¼>ŠŽŸu^!éíHþ4Ôí@GÞµ0WÒ£ÞíµL-æcNäô§CÕµ}¡! I³òY¬—4)‚I’ÖE°3+p¯oœ*÷ãe,—t*+“è–9·$ý”Ò̃º9–mõæÊ5œ/d; ¬õì}–ÁÆÇž,ÃǵÜ—Œ1ÿ¨r7&I È—ñ3¼¡¥ïhðwo«3ú"‹>øåH "I ŠLkq’ÁKÞ³|r;w¿:v.÷fô)ßféæ m¤aOïÙ,d’^”4͹,Œ1×U¹4žfmg JbvîÀWVJ¾öl¬Éètù`ÃÍåÍ`#”?Ü<œ’ì ຣÿ30.­ÓŽ=|çØ»<žÒFè`d[Hp

ÜðÑðÉájù“{¼áÙÜ™B7t4v˜XKaM@a¬ŽÖ.™±]îD@i¬ŸõÏ–ÇJDc'OŒÍ™Æc´z‘”5ÖºerŽÑ΀ÁrOhšá@…’ŽñÖ-•µ­],mÉZ·\Þ#î¤_˜ðœhÝWf§ší¥©ƒd|i*ïksK%½)in µ˜¯Í”ôŠ1æ‹:qA²ZCx+]zIÊz›g—J’OØB’Yj¤Û¦ÅI1çV ¨!Š à’W[÷PrOƒ«$%|/P@Ùž”sh$áÅJŠ±Ò¼>NÉajê„jüLÍj¹ÑL‹IEND®B`‚cinnamon-settings-daemon-2.8.3/plugins/keyboard/csd-keyboard-plugin.h0000664000175000017500000000432312625665665024673 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. * */ #ifndef __CSD_KEYBOARD_PLUGIN_H__ #define __CSD_KEYBOARD_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_KEYBOARD_PLUGIN (csd_keyboard_plugin_get_type ()) #define CSD_KEYBOARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_KEYBOARD_PLUGIN, CsdKeyboardPlugin)) #define CSD_KEYBOARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_KEYBOARD_PLUGIN, CsdKeyboardPluginClass)) #define CSD_IS_KEYBOARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_KEYBOARD_PLUGIN)) #define CSD_IS_KEYBOARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_KEYBOARD_PLUGIN)) #define CSD_KEYBOARD_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_KEYBOARD_PLUGIN, CsdKeyboardPluginClass)) typedef struct CsdKeyboardPluginPrivate CsdKeyboardPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdKeyboardPluginPrivate *priv; } CsdKeyboardPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdKeyboardPluginClass; GType csd_keyboard_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_KEYBOARD_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/keyboard/csd-keyboard-manager.h0000664000175000017500000000466512625665665025020 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_KEYBOARD_MANAGER_H #define __CSD_KEYBOARD_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_KEYBOARD_MANAGER (csd_keyboard_manager_get_type ()) #define CSD_KEYBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_KEYBOARD_MANAGER, CsdKeyboardManager)) #define CSD_KEYBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_KEYBOARD_MANAGER, CsdKeyboardManagerClass)) #define CSD_IS_KEYBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_KEYBOARD_MANAGER)) #define CSD_IS_KEYBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_KEYBOARD_MANAGER)) #define CSD_KEYBOARD_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_KEYBOARD_MANAGER, CsdKeyboardManagerClass)) typedef struct CsdKeyboardManagerPrivate CsdKeyboardManagerPrivate; typedef struct { GObject parent; CsdKeyboardManagerPrivate *priv; } CsdKeyboardManager; typedef struct { GObjectClass parent_class; } CsdKeyboardManagerClass; GType csd_keyboard_manager_get_type (void); CsdKeyboardManager * csd_keyboard_manager_new (void); gboolean csd_keyboard_manager_start (CsdKeyboardManager *manager, GError **error); void csd_keyboard_manager_stop (CsdKeyboardManager *manager); void csd_keyboard_manager_apply_settings (CsdKeyboardManager *manager); G_END_DECLS #endif /* __CSD_KEYBOARD_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/keyboard/kbd-capslock-on.png0000664000175000017500000000272012625665665024333 0ustar fabiofabio‰PNG  IHDR@@ªiqÞsRGB®ÎébKGDÿÿÿ ½§“ pHYsœœn›¡NtIMEÚ:=¨¾PIDATxÚå›KhE€¿{í#‰¡Å4Y””¸SZ¸|ä!±u!nJk¤±´»(iDtck] Ò…º(ŠÚE´4©Þ’¦B >j‹F%!M VÓúHŽ‹LÈdrþ{ïÿ™ëMî÷ÿï™óš3gÎ93“"ð#P Ü4›”0©´q`0Ó¬´G N`ŸÀiR`»!Ð/°_ ¾Ô…^+pHà¼À\¡£ÚœÀˆÀaõ¥$xZ Kàr¡£ÚÏ{ÒIùO%¾8Ü£Û´3×q|Bu \—€§S0PìQoÈä1R³Ã½w Ô仯Àöš¾³yÐ9+ÐP,á[®ä`h@ [`£z ®4¯´„¾+‡WÿD 9 ýfC#۪тp…À±,„/ tq všQü¨ð)|_¡z|xãWŸÃÆ[Ÿ%dùßZK`n5¼¨–àcÎkˆGšJ(i2²ÇˆÊ¥5¢¥œnÞ=hDžÍ’Ä<ˆæ€R^«‡E綃åŽîd ÿÔfýþ ³Þ;Ñ<©T¶Û:¥TrB˜ã=YtÞ8n½ÿ-poºš…÷/üY%pÝùs8)¾æ(¹SàA'hy=ía%G¨F`»2{0p³À/Äe>·¾ ¬ @¿W‘sGØ¢ÀŸ 0³4—L˜ßvœÞ<€¾&ScšÅí)û™ÀÀÃÖïà-ëý `*Öףɴ ŽYL0¿Í×,+0ýÖÿˆn™Iù˜rd=¡YÀdíïei!£ÀØßnºð1©Y€[@  ù§8q«SmâôeNÒ#Cn'¸˜dênëÓP ®±<2™f©ò·. VY@1ÒÜÇœ(óTØ>W†4ðh1òæ`SÀìóÙfým¶Z½É῱à‘yt ,w ~_½³öÏF§`txÙ둟eÓ½2°Ü\­À‹9úÔ*8^ ¥Ž*!bsÛ&0ãá0ÄŒ,u¢I¦£‹ûh:Âëoöú®ó€g°ÛM¦ÉJ'·óò‹ ´]´[Ÿ¦ïb¢¹ÃšíÙüGVk’ ìrð}PŽw»‚¤Ã! "ï;øž*‡»1ûžç‚Èi [qÝ«¸ê¬åUà¹IàG ÏUÛ äI“oŸ °ÁWQTà7ãJ0rÇ\Ï{,ŠÖ¹@Ÿú(‹ |æàØ™$pæ\8´²øy ð@Òþ±ú/P™@)¯œ¢é}1qh#‡¢jvãI¶Æ^1›« -q'ð’ƒóHL rå¹,°6ªÃÎ2ØíÊer_®âíñ 9S mèÈÁj<"“‰ƒ¤¼Idå{L.K<^>%-äå{Tv!·/ëÃÒ–Êó¸¼âÊ:”ç•'N(¥KS™B/M%½6×¼ l‹ÑÍçµ¹ À3)øèÿ\†R&‹/âÅÉ s¬·t²TSO8`*K³„ž5‡9†8Cä[ÌÕÖ•’{œvÝT¬Ÿ ql/±ÈSUÌ_ŸßB¼ëócÌo¦þ’¿ÿN|HƒÌ×0IEND®B`‚cinnamon-settings-daemon-2.8.3/plugins/keyboard/kbd-numlock-on.png0000664000175000017500000000306712625665665024211 0ustar fabiofabio‰PNG  IHDR@@ªiqÞsRGB®ÎébKGDÿÿÿ ½§“ pHYsœœn›¡NtIMEÚPˆL·IDATxÚå›mh•UÀÏu9Ý –åÈm±ޖƒ¤–‹ l­†}Ó^VN˜¬iÑ—JòCôQ"(êKA˜¢Ó&R¹†Óˆ¦®Fâ\&Wr,Zlmmÿ>ܳ|8û?÷>÷î<×»ÝçÃó<çüßžsþoç<"n%@°(W:@\é#ÀqÆYlM`­@»À!IɰO Ø.P‘ëL¯è˜]ÓA}Và´ÀN¢\b<&Ð*p)¦ƒúe­±…Òï-ùf`P›Æ´qk¯cé„’4`^ñ 'Û½R 7ÄŸšèØ%°^ 4ìR3v—™;Ï1Êl1_/p%A=með•X=)p^¨šùÖZýkºñ×ɬFkˆ— ìM‚øœ@K·`‹ÁDÏ^e.™ß€è_nÚ8CëÓmhÐhÛïDIþü5Æ0Æu%¸ØóàaêòEª M­­™­PxÇVå 'ºÊЦ)ÆútU˜ºá\dÞÂp€‰¬LPoÀž¯&ǛٚN8ÀãÚ¾‘EÒŒbÔ¬ÃaLËÊÄîE’w+|œMj²ž prbމ+¨Ø$°A`uD~‚æ,m šP(0ªLhqDPÀKGÆýòÀ.•¬ñµPºHÜ©ùöŽÙ p*d¬?(ð¤C!h±ÃNmàwÊÀ:4üበL(߯\ ÁP6üÓZÈiÇÝ=¯8cÁ ¼.ð‰3*^è·Æ ÜáH=Šð+ü¶)Rj‹ Žx0`ìJÏ­ñ:@›Âßvÿ€ƒJ&§ÌÒ;oI}GˆsÑ7çOû%Uì~xîc±²û m¶`ž cNöXóÞr´ ú”¡$FâÐb…5þK8ï·žñ`6ļAëùaGÁæ©hˆUÊà#Úö<rÞ0ã{®qt ñ´.Æõã)u€p¹õ<rÞ5kìm(Î4›ÆS¹&€qþr€ÐføöóŠ­wëJŒái<ŒâŽöÜUë9ìÙ޽ʻ[ÑϦX«à™¯µ¶Iy·rÑ ÀKoŸð½ºxM’Ççë±l Êö0å{~øB;êxxÝWð¢"°ÀHå.¿T\÷à3&®»Õð‰å<ð«ÙßUÀ=>FGHTü¯˜‘4oµG*ÓvGk³ïï–'ÁsøèʆbÚ¾pɽS< t§,'Çß.o%¸:…Eq¾ü­D Ô‘/àÄ>`ŸÀFàQãà˜%ÿ‰ÿ}p§oêð•ƒX ”ùµª ‡ŸBéxp’D"ôVàn+†¸ìµ–[ˆÇ€ ʇfn\k·Ÿ~Gp5žF" ‡3\¦…¦jŽŽ WõAápd ‘ ‰|Ï¢ã #¸ZBäPª”Q›#äS%B<7­ÃØß%½â«tSbív*ÊyRÔÀî7ï <#‰ø¾Pà&*—•SÝ)ÝW––]k:QZü[ù˜ÀUiç´«4˜Á¯¥Å´QŒ(HÖG:ëí`¤K¸ÜàôhLày~ ¨ù›øÞ(ÀJÇÌkGc—Ä—õ¬ [€O-8C@mÈ„fREgœ¦†<8E‰‘€[c}zÁƒ’iã–ðñø`ÊÔ¼@Ó.h `)–Èô¦$¿‹¤ °ü-“óÍßBIðü-•5ò»XÚ'„ü,—WtBþ]˜P¬C~^™±ü„\º4Õ›i µÐksMÀ;„;ôœk.¯Í »=8z#Í'°% ”Žªš²Þ¹ÒL>¡Ãd–f"`zÆsvJ¢¾'§’5æjë€Jа}Âd¬·E•¥ö² Œb•hU¤w}þ‰ëóGIßÁñ8n. !IEND®B`‚cinnamon-settings-daemon-2.8.3/plugins/keyboard/Makefile.am0000664000175000017500000000276712625665665022725 0ustar fabiofabioNULL = plugin_name = keyboard plugin_LTLIBRARIES = \ libkeyboard.la \ $(NULL) themedir = $(pkgdatadir)/icons/hicolor size = 64x64 context = devices iconsdir = $(themedir)/$(size)/$(context) icons_DATA = \ kbd-capslock-off.png kbd-numlock-off.png kbd-scrolllock-off.png \ kbd-capslock-on.png kbd-numlock-on.png kbd-scrolllock-on.png libkeyboard_la_SOURCES = \ csd-keyboard-plugin.h \ csd-keyboard-plugin.c \ csd-keyboard-manager.h \ csd-keyboard-manager.c \ csd-keyboard-xkb.h \ csd-keyboard-xkb.c \ delayed-dialog.h \ delayed-dialog.c \ gkbd-configuration.c \ gkbd-configuration.h \ $(NULL) libkeyboard_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/data \ -DDATADIR=\""$(pkgdatadir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libkeyboard_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(APPINDICATOR_CFLAGS) \ $(KEYBOARD_CFLAGS) \ $(AM_CFLAGS) libkeyboard_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) \ $(NULL) libkeyboard_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(XF86MISC_LIBS) \ $(KEYBOARD_LIBS) \ $(APPINDICATOR_LIBS) \ $(NULL) plugin_in_files = \ keyboard.cinnamon-settings-plugin.in \ $(NULL) plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ $(icons_DATA) \ $(plugin_in_files) \ $(ui_DATA) \ $(NULL) CLEANFILES = \ $(plugin_DATA) \ $(NULL) DISTCLEANFILES = \ $(plugin_DATA) \ $(NULL) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/keyboard/kbd-scrolllock-off.png0000664000175000017500000000267312625665665025050 0ustar fabiofabio‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYsœœn›¡NtEXtSoftwarewww.inkscape.org›î<8IDATxœí›ÏkUGÇ¿ó"F4"RЊJK6B„nºSˆMš?@hi¡u!Dbê? Ø¢….]»î"µj(i\¡(qcÁš]SlJÒüútqç™››s_ÞË›y/ôå ÷Î9ßsÎ;wæÌ§ÈZ$•ô¾¤ÃÆO’^¿IIœss±m àðpX`ëXî_ïÕÛ¯’ö—€q`µ §ó° <.{ëíï[ ˜Žàt^}@¡Zû]•ÎwIúNÒÉ Äæ´þ]—Ö -èšôsn¸™êFÊxR+À0´ûËн߷ô²+eðÜŽÔÂw§€™M ¾Zðµz]ÛpΧBøXʘ^Jê£@GDþÏ‘‡ 7qp£ñМ8ßžnÏ™‡@S(²&`(‡h Àh¼» ž{9Ƕ¡ A(ñägξTk_§·Åì Õ*ïÍQüh äCÕÚ¼M¶6&ŒöÖ€÷8؇ªð¶e±@¥_’ï¼õ©{±/ÂÁê 3T2OÀžäÌÆèöÀÁÀúÚ°Ç„ûå*øÈ^&€ž{ëíÄþ:|¼™`xb„40ÅwÇ댠{Àðã¥>ÙÀg†ÐDI¡­Ø“âxCøW¡€=YêËh¦ à3<`/ðk EàzžnßWXùà¢Ñx4´Qžë°”áZŽFà²Ö—­†Œ†Á6À ìj¸¯ÃàzœmÔÊÆuw”$É?ûô‹X*I®”Ë™]J¯âsŒÅÁ­'õ¿ˆ#ò¹¤Ó’vå4Y–TÝüÝFÖ'éÓ´a?g"´B€dFÀAàOÊK˜ž Ìmõð{Å›û€ùÌͱxž›^÷"ùKØb÷|T•¯4øÇ2< @KAɦEv&öS`òfIÓ’®JúAÒ#£Ù_’J—´()tz+ëS³¤³ú§Ð˜|€+çÃÈœígAkÛSiLÅ4FÒnãÚbdÎ)ãÚa+sι¿#Ól\û7&¡÷)»Ïhàµâ£æðÈú¶€Ô€ÔB=AQ©o½zÀ†Þ¾í`CZ(c»JÔ<Þ§líI:ÓÕgkcä’Õp70i4ޱ5v=„’m²à坨[cÓäíFç à›£$)ò7)Žžú=GÞæh~É É÷úwC(øö8I%(Àк½~k{üé¦8g/ ©. ©×ëÎ+°fƒ¦‚š”ÈxÂãuæ•ÈŒT¢¤±‹¤¼²Æ-“K)í5{Âÿ»P2¥¼qKe=AcK{²Æ-—Ï÷Òˆ&2F4î‘™”QÛíÐÔ[<4Uí±¹s’¾•ôab!Í=•tÅ9÷K2aA²€:½”Ž…)’²ÞzímnI>áIf©œn[)VHŠ9/’Ôm_äû€ÛlL¹W‚y’Œõ—ÎR´Í°OI%ÚªìøüK%Ççÿ‰ißv@é‹É?rIEND®B`‚cinnamon-settings-daemon-2.8.3/plugins/keyboard/kbd-scrolllock-on.png0000664000175000017500000000247112625665665024706 0ustar fabiofabio‰PNG  IHDR@@ªiqÞsRGB®ÎébKGDÿÿÿ ½§“ pHYsœœn›¡NtIMEÚ)øzè¹IDATxÚí›ÏkTWÇ?o#qD¤Pƒ––l„º ÄBlÚü…vÀZB$¦þ[´Ð¥k×.âÏ¡ŒØJã"EQ$CmÜi±)±“Œ§‹Üâã͹3o2÷¼<<¸›÷î;ßsν÷Ü{~ÜãG >( `IióÀ–yÛý_ Üx% l¯n |#p0ïBï8#0+𺠡}íµÀ}³Ýy¼ PX4Ú×þ8)Ph—ÿ¨MáG€€~[N¬u6¡Ø­ÇÀ·”³õ^JŠ‘ª ÌL ô ìNA{·ë;åþ­¥À¹-Л•ðCÏš0TøR '^£Un‚ùL`ÈZøR«þ«À !þ Ãh´k”,€· \lüX`4Ã%8ê0}ü\ØRøiКÀdk¼ÁÝgÒñ ñ6D Fþ…Àp¶áaÇ‹:B¬yðœ@_ŽÎ"}Ž'×ÒF‰y Þ=9<‰îq¼i†q¨Ub½ž­n.Â'”0çÙ"{[!Tñ¬ù>¦÷,Í&ÜNKàcµ6þ°À†QÛ>I³µ ìŒüT€Õ&]'"xxŒQò»×о,‚¢ –ÁªE$ÊájAÑýÉN¿e¿[ëIpÄO ‹ÏjOe‘8¤(`Uà¼Ñèk‰‘3ZÇó¥Æ.Ä”Psi²n-5¶èÍF |–ErÔ…È_Æ0Æ „÷%GKÍöëß³H»JP¸a4õµôøÃ¦ƒ)p"‹ W]þDà°ð¾‰‘´2)‘ }àq4}%2•Vˆtv‘”#Ö¹er1¢[(#Þ¹¥² ³‹¥cJèÌryÅ&tÞ… ewèÌ+3‰sBž.MU6ziªÝks'€ïZø-äµ¹‡À¹~ÞÌm(r^ä|†'\Yo¼<.žpÊE–jB×\1çiÑ+¹:–îsW[¯)!÷VÚŠ‹X:JĤTÆ.Ö+Ñ>¤µëóOY¿>ÿ%ÿ üë»-u"ÌIEND®B`‚cinnamon-settings-daemon-2.8.3/plugins/keyboard/csd-keyboard-plugin.c0000664000175000017500000000623112625665665024666 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 "cinnamon-settings-plugin.h" #include "csd-keyboard-plugin.h" #include "csd-keyboard-manager.h" struct CsdKeyboardPluginPrivate { CsdKeyboardManager *manager; }; #define CSD_KEYBOARD_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_KEYBOARD_PLUGIN, CsdKeyboardPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdKeyboardPlugin, csd_keyboard_plugin) static void csd_keyboard_plugin_init (CsdKeyboardPlugin *plugin) { plugin->priv = CSD_KEYBOARD_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdKeyboardPlugin initializing"); plugin->priv->manager = csd_keyboard_manager_new (); } static void csd_keyboard_plugin_finalize (GObject *object) { CsdKeyboardPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_KEYBOARD_PLUGIN (object)); g_debug ("CsdKeyboardPlugin finalizing"); plugin = CSD_KEYBOARD_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_keyboard_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating keyboard plugin"); error = NULL; res = csd_keyboard_manager_start (CSD_KEYBOARD_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start keyboard manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating keyboard plugin"); csd_keyboard_manager_stop (CSD_KEYBOARD_PLUGIN (plugin)->priv->manager); } static void csd_keyboard_plugin_class_init (CsdKeyboardPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_keyboard_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdKeyboardPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/automount/0000775000175000017500000000000012625665665021110 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/automount/csd-automount-manager.h0000664000175000017500000000461612625665665025502 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-2.8.3/plugins/automount/test-automount.c0000664000175000017500000000033112625665665024261 0ustar fabiofabio#define NEW csd_automount_manager_new #define START csd_automount_manager_start #define STOP csd_automount_manager_stop #define MANAGER CsdAutomountManager #include "csd-automount-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/automount/csd-autorun.c0000664000175000017500000007076012625665665023532 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); gtk_icon_info_free (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 (GTK_STOCK_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 (GTK_STOCK_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_error_trap_push (); status = XkbGetState (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), XkbUseCoreKbd, &state); gdk_error_trap_pop_ignored (); 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 (); hbox = gtk_hbox_new (FALSE, 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_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); 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_vbox_new (FALSE, 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_misc_set_alignment (GTK_MISC (label), 0.0, 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_misc_set_alignment (GTK_MISC (label), 0.0, 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), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); if (g_mount_can_eject (mount)) { GtkWidget *eject_image; eject_button = gtk_button_new_with_mnemonic (_("_Eject")); eject_image = gtk_image_new_from_icon_name ("media-eject", GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (eject_button), eject_image); 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; } cinnamon-settings-daemon-2.8.3/plugins/automount/csd-automount-plugin.c0000664000175000017500000000633112625665665025355 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Tomas Bzatek */ #include "config.h" #include #include #include "cinnamon-settings-plugin.h" #include "csd-automount-plugin.h" #include "csd-automount-manager.h" struct CsdAutomountPluginPrivate { CsdAutomountManager *manager; }; #define CSD_AUTOMOUNT_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_AUTOMOUNT_PLUGIN, CsdAutomountPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdAutomountPlugin, csd_automount_plugin) static void csd_automount_plugin_init (CsdAutomountPlugin *plugin) { plugin->priv = CSD_AUTOMOUNT_PLUGIN_GET_PRIVATE (plugin); g_debug ("Automount plugin initializing"); plugin->priv->manager = csd_automount_manager_new (); } static void csd_automount_plugin_finalize (GObject *object) { CsdAutomountPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_AUTOMOUNT_PLUGIN (object)); g_debug ("Automount plugin finalizing"); plugin = CSD_AUTOMOUNT_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_automount_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating automount plugin"); error = NULL; res = csd_automount_manager_start (CSD_AUTOMOUNT_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start automount manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating automount plugin"); csd_automount_manager_stop (CSD_AUTOMOUNT_PLUGIN (plugin)->priv->manager); } static void csd_automount_plugin_class_init (CsdAutomountPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_automount_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdAutomountPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/automount/csd-automount-plugin.h0000664000175000017500000000443012625665665025360 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Tomas Bzatek */ #ifndef __CSD_AUTOMOUNT_PLUGIN_H__ #define __CSD_AUTOMOUNT_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_AUTOMOUNT_PLUGIN (csd_automount_plugin_get_type ()) #define CSD_AUTOMOUNT_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_AUTOMOUNT_PLUGIN, CsdAutomountPlugin)) #define CSD_AUTOMOUNT_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_AUTOMOUNT_PLUGIN, CsdAutomountPluginClass)) #define CSD_IS_AUTOMOUNT_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_AUTOMOUNT_PLUGIN)) #define CSD_IS_AUTOMOUNT_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_AUTOMOUNT_PLUGIN)) #define CSD_AUTOMOUNT_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_AUTOMOUNT_PLUGIN, CsdAutomountPluginClass)) typedef struct CsdAutomountPluginPrivate CsdAutomountPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdAutomountPluginPrivate *priv; } CsdAutomountPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdAutomountPluginClass; GType csd_automount_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_AUTOMOUNT_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/automount/csd-automount-manager.c0000664000175000017500000004163012625665665025472 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; 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; }; static void csd_automount_manager_class_init (CsdAutomountManagerClass *klass); static void csd_automount_manager_init (CsdAutomountManager *csd_automount_manager); 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); do_initialize_screensaver (manager); 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"); 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->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-2.8.3/plugins/automount/automount.cinnamon-settings-plugin.in0000664000175000017500000000025312625665665030426 0ustar fabiofabio[Cinnamon Settings Plugin] Module=automount IAge=0 _Name=Automount _Description=Automounter plugin Authors=Tomas Bzatek Copyright=Copyright © 2010 Red Hat, Inc. Website= cinnamon-settings-daemon-2.8.3/plugins/automount/csd-autorun.h0000664000175000017500000000316512625665665023532 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_allow_autorun_for_volume (GVolume *volume); void csd_allow_autorun_for_volume_finish (GVolume *volume); #endif /* __CSD_AUTORUN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/automount/Makefile.am0000664000175000017500000000327712625665665023155 0ustar fabiofabioNULL = plugin_name = automount libexec_PROGRAMS = csd-test-automount csd_test_automount_SOURCES = \ test-automount.c \ csd-automount-manager.h \ csd-automount-manager.c \ csd-autorun.c \ csd-autorun.h \ $(NULL) csd_test_automount_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_test_automount_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(LOGIND_CFLAGS) \ $(AUTOMOUNT_CFLAGS) $(AM_CFLAGS) csd_test_automount_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(SETTINGS_PLUGIN_LIBS) \ $(LOGIND_LIBS) \ $(AUTOMOUNT_LIBS) \ $(NULL) plugin_LTLIBRARIES = \ libautomount.la \ $(NULL) libautomount_la_SOURCES = \ csd-automount-plugin.h \ csd-automount-plugin.c \ csd-automount-manager.h \ csd-automount-manager.c \ csd-autorun.c \ csd-autorun.h \ $(NULL) libautomount_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libautomount_la_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(LOGIND_CFLAGS) \ $(AUTOMOUNT_CFLAGS) \ $(AM_CFLAGS) libautomount_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) \ $(NULL) libautomount_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(LOGIND_LIBS) \ $(AUTOMOUNT_LIBS) \ $(NULL) plugin_in_files = \ automount.cinnamon-settings-plugin.in \ $(NULL) plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) \ $(NULL) CLEANFILES = \ $(plugin_DATA) \ $(NULL) DISTCLEANFILES = \ $(plugin_DATA) \ $(NULL) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/smartcard/0000775000175000017500000000000012625665665021035 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/smartcard/csd-smartcard-manager.h0000664000175000017500000000716312625665665025354 0ustar fabiofabio/* csd-smartcard-manager.h - object for monitoring smartcard insertion and * removal events * * Copyright (C) 2006, 2009 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. * * Written by: Ray Strode */ #ifndef CSD_SMARTCARD_MANAGER_H #define CSD_SMARTCARD_MANAGER_H #define CSD_SMARTCARD_ENABLE_INTERNAL_API #include "csd-smartcard.h" #include #include G_BEGIN_DECLS #define CSD_TYPE_SMARTCARD_MANAGER (csd_smartcard_manager_get_type ()) #define CSD_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSD_TYPE_SMARTCARD_MANAGER, CsdSmartcardManager)) #define CSD_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSD_TYPE_SMARTCARD_MANAGER, CsdSmartcardManagerClass)) #define CSD_IS_SMARTCARD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_SMARTCARD_MANAGER)) #define CSD_IS_SMARTCARD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_SMARTCARD_MANAGER)) #define CSD_SMARTCARD_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), CSD_TYPE_SMARTCARD_MANAGER, CsdSmartcardManagerClass)) #define CSD_SMARTCARD_MANAGER_ERROR (csd_smartcard_manager_error_quark ()) typedef struct _CsdSmartcardManager CsdSmartcardManager; typedef struct _CsdSmartcardManagerClass CsdSmartcardManagerClass; typedef struct _CsdSmartcardManagerPrivate CsdSmartcardManagerPrivate; typedef enum _CsdSmartcardManagerError CsdSmartcardManagerError; struct _CsdSmartcardManager { GObject parent; /*< private > */ CsdSmartcardManagerPrivate *priv; }; struct _CsdSmartcardManagerClass { GObjectClass parent_class; /* Signals */ void (*smartcard_inserted) (CsdSmartcardManager *manager, CsdSmartcard *token); void (*smartcard_removed) (CsdSmartcardManager *manager, CsdSmartcard *token); void (*error) (CsdSmartcardManager *manager, GError *error); }; enum _CsdSmartcardManagerError { CSD_SMARTCARD_MANAGER_ERROR_GENERIC = 0, CSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, CSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, CSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, CSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS }; GType csd_smartcard_manager_get_type (void) G_GNUC_CONST; GQuark csd_smartcard_manager_error_quark (void) G_GNUC_CONST; CsdSmartcardManager *csd_smartcard_manager_new_default (void); CsdSmartcardManager *csd_smartcard_manager_new (const char *module); gboolean csd_smartcard_manager_start (CsdSmartcardManager *manager, GError **error); void csd_smartcard_manager_stop (CsdSmartcardManager *manager); char *csd_smartcard_manager_get_module_path (CsdSmartcardManager *manager); gboolean csd_smartcard_manager_login_card_is_inserted (CsdSmartcardManager *manager); G_END_DECLS #endif /* CSD_SMARTCARD_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/smartcard/csd-smartcard.c0000664000175000017500000004424412625665665023740 0ustar fabiofabio/* csd-smartcard.c - smartcard object * * Copyright (C) 2006 Ray Strode * * 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" #define CSD_SMARTCARD_ENABLE_INTERNAL_API #include "csd-smartcard.h" #include #include #include #include #include #include #include #include #include #include #include struct _CsdSmartcardPrivate { SECMODModule *module; CsdSmartcardState state; CK_SLOT_ID slot_id; int slot_series; PK11SlotInfo *slot; char *name; CERTCertificate *signing_certificate; CERTCertificate *encryption_certificate; }; static void csd_smartcard_finalize (GObject *object); static void csd_smartcard_class_install_signals (CsdSmartcardClass *card_class); static void csd_smartcard_class_install_properties (CsdSmartcardClass *card_class); static void csd_smartcard_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void csd_smartcard_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void csd_smartcard_set_name (CsdSmartcard *card, const char *name); static void csd_smartcard_set_slot_id (CsdSmartcard *card, int slot_id); static void csd_smartcard_set_slot_series (CsdSmartcard *card, int slot_series); static void csd_smartcard_set_module (CsdSmartcard *card, SECMODModule *module); static PK11SlotInfo *csd_smartcard_find_slot_from_id (CsdSmartcard *card, int slot_id); static PK11SlotInfo *csd_smartcard_find_slot_from_card_name (CsdSmartcard *card, const char *card_name); #ifndef CSD_SMARTCARD_DEFAULT_SLOT_ID #define CSD_SMARTCARD_DEFAULT_SLOT_ID ((gulong) -1) #endif #ifndef CSD_SMARTCARD_DEFAULT_SLOT_SERIES #define CSD_SMARTCARD_DEFAULT_SLOT_SERIES -1 #endif enum { PROP_0 = 0, PROP_NAME, PROP_SLOT_ID, PROP_SLOT_SERIES, PROP_MODULE, NUMBER_OF_PROPERTIES }; enum { INSERTED, REMOVED, NUMBER_OF_SIGNALS }; static guint csd_smartcard_signals[NUMBER_OF_SIGNALS]; G_DEFINE_TYPE (CsdSmartcard, csd_smartcard, G_TYPE_OBJECT); static void csd_smartcard_class_init (CsdSmartcardClass *card_class) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (card_class); gobject_class->finalize = csd_smartcard_finalize; csd_smartcard_class_install_signals (card_class); csd_smartcard_class_install_properties (card_class); g_type_class_add_private (card_class, sizeof (CsdSmartcardPrivate)); } static void csd_smartcard_class_install_signals (CsdSmartcardClass *card_class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (card_class); csd_smartcard_signals[INSERTED] = g_signal_new ("inserted", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdSmartcardClass, inserted), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); csd_smartcard_signals[REMOVED] = g_signal_new ("removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdSmartcardClass, removed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void csd_smartcard_class_install_properties (CsdSmartcardClass *card_class) { GObjectClass *object_class; GParamSpec *param_spec; object_class = G_OBJECT_CLASS (card_class); object_class->set_property = csd_smartcard_set_property; object_class->get_property = csd_smartcard_get_property; param_spec = g_param_spec_ulong ("slot-id", "Slot ID", "The slot the card is in", 1, G_MAXULONG, CSD_SMARTCARD_DEFAULT_SLOT_ID, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_SLOT_ID, param_spec); param_spec = g_param_spec_int ("slot-series", "Slot Series", "per-slot card identifier", -1, G_MAXINT, CSD_SMARTCARD_DEFAULT_SLOT_SERIES, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_SLOT_SERIES, param_spec); param_spec = g_param_spec_string ("name", "name", "name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_NAME, param_spec); param_spec = g_param_spec_pointer ("module", "Module", "smartcard driver", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_MODULE, param_spec); } static void csd_smartcard_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsdSmartcard *card = CSD_SMARTCARD (object); switch (prop_id) { case PROP_NAME: csd_smartcard_set_name (card, g_value_get_string (value)); break; case PROP_SLOT_ID: csd_smartcard_set_slot_id (card, g_value_get_ulong (value)); break; case PROP_SLOT_SERIES: csd_smartcard_set_slot_series (card, g_value_get_int (value)); break; case PROP_MODULE: csd_smartcard_set_module (card, (SECMODModule *) g_value_get_pointer (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } CK_SLOT_ID csd_smartcard_get_slot_id (CsdSmartcard *card) { return card->priv->slot_id; } CsdSmartcardState csd_smartcard_get_state (CsdSmartcard *card) { return card->priv->state; } char * csd_smartcard_get_name (CsdSmartcard *card) { return g_strdup (card->priv->name); } gboolean csd_smartcard_is_login_card (CsdSmartcard *card) { const char *login_card_name; login_card_name = g_getenv ("PKCS11_LOGIN_TOKEN_NAME"); if ((login_card_name == NULL) || (card->priv->name == NULL)) { return FALSE; } if (strcmp (card->priv->name, login_card_name) == 0) { return TRUE; } return FALSE; } static void csd_smartcard_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdSmartcard *card = CSD_SMARTCARD (object); switch (prop_id) { case PROP_NAME: g_value_take_string (value, csd_smartcard_get_name (card)); break; case PROP_SLOT_ID: g_value_set_ulong (value, (gulong) csd_smartcard_get_slot_id (card)); break; case PROP_SLOT_SERIES: g_value_set_int (value, csd_smartcard_get_slot_series (card)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void csd_smartcard_set_name (CsdSmartcard *card, const char *name) { if (name == NULL) { return; } if ((card->priv->name == NULL) || (strcmp (card->priv->name, name) != 0)) { g_free (card->priv->name); card->priv->name = g_strdup (name); if (card->priv->slot == NULL) { card->priv->slot = csd_smartcard_find_slot_from_card_name (card, card->priv->name); if (card->priv->slot != NULL) { int slot_id, slot_series; slot_id = PK11_GetSlotID (card->priv->slot); if (slot_id != card->priv->slot_id) { csd_smartcard_set_slot_id (card, slot_id); } slot_series = PK11_GetSlotSeries (card->priv->slot); if (slot_series != card->priv->slot_series) { csd_smartcard_set_slot_series (card, slot_series); } _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_INSERTED); } else { _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_REMOVED); } } g_object_notify (G_OBJECT (card), "name"); } } static void csd_smartcard_set_slot_id (CsdSmartcard *card, int slot_id) { if (card->priv->slot_id != slot_id) { card->priv->slot_id = slot_id; if (card->priv->slot == NULL) { card->priv->slot = csd_smartcard_find_slot_from_id (card, card->priv->slot_id); if (card->priv->slot != NULL) { const char *card_name; card_name = PK11_GetTokenName (card->priv->slot); if ((card->priv->name == NULL) || ((card_name != NULL) && (strcmp (card_name, card->priv->name) != 0))) { csd_smartcard_set_name (card, card_name); } _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_INSERTED); } else { _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_REMOVED); } } g_object_notify (G_OBJECT (card), "slot-id"); } } static void csd_smartcard_set_slot_series (CsdSmartcard *card, int slot_series) { if (card->priv->slot_series != slot_series) { card->priv->slot_series = slot_series; g_object_notify (G_OBJECT (card), "slot-series"); } } static void csd_smartcard_set_module (CsdSmartcard *card, SECMODModule *module) { gboolean should_notify; if (card->priv->module != module) { should_notify = TRUE; } else { should_notify = FALSE; } if (card->priv->module != NULL) { SECMOD_DestroyModule (card->priv->module); card->priv->module = NULL; } if (module != NULL) { card->priv->module = SECMOD_ReferenceModule (module); } if (should_notify) { g_object_notify (G_OBJECT (card), "module"); } } int csd_smartcard_get_slot_series (CsdSmartcard *card) { return card->priv->slot_series; } static void csd_smartcard_init (CsdSmartcard *card) { g_debug ("initializing smartcard "); card->priv = G_TYPE_INSTANCE_GET_PRIVATE (card, CSD_TYPE_SMARTCARD, CsdSmartcardPrivate); } static void csd_smartcard_finalize (GObject *object) { CsdSmartcard *card; GObjectClass *gobject_class; card = CSD_SMARTCARD (object); g_free (card->priv->name); csd_smartcard_set_module (card, NULL); gobject_class = G_OBJECT_CLASS (csd_smartcard_parent_class); gobject_class->finalize (object); } GQuark csd_smartcard_error_quark (void) { static GQuark error_quark = 0; if (error_quark == 0) { error_quark = g_quark_from_static_string ("csd-smartcard-error-quark"); } return error_quark; } CsdSmartcard * _csd_smartcard_new (SECMODModule *module, CK_SLOT_ID slot_id, int slot_series) { CsdSmartcard *card; g_return_val_if_fail (module != NULL, NULL); g_return_val_if_fail (slot_id >= 1, NULL); g_return_val_if_fail (slot_series > 0, NULL); g_return_val_if_fail (sizeof (gulong) == sizeof (slot_id), NULL); card = CSD_SMARTCARD (g_object_new (CSD_TYPE_SMARTCARD, "module", module, "slot-id", (gulong) slot_id, "slot-series", slot_series, NULL)); return card; } CsdSmartcard * _csd_smartcard_new_from_name (SECMODModule *module, const char *name) { CsdSmartcard *card; g_return_val_if_fail (module != NULL, NULL); g_return_val_if_fail (name != NULL, NULL); card = CSD_SMARTCARD (g_object_new (CSD_TYPE_SMARTCARD, "module", module, "name", name, NULL)); return card; } void _csd_smartcard_set_state (CsdSmartcard *card, CsdSmartcardState state) { /* csd_smartcard_fetch_certificates (card); */ if (card->priv->state != state) { card->priv->state = state; if (state == CSD_SMARTCARD_STATE_INSERTED) { g_signal_emit (card, csd_smartcard_signals[INSERTED], 0); } else if (state == CSD_SMARTCARD_STATE_REMOVED) { g_signal_emit (card, csd_smartcard_signals[REMOVED], 0); } else { g_assert_not_reached (); } } } /* So we could conceivably make the closure data a pointer to the card * or something similiar and then emit signals when we want passwords, * but it's probably easier to just get the password up front and use * it. So we just take the passed in g_malloc'd (well probably, who knows) * and strdup it using NSPR's memory allocation routines. */ static char * csd_smartcard_password_handler (PK11SlotInfo *slot, PRBool is_retrying, const char *password) { if (is_retrying) { return NULL; } return password != NULL? PL_strdup (password): NULL; } gboolean csd_smartcard_unlock (CsdSmartcard *card, const char *password) { SECStatus status; PK11_SetPasswordFunc ((PK11PasswordFunc) csd_smartcard_password_handler); /* we pass PR_TRUE to load certificates */ status = PK11_Authenticate (card->priv->slot, PR_TRUE, (gpointer) password); if (status != SECSuccess) { g_debug ("could not unlock card - %d", status); return FALSE; } return TRUE; } static PK11SlotInfo * csd_smartcard_find_slot_from_card_name (CsdSmartcard *card, const char *card_name) { int i; for (i = 0; i < card->priv->module->slotCount; i++) { const char *slot_card_name; slot_card_name = PK11_GetTokenName (card->priv->module->slots[i]); if ((slot_card_name != NULL) && (strcmp (slot_card_name, card_name) == 0)) { return card->priv->module->slots[i]; } } return NULL; } static PK11SlotInfo * csd_smartcard_find_slot_from_id (CsdSmartcard *card, int slot_id) { int i; for (i = 0; i < card->priv->module->slotCount; i++) { if (PK11_GetSlotID (card->priv->module->slots[i]) == slot_id) { return card->priv->module->slots[i]; } } return NULL; } cinnamon-settings-daemon-2.8.3/plugins/smartcard/csd-smartcard-plugin.h0000664000175000017500000000430612625665665025234 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, 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_SMARTCARD_PLUGIN_H__ #define __CSD_SMARTCARD_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_SMARTCARD_PLUGIN (csd_smartcard_plugin_get_type ()) #define CSD_SMARTCARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_SMARTCARD_PLUGIN, CsdSmartcardPlugin)) #define CSD_SMARTCARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CSD_TYPE_SMARTCARD_PLUGIN, CsdSmartcardPluginClass)) #define CSD_IS_SMARTCARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_SMARTCARD_PLUGIN)) #define CSD_IS_SMARTCARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_SMARTCARD_PLUGIN)) #define CSD_SMARTCARD_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_SMARTCARD_PLUGIN, CsdSmartcardPluginClass)) typedef struct CsdSmartcardPluginPrivate CsdSmartcardPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdSmartcardPluginPrivate *priv; } CsdSmartcardPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdSmartcardPluginClass; GType csd_smartcard_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_SMARTCARD_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/smartcard/csd-smartcard.h0000664000175000017500000000656512625665665023751 0ustar fabiofabio/* securitycard.h - api for reading and writing data to a security card * * Copyright (C) 2006 Ray Strode * * 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_SMARTCARD_H #define CSD_SMARTCARD_H #include #include #include G_BEGIN_DECLS #define CSD_TYPE_SMARTCARD (csd_smartcard_get_type ()) #define CSD_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSD_TYPE_SMARTCARD, CsdSmartcard)) #define CSD_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSD_TYPE_SMARTCARD, CsdSmartcardClass)) #define CSD_IS_SMARTCARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSD_TYPE_SMARTCARD)) #define CSD_IS_SMARTCARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSD_TYPE_SMARTCARD)) #define CSD_SMARTCARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), CSD_TYPE_SMARTCARD, CsdSmartcardClass)) #define CSD_SMARTCARD_ERROR (csd_smartcard_error_quark ()) typedef struct _CsdSmartcardClass CsdSmartcardClass; typedef struct _CsdSmartcard CsdSmartcard; typedef struct _CsdSmartcardPrivate CsdSmartcardPrivate; typedef enum _CsdSmartcardError CsdSmartcardError; typedef enum _CsdSmartcardState CsdSmartcardState; typedef struct _CsdSmartcardRequest CsdSmartcardRequest; struct _CsdSmartcard { GObject parent; /*< private > */ CsdSmartcardPrivate *priv; }; struct _CsdSmartcardClass { GObjectClass parent_class; void (* inserted) (CsdSmartcard *card); void (* removed) (CsdSmartcard *card); }; enum _CsdSmartcardError { CSD_SMARTCARD_ERROR_GENERIC = 0, }; enum _CsdSmartcardState { CSD_SMARTCARD_STATE_INSERTED = 0, CSD_SMARTCARD_STATE_REMOVED, }; GType csd_smartcard_get_type (void) G_GNUC_CONST; GQuark csd_smartcard_error_quark (void) G_GNUC_CONST; CK_SLOT_ID csd_smartcard_get_slot_id (CsdSmartcard *card); gint csd_smartcard_get_slot_series (CsdSmartcard *card); CsdSmartcardState csd_smartcard_get_state (CsdSmartcard *card); char *csd_smartcard_get_name (CsdSmartcard *card); gboolean csd_smartcard_is_login_card (CsdSmartcard *card); gboolean csd_smartcard_unlock (CsdSmartcard *card, const char *password); /* don't under any circumstances call these functions */ #ifdef CSD_SMARTCARD_ENABLE_INTERNAL_API CsdSmartcard *_csd_smartcard_new (SECMODModule *module, CK_SLOT_ID slot_id, gint slot_series); CsdSmartcard *_csd_smartcard_new_from_name (SECMODModule *module, const char *name); void _csd_smartcard_set_state (CsdSmartcard *card, CsdSmartcardState state); #endif G_END_DECLS #endif /* CSD_SMARTCARD_H */ cinnamon-settings-daemon-2.8.3/plugins/smartcard/csd-smartcard-manager.c0000664000175000017500000014366112625665665025353 0ustar fabiofabio/* csd-smartcard-manager.c - object for monitoring smartcard insertion and * removal events * * Copyright (C) 2006, 2009 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. * * Written By: Ray Strode */ #include "config.h" #include "csd-smartcard-manager.h" #define SMARTCARD_ENABLE_INTERNAL_API #include "csd-smartcard.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef CSD_SMARTCARD_MANAGER_DRIVER #define CSD_SMARTCARD_MANAGER_DRIVER LIBDIR"/pkcs11/libcoolkeypk11.so" #endif #ifndef CSD_SMARTCARD_MANAGER_NSS_DB #define CSD_SMARTCARD_MANAGER_NSS_DB SYSCONFDIR"/pki/nssdb" #endif #ifndef CSD_MAX_OPEN_FILE_DESCRIPTORS #define CSD_MAX_OPEN_FILE_DESCRIPTORS 1024 #endif #ifndef CSD_OPEN_FILE_DESCRIPTORS_DIR #define CSD_OPEN_FILE_DESCRIPTORS_DIR "/proc/self/fd" #endif typedef enum _CsdSmartcardManagerState CsdSmartcardManagerState; typedef struct _CsdSmartcardManagerWorker CsdSmartcardManagerWorker; enum _CsdSmartcardManagerState { CSD_SMARTCARD_MANAGER_STATE_STOPPED = 0, CSD_SMARTCARD_MANAGER_STATE_STARTING, CSD_SMARTCARD_MANAGER_STATE_STARTED, CSD_SMARTCARD_MANAGER_STATE_STOPPING, }; struct _CsdSmartcardManagerPrivate { CsdSmartcardManagerState state; GList *modules; char *module_path; GList *workers; GPid smartcard_event_watcher_pid; GHashTable *smartcards; guint poll_timeout_id; guint32 is_unstoppable : 1; guint32 nss_is_loaded : 1; }; struct _CsdSmartcardManagerWorker { CsdSmartcardManager *manager; int manager_fd; GThread *thread; SECMODModule *module; GHashTable *smartcards; int fd; GSource *event_source; guint32 nss_is_loaded : 1; }; static void csd_smartcard_manager_finalize (GObject *object); static void csd_smartcard_manager_class_install_signals (CsdSmartcardManagerClass *service_class); static void csd_smartcard_manager_class_install_properties (CsdSmartcardManagerClass *service_class); static void csd_smartcard_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void csd_smartcard_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void csd_smartcard_manager_set_module_path (CsdSmartcardManager *manager, const char *module_path); static void csd_smartcard_manager_card_removed_handler (CsdSmartcardManager *manager, CsdSmartcard *card); static void csd_smartcard_manager_card_inserted_handler (CsdSmartcardManager *manager_class, CsdSmartcard *card); static gboolean csd_smartcard_manager_stop_now (CsdSmartcardManager *manager); static void csd_smartcard_manager_queue_stop (CsdSmartcardManager *manager); static CsdSmartcardManagerWorker *csd_smartcard_manager_create_worker (CsdSmartcardManager *manager, SECMODModule *module); static CsdSmartcardManagerWorker * csd_smartcard_manager_worker_new (CsdSmartcardManager *manager, int worker_fd, int manager_fd, SECMODModule *module); static void csd_smartcard_manager_worker_free (CsdSmartcardManagerWorker *worker); static gboolean open_pipe (int *write_fd, int *read_fd); static gboolean read_bytes (int fd, gpointer bytes, gsize num_bytes); static gboolean write_bytes (int fd, gconstpointer bytes, gsize num_bytes); static CsdSmartcard *read_smartcard (int fd, SECMODModule *module); static gboolean write_smartcard (int fd, CsdSmartcard *card); enum { PROP_0 = 0, PROP_MODULE_PATH, NUMBER_OF_PROPERTIES }; enum { SMARTCARD_INSERTED = 0, SMARTCARD_REMOVED, ERROR, NUMBER_OF_SIGNALS }; static guint csd_smartcard_manager_signals[NUMBER_OF_SIGNALS]; G_DEFINE_TYPE (CsdSmartcardManager, csd_smartcard_manager, G_TYPE_OBJECT); static void csd_smartcard_manager_class_init (CsdSmartcardManagerClass *manager_class) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (manager_class); gobject_class->finalize = csd_smartcard_manager_finalize; csd_smartcard_manager_class_install_signals (manager_class); csd_smartcard_manager_class_install_properties (manager_class); g_type_class_add_private (manager_class, sizeof (CsdSmartcardManagerPrivate)); } static void csd_smartcard_manager_class_install_properties (CsdSmartcardManagerClass *card_class) { GObjectClass *object_class; GParamSpec *param_spec; object_class = G_OBJECT_CLASS (card_class); object_class->set_property = csd_smartcard_manager_set_property; object_class->get_property = csd_smartcard_manager_get_property; param_spec = g_param_spec_string ("module-path", "Module Path", "path to smartcard PKCS #11 driver", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_property (object_class, PROP_MODULE_PATH, param_spec); } static void csd_smartcard_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsdSmartcardManager *manager = CSD_SMARTCARD_MANAGER (object); switch (prop_id) { case PROP_MODULE_PATH: csd_smartcard_manager_set_module_path (manager, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_smartcard_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdSmartcardManager *manager = CSD_SMARTCARD_MANAGER (object); char *module_path; switch (prop_id) { case PROP_MODULE_PATH: module_path = csd_smartcard_manager_get_module_path (manager); g_value_set_string (value, module_path); g_free (module_path); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } char * csd_smartcard_manager_get_module_path (CsdSmartcardManager *manager) { return manager->priv->module_path; } static void csd_smartcard_manager_set_module_path (CsdSmartcardManager *manager, const char *module_path) { if ((manager->priv->module_path == NULL) && (module_path == NULL)) { return; } if (((manager->priv->module_path == NULL) || (module_path == NULL) || (strcmp (manager->priv->module_path, module_path) != 0))) { g_free (manager->priv->module_path); manager->priv->module_path = g_strdup (module_path); g_object_notify (G_OBJECT (manager), "module-path"); } } static void csd_smartcard_manager_card_removed_handler (CsdSmartcardManager *manager, CsdSmartcard *card) { g_debug ("informing smartcard of its removal"); _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_REMOVED); g_debug ("done"); } static void csd_smartcard_manager_card_inserted_handler (CsdSmartcardManager *manager, CsdSmartcard *card) { g_debug ("informing smartcard of its insertion"); _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_INSERTED); g_debug ("done"); } static void csd_smartcard_manager_class_install_signals (CsdSmartcardManagerClass *manager_class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (manager_class); csd_smartcard_manager_signals[SMARTCARD_INSERTED] = g_signal_new ("smartcard-inserted", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (CsdSmartcardManagerClass, smartcard_inserted), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); manager_class->smartcard_inserted = csd_smartcard_manager_card_inserted_handler; csd_smartcard_manager_signals[SMARTCARD_REMOVED] = g_signal_new ("smartcard-removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (CsdSmartcardManagerClass, smartcard_removed), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); manager_class->smartcard_removed = csd_smartcard_manager_card_removed_handler; csd_smartcard_manager_signals[ERROR] = g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsdSmartcardManagerClass, error), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); manager_class->error = NULL; } static gboolean slot_id_equal (CK_SLOT_ID *slot_id_1, CK_SLOT_ID *slot_id_2) { g_assert (slot_id_1 != NULL); g_assert (slot_id_2 != NULL); return *slot_id_1 == *slot_id_2; } static gboolean slot_id_hash (CK_SLOT_ID *slot_id) { guint32 upper_bits, lower_bits; int temp; if (sizeof (CK_SLOT_ID) == sizeof (int)) { return g_int_hash (slot_id); } upper_bits = ((*slot_id) >> 31) - 1; lower_bits = (*slot_id) & 0xffffffff; /* The upper bits are almost certainly always zero, * so let's degenerate to g_int_hash for the * (very) common case */ temp = lower_bits + upper_bits; return upper_bits + g_int_hash (&temp); } static void csd_smartcard_manager_init (CsdSmartcardManager *manager) { g_debug ("initializing smartcard manager"); manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, CSD_TYPE_SMARTCARD_MANAGER, CsdSmartcardManagerPrivate); manager->priv->poll_timeout_id = 0; manager->priv->is_unstoppable = FALSE; manager->priv->smartcards = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref); } static void csd_smartcard_manager_finalize (GObject *object) { CsdSmartcardManager *manager; GObjectClass *gobject_class; manager = CSD_SMARTCARD_MANAGER (object); gobject_class = G_OBJECT_CLASS (csd_smartcard_manager_parent_class); csd_smartcard_manager_stop_now (manager); g_hash_table_destroy (manager->priv->smartcards); manager->priv->smartcards = NULL; gobject_class->finalize (object); } GQuark csd_smartcard_manager_error_quark (void) { static GQuark error_quark = 0; if (error_quark == 0) { error_quark = g_quark_from_static_string ("csd-smartcard-manager-error-quark"); } return error_quark; } CsdSmartcardManager * csd_smartcard_manager_new_default (void) { return csd_smartcard_manager_new (NULL); } CsdSmartcardManager * csd_smartcard_manager_new (const char *module_path) { CsdSmartcardManager *instance; instance = CSD_SMARTCARD_MANAGER (g_object_new (CSD_TYPE_SMARTCARD_MANAGER, "module-path", module_path, NULL)); return instance; } static void csd_smartcard_manager_emit_error (CsdSmartcardManager *manager, GError *error) { manager->priv->is_unstoppable = TRUE; g_signal_emit (manager, csd_smartcard_manager_signals[ERROR], 0, error); manager->priv->is_unstoppable = FALSE; } static void csd_smartcard_manager_emit_smartcard_inserted (CsdSmartcardManager *manager, CsdSmartcard *card) { manager->priv->is_unstoppable = TRUE; g_signal_emit (manager, csd_smartcard_manager_signals[SMARTCARD_INSERTED], 0, card); manager->priv->is_unstoppable = FALSE; } static void csd_smartcard_manager_emit_smartcard_removed (CsdSmartcardManager *manager, CsdSmartcard *card) { manager->priv->is_unstoppable = TRUE; g_signal_emit (manager, csd_smartcard_manager_signals[SMARTCARD_REMOVED], 0, card); manager->priv->is_unstoppable = FALSE; } static gboolean csd_smartcard_manager_check_for_and_process_events (GIOChannel *io_channel, GIOCondition condition, CsdSmartcardManagerWorker *worker) { CsdSmartcard *card; CsdSmartcardManager *manager; gboolean should_stop; guchar event_type; char *card_name; int fd; manager = worker->manager; g_debug ("event!"); card = NULL; should_stop = (condition & G_IO_HUP) || (condition & G_IO_ERR); if (should_stop) { g_debug ("received %s on event socket, stopping " "manager...", (condition & G_IO_HUP) && (condition & G_IO_ERR)? "error and hangup" : (condition & G_IO_HUP)? "hangup" : "error"); } if (!(condition & G_IO_IN)) { g_debug ("nevermind outta here!"); goto out; } fd = g_io_channel_unix_get_fd (io_channel); event_type = '\0'; if (!read_bytes (fd, &event_type, 1)) { g_debug ("could not read event type, stopping"); should_stop = TRUE; goto out; } card = read_smartcard (fd, worker->module); if (card == NULL) { g_debug ("could not read card, stopping"); should_stop = TRUE; goto out; } card_name = csd_smartcard_get_name (card); g_debug ("card '%s' had event %c", card_name, event_type); switch (event_type) { case 'I': g_hash_table_replace (manager->priv->smartcards, card_name, card); card_name = NULL; csd_smartcard_manager_emit_smartcard_inserted (manager, card); card = NULL; break; case 'R': csd_smartcard_manager_emit_smartcard_removed (manager, card); if (!g_hash_table_remove (manager->priv->smartcards, card_name)) { g_debug ("got removal event of unknown card!"); } g_free (card_name); card_name = NULL; card = NULL; break; default: g_free (card_name); card_name = NULL; g_object_unref (card); should_stop = TRUE; break; } out: if (should_stop) { GError *error; error = g_error_new (CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, "%s", (condition & G_IO_IN) ? g_strerror (errno) : _("received error or hang up from event source")); csd_smartcard_manager_emit_error (manager, error); g_error_free (error); csd_smartcard_manager_stop_now (manager); return FALSE; } return TRUE; } static void stop_manager (CsdSmartcardManager *manager) { manager->priv->state = CSD_SMARTCARD_MANAGER_STATE_STOPPED; if (manager->priv->nss_is_loaded) { NSS_Shutdown (); manager->priv->nss_is_loaded = FALSE; } g_debug ("smartcard manager stopped"); } static void stop_worker (CsdSmartcardManagerWorker *worker) { CsdSmartcardManager *manager; manager = worker->manager; if (worker->event_source != NULL) { g_source_destroy (worker->event_source); worker->event_source = NULL; } if (worker->thread != NULL) { SECMOD_CancelWait (worker->module); worker->thread = NULL; } SECMOD_DestroyModule (worker->module); manager->priv->workers = g_list_remove (manager->priv->workers, worker); if (manager->priv->workers == NULL && manager->priv->state != CSD_SMARTCARD_MANAGER_STATE_STOPPED) { stop_manager (manager); } } static void csd_smartcard_manager_event_processing_stopped_handler (CsdSmartcardManagerWorker *worker) { worker->event_source = NULL; stop_worker (worker); } static gboolean open_pipe (int *write_fd, int *read_fd) { int pipe_fds[2] = { -1, -1 }; g_assert (write_fd != NULL); g_assert (read_fd != NULL); if (pipe (pipe_fds) < 0) { return FALSE; } if (fcntl (pipe_fds[0], F_SETFD, FD_CLOEXEC) < 0) { close (pipe_fds[0]); close (pipe_fds[1]); return FALSE; } if (fcntl (pipe_fds[1], F_SETFD, FD_CLOEXEC) < 0) { close (pipe_fds[0]); close (pipe_fds[1]); return FALSE; } *read_fd = pipe_fds[0]; *write_fd = pipe_fds[1]; return TRUE; } static void csd_smartcard_manager_stop_watching_for_events (CsdSmartcardManager *manager) { GList *node; node = manager->priv->workers; while (node != NULL) { CsdSmartcardManagerWorker *worker; GList *next_node; worker = (CsdSmartcardManagerWorker *) node->data; next_node = node->next; stop_worker (worker); node = next_node; } } static gboolean load_nss (GError **error) { SECStatus status = SECSuccess; static const guint32 flags = NSS_INIT_READONLY | NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD; g_debug ("attempting to load NSS database '%s'", CSD_SMARTCARD_MANAGER_NSS_DB); PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); status = NSS_Initialize (CSD_SMARTCARD_MANAGER_NSS_DB, "", "", SECMOD_DB, flags); if (status != SECSuccess) { gsize error_message_size; char *error_message; error_message_size = PR_GetErrorTextLength (); if (error_message_size == 0) { g_debug ("NSS security system could not be initialized"); g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, _("NSS security system could not be initialized")); goto out; } error_message = g_slice_alloc0 (error_message_size); PR_GetErrorText (error_message); g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, "%s", error_message); g_debug ("NSS security system could not be initialized - %s", error_message); g_slice_free1 (error_message_size, error_message); goto out; } g_debug ("NSS database sucessfully loaded"); return TRUE; out: g_debug ("NSS database couldn't be sucessfully loaded"); return FALSE; } static GList * get_available_modules (CsdSmartcardManager *manager) { SECMODModuleList *module_list, *tmp; GList *modules; g_debug ("Getting list of suitable modules"); module_list = SECMOD_GetDefaultModuleList (); modules = NULL; for (tmp = module_list; tmp != NULL; tmp = tmp->next) { if (!SECMOD_HasRemovableSlots (tmp->module) || !tmp->module->loaded) continue; g_debug ("Using module '%s'", tmp->module->commonName); modules = g_list_prepend (modules, SECMOD_ReferenceModule (tmp->module)); } return modules; } static gboolean load_driver (CsdSmartcardManager *manager, char *module_path, GError **error) { GList *modules; char *module_spec; gboolean module_explicitly_specified; g_debug ("attempting to load driver..."); modules = NULL; module_explicitly_specified = module_path != NULL; if (module_explicitly_specified) { SECMODModule *module; module_spec = g_strdup_printf ("library=\"%s\"", module_path); g_debug ("loading smartcard driver using spec '%s'", module_spec); module = SECMOD_LoadUserModule (module_spec, NULL /* parent */, FALSE /* recurse */); g_free (module_spec); module_spec = NULL; if (SECMOD_HasRemovableSlots (module) && module->loaded) { modules = g_list_prepend (modules, module); } else { g_debug ("fallback module found but not %s", SECMOD_HasRemovableSlots (module)? "removable" : "loaded"); SECMOD_DestroyModule (module); } } else { SECMODListLock *lock; lock = SECMOD_GetDefaultModuleListLock (); if (lock != NULL) { SECMOD_GetReadLock (lock); modules = get_available_modules (manager); SECMOD_ReleaseReadLock (lock); } /* fallback to compiled in driver path */ if (modules == NULL) { SECMODModule *module; module_path = CSD_SMARTCARD_MANAGER_DRIVER; module_spec = g_strdup_printf ("library=\"%s\"", module_path); g_debug ("loading smartcard driver using spec '%s'", module_spec); module = SECMOD_LoadUserModule (module_spec, NULL /* parent */, FALSE /* recurse */); g_free (module_spec); module_spec = NULL; if (SECMOD_HasRemovableSlots (module) && module->loaded) { modules = g_list_prepend (modules, module); } else { g_debug ("fallback module found but not loaded"); SECMOD_DestroyModule (module); } } } if (!module_explicitly_specified && modules == NULL) { g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, _("no suitable smartcard driver could be found")); } else if (modules == NULL) { gsize error_message_size; char *error_message; error_message_size = PR_GetErrorTextLength (); if (error_message_size == 0) { g_debug ("smartcard driver '%s' could not be loaded", module_path); g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, _("smartcard driver '%s' could not be " "loaded"), module_path); goto out; } error_message = g_slice_alloc0 (error_message_size); PR_GetErrorText (error_message); g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER, "%s", error_message); g_debug ("smartcard driver '%s' could not be loaded - %s", module_path, error_message); g_slice_free1 (error_message_size, error_message); } manager->priv->modules = modules; out: return manager->priv->modules != NULL; } static void csd_smartcard_manager_get_all_cards (CsdSmartcardManager *manager) { GList *node; int i; node = manager->priv->workers; while (node != NULL) { CsdSmartcardManagerWorker *worker; worker = (CsdSmartcardManagerWorker *) node->data; for (i = 0; i < worker->module->slotCount; i++) { CsdSmartcard *card; CK_SLOT_ID slot_id; int slot_series; char *card_name; slot_id = PK11_GetSlotID (worker->module->slots[i]); slot_series = PK11_GetSlotSeries (worker->module->slots[i]); card = _csd_smartcard_new (worker->module, slot_id, slot_series); card_name = csd_smartcard_get_name (card); g_hash_table_replace (manager->priv->smartcards, card_name, card); } node = node->next; } } static CsdSmartcardManagerWorker * start_worker (CsdSmartcardManager *manager, SECMODModule *module, GError **error) { GIOChannel *io_channel; GSource *source; CsdSmartcardManagerWorker *worker; worker = csd_smartcard_manager_create_worker (manager, module); if (worker == NULL) { g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS, _("could not watch for incoming card events - %s"), g_strerror (errno)); goto out; } io_channel = g_io_channel_unix_new (worker->manager_fd); source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP); g_io_channel_unref (io_channel); io_channel = NULL; worker->event_source = source; g_source_set_callback (worker->event_source, (GSourceFunc) (GIOFunc) csd_smartcard_manager_check_for_and_process_events, worker, (GDestroyNotify) csd_smartcard_manager_event_processing_stopped_handler); g_source_attach (worker->event_source, NULL); g_source_unref (worker->event_source); out: return worker; } static void start_workers (CsdSmartcardManager *manager) { GList *node; node = manager->priv->modules; while (node != NULL) { SECMODModule *module; CsdSmartcardManagerWorker *worker; GError *error; module = (SECMODModule *) node->data; error = NULL; worker = start_worker (manager, module, &error); if (worker == NULL) { g_warning ("%s", error->message); g_error_free (error); } else { manager->priv->workers = g_list_prepend (manager->priv->workers, worker); } node = node->next; } } gboolean csd_smartcard_manager_start (CsdSmartcardManager *manager, GError **error) { GError *nss_error; if (manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STARTED) { g_debug ("smartcard manager already started"); return TRUE; } manager->priv->state = CSD_SMARTCARD_MANAGER_STATE_STARTING; nss_error = NULL; if (!manager->priv->nss_is_loaded && !load_nss (&nss_error)) { g_propagate_error (error, nss_error); goto out; } manager->priv->nss_is_loaded = TRUE; if (manager->priv->modules == NULL) { if (!load_driver (manager, manager->priv->module_path, &nss_error)) { g_propagate_error (error, nss_error); goto out; } } start_workers (manager); /* populate the hash with cards that are already inserted */ csd_smartcard_manager_get_all_cards (manager); manager->priv->state = CSD_SMARTCARD_MANAGER_STATE_STARTED; out: /* don't leave it in a half started state */ if (manager->priv->state != CSD_SMARTCARD_MANAGER_STATE_STARTED) { g_debug ("smartcard manager could not be completely started"); csd_smartcard_manager_stop (manager); } else { g_debug ("smartcard manager started"); } return manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STARTED; } static gboolean csd_smartcard_manager_stop_now (CsdSmartcardManager *manager) { if (manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STOPPED) { return FALSE; } csd_smartcard_manager_stop_watching_for_events (manager); return FALSE; } static void csd_smartcard_manager_queue_stop (CsdSmartcardManager *manager) { manager->priv->state = CSD_SMARTCARD_MANAGER_STATE_STOPPING; g_idle_add ((GSourceFunc) csd_smartcard_manager_stop_now, manager); } void csd_smartcard_manager_stop (CsdSmartcardManager *manager) { if (manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STOPPED) { return; } if (manager->priv->is_unstoppable) { csd_smartcard_manager_queue_stop (manager); return; } csd_smartcard_manager_stop_now (manager); } static void csd_smartcard_manager_check_for_login_card (CK_SLOT_ID slot_id, CsdSmartcard *card, gboolean *is_inserted) { g_assert (is_inserted != NULL); if (csd_smartcard_is_login_card (card)) { *is_inserted = TRUE; } } gboolean csd_smartcard_manager_login_card_is_inserted (CsdSmartcardManager *manager) { gboolean is_inserted; is_inserted = FALSE; g_hash_table_foreach (manager->priv->smartcards, (GHFunc) csd_smartcard_manager_check_for_login_card, &is_inserted); return is_inserted; } static CsdSmartcardManagerWorker * csd_smartcard_manager_worker_new (CsdSmartcardManager *manager, int worker_fd, int manager_fd, SECMODModule *module) { CsdSmartcardManagerWorker *worker; worker = g_slice_new0 (CsdSmartcardManagerWorker); worker->manager = manager; worker->fd = worker_fd; worker->manager_fd = manager_fd; worker->module = module; worker->smartcards = g_hash_table_new_full ((GHashFunc) slot_id_hash, (GEqualFunc) slot_id_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref); return worker; } static void csd_smartcard_manager_worker_free (CsdSmartcardManagerWorker *worker) { if (worker->smartcards != NULL) { g_hash_table_destroy (worker->smartcards); worker->smartcards = NULL; } g_slice_free (CsdSmartcardManagerWorker, worker); } static gboolean read_bytes (int fd, gpointer bytes, gsize num_bytes) { size_t bytes_left; size_t total_bytes_read; ssize_t bytes_read; bytes_left = (size_t) num_bytes; total_bytes_read = 0; do { bytes_read = read (fd, (char *) bytes + total_bytes_read, bytes_left); g_assert (bytes_read <= (ssize_t) bytes_left); if (bytes_read <= 0) { if ((bytes_read < 0) && (errno == EINTR || errno == EAGAIN)) { continue; } bytes_left = 0; } else { bytes_left -= bytes_read; total_bytes_read += bytes_read; } } while (bytes_left > 0); if (total_bytes_read < (size_t) num_bytes) { return FALSE; } return TRUE; } static gboolean write_bytes (int fd, gconstpointer bytes, gsize num_bytes) { size_t bytes_left; size_t total_bytes_written; ssize_t bytes_written; bytes_left = (size_t) num_bytes; total_bytes_written = 0; do { bytes_written = write (fd, (char *) bytes + total_bytes_written, bytes_left); g_assert (bytes_written <= (ssize_t) bytes_left); if (bytes_written <= 0) { if ((bytes_written < 0) && (errno == EINTR || errno == EAGAIN)) { continue; } bytes_left = 0; } else { bytes_left -= bytes_written; total_bytes_written += bytes_written; } } while (bytes_left > 0); if (total_bytes_written < (size_t) num_bytes) { return FALSE; } return TRUE; } static CsdSmartcard * read_smartcard (int fd, SECMODModule *module) { CsdSmartcard *card; char *card_name; gsize card_name_size; card_name_size = 0; if (!read_bytes (fd, &card_name_size, sizeof (card_name_size))) { return NULL; } card_name = g_slice_alloc0 (card_name_size); if (!read_bytes (fd, card_name, card_name_size)) { g_slice_free1 (card_name_size, card_name); return NULL; } card = _csd_smartcard_new_from_name (module, card_name); g_slice_free1 (card_name_size, card_name); return card; } static gboolean write_smartcard (int fd, CsdSmartcard *card) { gsize card_name_size; char *card_name; card_name = csd_smartcard_get_name (card); card_name_size = strlen (card_name) + 1; if (!write_bytes (fd, &card_name_size, sizeof (card_name_size))) { g_free (card_name); return FALSE; } if (!write_bytes (fd, card_name, card_name_size)) { g_free (card_name); return FALSE; } g_free (card_name); return TRUE; } static gboolean csd_smartcard_manager_worker_emit_smartcard_removed (CsdSmartcardManagerWorker *worker, CsdSmartcard *card, GError **error) { g_debug ("card '%s' removed!", csd_smartcard_get_name (card)); if (!write_bytes (worker->fd, "R", 1)) { goto error_out; } if (!write_smartcard (worker->fd, card)) { goto error_out; } return TRUE; error_out: g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, "%s", g_strerror (errno)); return FALSE; } static gboolean csd_smartcard_manager_worker_emit_smartcard_inserted (CsdSmartcardManagerWorker *worker, CsdSmartcard *card, GError **error) { g_debug ("card '%s' inserted!", csd_smartcard_get_name (card)); if (!write_bytes (worker->fd, "I", 1)) { goto error_out; } if (!write_smartcard (worker->fd, card)) { goto error_out; } return TRUE; error_out: g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS, "%s", g_strerror (errno)); return FALSE; } static gboolean csd_smartcard_manager_worker_watch_for_and_process_event (CsdSmartcardManagerWorker *worker, GError **error) { PK11SlotInfo *slot; CK_SLOT_ID slot_id, *key = NULL; int slot_series, card_slot_series; CsdSmartcard *card; GError *processing_error; gboolean ret; g_debug ("waiting for card event"); ret = FALSE; slot = SECMOD_WaitForAnyTokenEvent (worker->module, 0, PR_SecondsToInterval (1)); processing_error = NULL; if (slot == NULL) { int error_code; error_code = PORT_GetError (); if ((error_code == 0) || (error_code == SEC_ERROR_NO_EVENT)) { g_debug ("spurrious event occurred"); return TRUE; } /* FIXME: is there a function to convert from a PORT error * code to a translated string? */ g_set_error (error, CSD_SMARTCARD_MANAGER_ERROR, CSD_SMARTCARD_MANAGER_ERROR_WITH_NSS, _("encountered unexpected error while " "waiting for smartcard events")); goto out; } /* the slot id and series together uniquely identify a card. * You can never have two cards with the same slot id at the * same time, however (I think), so we can key off of it. */ slot_id = PK11_GetSlotID (slot); slot_series = PK11_GetSlotSeries (slot); /* First check to see if there is a card that we're currently * tracking in the slot. */ key = g_new (CK_SLOT_ID, 1); *key = slot_id; card = g_hash_table_lookup (worker->smartcards, key); if (card != NULL) { card_slot_series = csd_smartcard_get_slot_series (card); } else { card_slot_series = -1; } if (PK11_IsPresent (slot)) { /* Now, check to see if their is a new card in the slot. * If there was a different card in the slot now than * there was before, then we need to emit a removed signal * for the old card (we don't want unpaired insertion events). */ if ((card != NULL) && card_slot_series != slot_series) { if (!csd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { g_propagate_error (error, processing_error); goto out; } } card = _csd_smartcard_new (worker->module, slot_id, slot_series); g_hash_table_replace (worker->smartcards, key, card); key = NULL; if (!csd_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) { g_propagate_error (error, processing_error); goto out; } } else { /* if we aren't tracking the card, just discard the event. * We don't want unpaired remove events. Note on startup * NSS will generate an "insertion" event if a card is * already inserted in the slot. */ if ((card != NULL)) { /* FIXME: i'm not sure about this code. Maybe we * shouldn't do this at all, or maybe we should do it * n times (where n = slot_series - card_slot_series + 1) * * Right now, i'm just doing it once. */ if ((slot_series - card_slot_series) > 1) { if (!csd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { g_propagate_error (error, processing_error); goto out; } g_hash_table_remove (worker->smartcards, key); card = _csd_smartcard_new (worker->module, slot_id, slot_series); g_hash_table_replace (worker->smartcards, key, card); key = NULL; if (!csd_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) { g_propagate_error (error, processing_error); goto out; } } if (!csd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) { g_propagate_error (error, processing_error); goto out; } g_hash_table_remove (worker->smartcards, key); card = NULL; } else { g_debug ("got spurious remove event"); } } ret = TRUE; out: g_free (key); PK11_FreeSlot (slot); return ret; } static void csd_smartcard_manager_worker_run (CsdSmartcardManagerWorker *worker) { GError *error; gboolean should_continue; do { error = NULL; should_continue = csd_smartcard_manager_worker_watch_for_and_process_event (worker, &error); } while (should_continue); if (error != NULL) { g_debug ("could not process card event - %s", error->message); g_error_free (error); } csd_smartcard_manager_worker_free (worker); } static CsdSmartcardManagerWorker * csd_smartcard_manager_create_worker (CsdSmartcardManager *manager, SECMODModule *module) { CsdSmartcardManagerWorker *worker; int write_fd, read_fd; write_fd = -1; read_fd = -1; if (!open_pipe (&write_fd, &read_fd)) { return NULL; } worker = csd_smartcard_manager_worker_new (manager, write_fd, read_fd, module); worker->thread = g_thread_create ((GThreadFunc) csd_smartcard_manager_worker_run, worker, FALSE, NULL); if (worker->thread == NULL) { csd_smartcard_manager_worker_free (worker); return NULL; } return worker; } #ifdef CSD_SMARTCARD_MANAGER_ENABLE_TEST #include static GMainLoop *event_loop; static gboolean should_exit_on_next_remove = FALSE; static gboolean on_timeout (CsdSmartcardManager *manager) { GError *error; g_print ("Re-enabling manager.\n"); if (!csd_smartcard_manager_start (manager, &error)) { g_warning ("could not start smartcard manager - %s", error->message); g_error_free (error); return TRUE; } g_print ("Please re-insert smartcard\n"); should_exit_on_next_remove = TRUE; return FALSE; } static void on_device_inserted (CsdSmartcardManager *manager, CsdSmartcard *card) { g_print ("smartcard inserted!\n"); g_print ("Please remove it.\n"); } static void on_device_removed (CsdSmartcardManager *manager, CsdSmartcard *card) { g_print ("smartcard removed!\n"); if (should_exit_on_next_remove) { g_main_loop_quit (event_loop); } else { g_print ("disabling manager for 2 seconds\n"); csd_smartcard_manager_stop (manager); g_timeout_add_seconds (2, (GSourceFunc) on_timeout, manager); } } int main (int argc, char *argv[]) { CsdSmartcardManager *manager; GError *error; g_log_set_always_fatal (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); g_type_init (); g_message ("creating instance of 'smartcard manager' object..."); manager = csd_smartcard_manager_new (NULL); g_message ("'smartcard manager' object created successfully"); g_signal_connect (manager, "smartcard-inserted", G_CALLBACK (on_device_inserted), NULL); g_signal_connect (manager, "smartcard-removed", G_CALLBACK (on_device_removed), NULL); g_message ("starting listener..."); error = NULL; if (!csd_smartcard_manager_start (manager, &error)) { g_warning ("could not start smartcard manager - %s", error->message); g_error_free (error); return 1; } event_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (event_loop); g_main_loop_unref (event_loop); event_loop = NULL; g_message ("destroying previously created 'smartcard manager' object..."); g_object_unref (manager); manager = NULL; g_message ("'smartcard manager' object destroyed successfully"); return 0; } #endif cinnamon-settings-daemon-2.8.3/plugins/smartcard/smartcard.cinnamon-settings-plugin.in0000664000175000017500000000024712625665665030303 0ustar fabiofabio[Cinnamon Settings Plugin] Module=smartcard IAge=0 _Name=Smartcard _Description=Smartcard plugin Authors=Ray Strode Copyright=Copyright © 2010 Red Hat, Inc. Website= cinnamon-settings-daemon-2.8.3/plugins/smartcard/csd-smartcard-plugin.c0000664000175000017500000002753412625665665025237 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, 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 "cinnamon-settings-plugin.h" #include "csd-smartcard-plugin.h" #include "csd-smartcard-manager.h" struct CsdSmartcardPluginPrivate { CsdSmartcardManager *manager; GDBusConnection *bus_connection; guint32 is_active : 1; }; typedef enum { CSD_SMARTCARD_REMOVE_ACTION_NONE, CSD_SMARTCARD_REMOVE_ACTION_LOCK_SCREEN, CSD_SMARTCARD_REMOVE_ACTION_FORCE_LOGOUT, } CsdSmartcardRemoveAction; #define SCREENSAVER_DBUS_NAME "org.cinnamon.ScreenSaver" #define SCREENSAVER_DBUS_PATH "/" #define SCREENSAVER_DBUS_INTERFACE "org.cinnamon.ScreenSaver" #define SM_DBUS_NAME "org.gnome.SessionManager" #define SM_DBUS_PATH "/org/gnome/SessionManager" #define SM_DBUS_INTERFACE "org.gnome.SessionManager" #define SM_LOGOUT_MODE_FORCE 2 #define KEY_REMOVE_ACTION "removal-action" #define CSD_SMARTCARD_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_SMARTCARD_PLUGIN, CsdSmartcardPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdSmartcardPlugin, csd_smartcard_plugin); static void simulate_user_activity (CsdSmartcardPlugin *plugin) { GDBusProxy *screensaver_proxy; g_debug ("CsdSmartcardPlugin telling screensaver about smart card insertion"); screensaver_proxy = g_dbus_proxy_new_sync (plugin->priv->bus_connection, 0, NULL, SCREENSAVER_DBUS_NAME, SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE, NULL, NULL); g_dbus_proxy_call (screensaver_proxy, "SimulateUserActivity", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); g_object_unref (screensaver_proxy); } static void lock_screen (CsdSmartcardPlugin *plugin) { GDBusProxy *screensaver_proxy; g_debug ("CsdSmartcardPlugin telling screensaver to lock screen"); screensaver_proxy = g_dbus_proxy_new_sync (plugin->priv->bus_connection, 0, NULL, SCREENSAVER_DBUS_NAME, SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE, NULL, NULL); g_dbus_proxy_call (screensaver_proxy, "Lock", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); g_object_unref (screensaver_proxy); } static void force_logout (CsdSmartcardPlugin *plugin) { GDBusProxy *sm_proxy; GError *error; GVariant *res; g_debug ("CsdSmartcardPlugin telling session manager to force logout"); sm_proxy = g_dbus_proxy_new_sync (plugin->priv->bus_connection, 0, NULL, SM_DBUS_NAME, SM_DBUS_PATH, SM_DBUS_INTERFACE, NULL, NULL); error = NULL; res = g_dbus_proxy_call_sync (sm_proxy, "Logout", g_variant_new ("(i)", SM_LOGOUT_MODE_FORCE), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (! res) { g_warning ("CsdSmartcardPlugin Unable to force logout: %s", error->message); g_error_free (error); } else g_variant_unref (res); g_object_unref (sm_proxy); } static void csd_smartcard_plugin_init (CsdSmartcardPlugin *plugin) { plugin->priv = CSD_SMARTCARD_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdSmartcardPlugin initializing"); plugin->priv->manager = csd_smartcard_manager_new (NULL); } static void csd_smartcard_plugin_finalize (GObject *object) { CsdSmartcardPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_SMARTCARD_PLUGIN (object)); g_debug ("CsdSmartcardPlugin finalizing"); plugin = CSD_SMARTCARD_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_smartcard_plugin_parent_class)->finalize (object); } static void smartcard_inserted_cb (CsdSmartcardManager *card_monitor, CsdSmartcard *card, CsdSmartcardPlugin *plugin) { char *name; name = csd_smartcard_get_name (card); g_debug ("CsdSmartcardPlugin smart card '%s' inserted", name); g_free (name); simulate_user_activity (plugin); } static gboolean user_logged_in_with_smartcard (void) { return g_getenv ("PKCS11_LOGIN_TOKEN_NAME") != NULL; } static CsdSmartcardRemoveAction get_configured_remove_action (CsdSmartcardPlugin *plugin) { GSettings *settings; char *remove_action_string; CsdSmartcardRemoveAction remove_action; settings = g_settings_new ("org.cinnamon.settings-daemon.peripherals.smartcard"); remove_action_string = g_settings_get_string (settings, KEY_REMOVE_ACTION); if (remove_action_string == NULL) { g_warning ("CsdSmartcardPlugin unable to get smartcard remove action"); remove_action = CSD_SMARTCARD_REMOVE_ACTION_NONE; } else if (strcmp (remove_action_string, "none") == 0) { remove_action = CSD_SMARTCARD_REMOVE_ACTION_NONE; } else if (strcmp (remove_action_string, "lock_screen") == 0) { remove_action = CSD_SMARTCARD_REMOVE_ACTION_LOCK_SCREEN; } else if (strcmp (remove_action_string, "force_logout") == 0) { remove_action = CSD_SMARTCARD_REMOVE_ACTION_FORCE_LOGOUT; } else { g_warning ("CsdSmartcardPlugin unknown smartcard remove action"); remove_action = CSD_SMARTCARD_REMOVE_ACTION_NONE; } g_object_unref (settings); return remove_action; } static void process_smartcard_removal (CsdSmartcardPlugin *plugin) { CsdSmartcardRemoveAction remove_action; g_debug ("CsdSmartcardPlugin processing smartcard removal"); remove_action = get_configured_remove_action (plugin); switch (remove_action) { case CSD_SMARTCARD_REMOVE_ACTION_NONE: return; case CSD_SMARTCARD_REMOVE_ACTION_LOCK_SCREEN: lock_screen (plugin); break; case CSD_SMARTCARD_REMOVE_ACTION_FORCE_LOGOUT: force_logout (plugin); break; } } static void smartcard_removed_cb (CsdSmartcardManager *card_monitor, CsdSmartcard *card, CsdSmartcardPlugin *plugin) { char *name; name = csd_smartcard_get_name (card); g_debug ("CsdSmartcardPlugin smart card '%s' removed", name); g_free (name); if (!csd_smartcard_is_login_card (card)) { g_debug ("CsdSmartcardPlugin removed smart card was not used to login"); return; } process_smartcard_removal (plugin); } static void impl_activate (CinnamonSettingsPlugin *plugin) { GError *error; CsdSmartcardPlugin *smartcard_plugin = CSD_SMARTCARD_PLUGIN (plugin); if (smartcard_plugin->priv->is_active) { g_debug ("CsdSmartcardPlugin Not activating smartcard plugin, because it's " "already active"); return; } if (!user_logged_in_with_smartcard ()) { g_debug ("CsdSmartcardPlugin Not activating smartcard plugin, because user didn't use " " smartcard to log in"); smartcard_plugin->priv->is_active = FALSE; return; } g_debug ("CsdSmartcardPlugin Activating smartcard plugin"); error = NULL; smartcard_plugin->priv->bus_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); if (smartcard_plugin->priv->bus_connection == NULL) { g_warning ("CsdSmartcardPlugin Unable to connect to session bus: %s", error->message); return; } if (!csd_smartcard_manager_start (smartcard_plugin->priv->manager, &error)) { g_warning ("CsdSmartcardPlugin Unable to start smartcard manager: %s", error->message); g_error_free (error); } g_signal_connect (smartcard_plugin->priv->manager, "smartcard-removed", G_CALLBACK (smartcard_removed_cb), smartcard_plugin); g_signal_connect (smartcard_plugin->priv->manager, "smartcard-inserted", G_CALLBACK (smartcard_inserted_cb), smartcard_plugin); if (!csd_smartcard_manager_login_card_is_inserted (smartcard_plugin->priv->manager)) { g_debug ("CsdSmartcardPlugin processing smartcard removal immediately user logged in with smartcard " "and it's not inserted"); process_smartcard_removal (smartcard_plugin); } smartcard_plugin->priv->is_active = TRUE; } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { CsdSmartcardPlugin *smartcard_plugin = CSD_SMARTCARD_PLUGIN (plugin); if (!smartcard_plugin->priv->is_active) { g_debug ("CsdSmartcardPlugin Not deactivating smartcard plugin, " "because it's already inactive"); return; } g_debug ("CsdSmartcardPlugin Deactivating smartcard plugin"); csd_smartcard_manager_stop (smartcard_plugin->priv->manager); g_signal_handlers_disconnect_by_func (smartcard_plugin->priv->manager, smartcard_removed_cb, smartcard_plugin); g_signal_handlers_disconnect_by_func (smartcard_plugin->priv->manager, smartcard_inserted_cb, smartcard_plugin); smartcard_plugin->priv->bus_connection = NULL; smartcard_plugin->priv->is_active = FALSE; } static void csd_smartcard_plugin_class_init (CsdSmartcardPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_smartcard_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdSmartcardPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/smartcard/Makefile.am0000664000175000017500000000331412625665665023072 0ustar fabiofabioplugin_name = smartcard libexec_PROGRAMS = csd-test-smartcard csd_test_smartcard_SOURCES = \ csd-smartcard-manager.h \ csd-smartcard-manager.c \ csd-smartcard.h \ csd-smartcard.c \ test-smartcard.c csd_test_smartcard_CFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -DLIBDIR=\""$(libdir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(NSS_CFLAGS) \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_test_smartcard_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(NSS_LIBS) \ $(SETTINGS_PLUGIN_LIBS) plugin_LTLIBRARIES = \ libsmartcard.la libsmartcard_la_SOURCES = \ csd-smartcard-plugin.h \ csd-smartcard-plugin.c \ csd-smartcard.h \ csd-smartcard.c \ csd-smartcard-manager.h \ csd-smartcard-manager.c libsmartcard_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -DLIBDIR=\""$(libdir)"\" \ -DCSD_SMARTCARD_MANAGER_NSS_DB=\""$(NSS_DATABASE)"\" \ $(AM_CPPFLAGS) libsmartcard_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(NSS_CFLAGS) \ $(AM_CFLAGS) libsmartcard_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) libsmartcard_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(NSS_LIBS) @CSD_INTLTOOL_PLUGIN_RULE@ plugin_in_files = \ smartcard.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) CLEANFILES = \ $(plugin_DATA) DISTCLEANFILES = \ $(plugin_DATA) cinnamon-settings-daemon-2.8.3/plugins/smartcard/test-smartcard.c0000664000175000017500000000034112625665665024134 0ustar fabiofabio#define NEW csd_smartcard_manager_new_default #define START csd_smartcard_manager_start #define STOP csd_smartcard_manager_stop #define MANAGER CsdSmartcardManager #include "csd-smartcard-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/screensaver-proxy/0000775000175000017500000000000012625665665022554 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/screensaver-proxy/csd-screensaver-proxy-manager.h0000664000175000017500000000517212625665665030610 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-2.8.3/plugins/screensaver-proxy/test-screensaver-proxy.c0000664000175000017500000000040012625665665027366 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 #include "csd-screensaver-proxy-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/screensaver-proxy/csd-screensaver-proxy-manager.c0000664000175000017500000004737612625665665030617 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_class_init (CsdScreensaverProxyManagerClass *klass); static void csd_screensaver_proxy_manager_init (CsdScreensaverProxyManager *screensaver_proxy_manager); 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); } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootcinnamon-settings-daemon-2.8.3/plugins/screensaver-proxy/screensaver-proxy.cinnamon-settings-plugin.incinnamon-settings-daemon-2.8.3/plugins/screensaver-proxy/screensaver-proxy.cinnamon-settings-plugin.0000664000175000017500000000034012625665665033204 0ustar fabiofabio[Cinnamon Settings Plugin] Module=screensaver-proxy IAge=0 _Name=Screensaver Proxy _Description=Proxy FreeDesktop screensaver inhibition to cinnamon-session Authors=AUTHOR Copyright=Copyright © 2012 Bastien Nocera Website= cinnamon-settings-daemon-2.8.3/plugins/screensaver-proxy/csd-screensaver-proxy-plugin.c0000664000175000017500000000664712625665665030477 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, 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 "cinnamon-settings-plugin.h" #include "csd-screensaver-proxy-plugin.h" #include "csd-screensaver-proxy-manager.h" struct CsdScreensaverProxyPluginPrivate { CsdScreensaverProxyManager *manager; }; #define CSD_SCREENSAVER_PROXY_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_SCREENSAVER_PROXY_PLUGIN, CsdScreensaverProxyPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdScreensaverProxyPlugin, csd_screensaver_proxy_plugin) static void csd_screensaver_proxy_plugin_init (CsdScreensaverProxyPlugin *plugin) { plugin->priv = CSD_SCREENSAVER_PROXY_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdScreensaverProxyPlugin initializing"); plugin->priv->manager = csd_screensaver_proxy_manager_new (); } static void csd_screensaver_proxy_plugin_finalize (GObject *object) { CsdScreensaverProxyPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_SCREENSAVER_PROXY_PLUGIN (object)); g_debug ("CsdScreensaverProxyPlugin finalizing"); plugin = CSD_SCREENSAVER_PROXY_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_screensaver_proxy_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating screensaver-proxy plugin"); error = NULL; res = csd_screensaver_proxy_manager_start (CSD_SCREENSAVER_PROXY_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start screensaver-proxy manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating screensaver-proxy plugin"); csd_screensaver_proxy_manager_stop (CSD_SCREENSAVER_PROXY_PLUGIN (plugin)->priv->manager); } static void csd_screensaver_proxy_plugin_class_init (CsdScreensaverProxyPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_screensaver_proxy_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdScreensaverProxyPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/screensaver-proxy/Makefile.am0000664000175000017500000000320012625665665024603 0ustar fabiofabioplugin_name = screensaver-proxy plugin_LTLIBRARIES = libscreensaver-proxy.la libscreensaver_proxy_la_SOURCES = \ csd-screensaver-proxy-manager.c \ csd-screensaver-proxy-manager.h \ csd-screensaver-proxy-plugin.c \ csd-screensaver-proxy-plugin.h libscreensaver_proxy_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libscreensaver_proxy_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) libscreensaver_proxy_la_LDFLAGS = $(CSD_PLUGIN_LDFLAGS) libscreensaver_proxy_la_LIBADD = $(SETTINGS_PLUGIN_LIBS) libexec_PROGRAMS = csd-test-screensaver-proxy csd_test_screensaver_proxy_SOURCES = \ test-screensaver-proxy.c \ csd-screensaver-proxy-manager.c \ csd-screensaver-proxy-manager.h csd_test_screensaver_proxy_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) csd_test_screensaver_proxy_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_test_screensaver_proxy_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) plugin_in_files = screensaver-proxy.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = $(plugin_in_files) CLEANFILES = $(plugin_DATA) DISTCLEANFILES = $(plugin_DATA) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/screensaver-proxy/csd-screensaver-proxy-plugin.h0000664000175000017500000000464212625665665030475 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, 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_PLUGIN_H__ #define __CSD_SCREENSAVER_PROXY_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_SCREENSAVER_PROXY_PLUGIN (csd_screensaver_proxy_plugin_get_type ()) #define CSD_SCREENSAVER_PROXY_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_SCREENSAVER_PROXY_PLUGIN, CsdScreensaverProxyPlugin)) #define CSD_SCREENSAVER_PROXY_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_SCREENSAVER_PROXY_PLUGIN, CsdScreensaverProxyPluginClass)) #define CSD_IS_SCREENSAVER_PROXY_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_SCREENSAVER_PROXY_PLUGIN)) #define CSD_IS_SCREENSAVER_PROXY_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_SCREENSAVER_PROXY_PLUGIN)) #define CSD_SCREENSAVER_PROXY_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_SCREENSAVER_PROXY_PLUGIN, CsdScreensaverProxyPluginClass)) typedef struct CsdScreensaverProxyPluginPrivate CsdScreensaverProxyPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdScreensaverProxyPluginPrivate *priv; } CsdScreensaverProxyPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdScreensaverProxyPluginClass; GType csd_screensaver_proxy_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_SCREENSAVER_PROXY_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/housekeeping/0000775000175000017500000000000012625665665021543 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-empty-trash-test.c0000664000175000017500000000236312625665665025714 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * Copyright (c) 2011, Red Hat, Inc. * * Authors: Cosimo Cecchi * * 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 "csd-disk-space.h" int main (int argc, char **argv) { GMainLoop *loop; gtk_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); csd_ldsm_show_empty_trash (); g_main_loop_run (loop); g_main_loop_unref (loop); return 0; } cinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-housekeeping-manager.h0000664000175000017500000000471012625665665026563 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Michael J. Chudobiak * * 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_HOUSEKEEPING_MANAGER_H #define __CSD_HOUSEKEEPING_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_HOUSEKEEPING_MANAGER (csd_housekeeping_manager_get_type ()) #define CSD_HOUSEKEEPING_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_HOUSEKEEPING_MANAGER, CsdHousekeepingManager)) #define CSD_HOUSEKEEPING_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_HOUSEKEEPING_MANAGER, CsdHousekeepingManagerClass)) #define CSD_IS_HOUSEKEEPING_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_HOUSEKEEPING_MANAGER)) #define CSD_IS_HOUSEKEEPING_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_HOUSEKEEPING_MANAGER)) #define CSD_HOUSEKEEPING_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_HOUSEKEEPING_MANAGER, CsdHousekeepingManagerClass)) typedef struct CsdHousekeepingManagerPrivate CsdHousekeepingManagerPrivate; typedef struct { GObject parent; CsdHousekeepingManagerPrivate *priv; } CsdHousekeepingManager; typedef struct { GObjectClass parent_class; } CsdHousekeepingManagerClass; GType csd_housekeeping_manager_get_type (void); CsdHousekeepingManager * csd_housekeeping_manager_new (void); gboolean csd_housekeeping_manager_start (CsdHousekeepingManager *manager, GError **error); void csd_housekeeping_manager_stop (CsdHousekeepingManager *manager); G_END_DECLS #endif /* __CSD_HOUSEKEEPING_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-housekeeping-manager.c0000664000175000017500000002642212625665665026562 0ustar fabiofabio/* * Copyright (C) 2008 Michael J. Chudobiak * * 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 "cinnamon-settings-profile.h" #include "csd-housekeeping-manager.h" #include "csd-disk-space.h" /* General */ #define INTERVAL_ONCE_A_DAY 24*60*60 #define INTERVAL_TWO_MINUTES 2*60 /* Thumbnail cleaner */ #define THUMB_PREFIX "org.cinnamon.desktop.thumbnail-cache" #define THUMB_AGE_KEY "maximum-age" #define THUMB_SIZE_KEY "maximum-size" struct CsdHousekeepingManagerPrivate { GSettings *settings; guint long_term_cb; guint short_term_cb; }; #define CSD_HOUSEKEEPING_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_HOUSEKEEPING_MANAGER, CsdHousekeepingManagerPrivate)) static void csd_housekeeping_manager_class_init (CsdHousekeepingManagerClass *klass); static void csd_housekeeping_manager_init (CsdHousekeepingManager *housekeeping_manager); G_DEFINE_TYPE (CsdHousekeepingManager, csd_housekeeping_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; typedef struct { glong now; glong max_age; goffset total_size; goffset max_size; } PurgeData; typedef struct { time_t mtime; char *path; glong size; } ThumbData; static void thumb_data_free (gpointer data) { ThumbData *info = data; if (info) { g_free (info->path); g_free (info); } } static GList * read_dir_for_purge (const char *path, GList *files) { GFile *read_path; GFileEnumerator *enum_dir; read_path = g_file_new_for_path (path); enum_dir = g_file_enumerate_children (read_path, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_TIME_MODIFIED "," G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, NULL); if (enum_dir != NULL) { GFileInfo *info; while ((info = g_file_enumerator_next_file (enum_dir, NULL, NULL)) != NULL) { const char *name; name = g_file_info_get_name (info); if (strlen (name) == 36 && strcmp (name + 32, ".png") == 0) { ThumbData *td; GFile *entry; char *entry_path; GTimeVal mod_time; entry = g_file_get_child (read_path, name); entry_path = g_file_get_path (entry); g_object_unref (entry); g_file_info_get_modification_time (info, &mod_time); td = g_new0 (ThumbData, 1); td->path = entry_path; td->mtime = mod_time.tv_sec; td->size = g_file_info_get_size (info); files = g_list_prepend (files, td); } g_object_unref (info); } g_object_unref (enum_dir); } g_object_unref (read_path); return files; } static void purge_old_thumbnails (ThumbData *info, PurgeData *purge_data) { if ((purge_data->now - info->mtime) > purge_data->max_age) { g_unlink (info->path); info->size = 0; } else { purge_data->total_size += info->size; } } static int sort_file_mtime (ThumbData *file1, ThumbData *file2) { return file1->mtime - file2->mtime; } static char ** get_thumbnail_dirs (void) { GPtrArray *array; char *path; array = g_ptr_array_new (); /* check new XDG cache */ path = g_build_filename (g_get_user_cache_dir (), "thumbnails", "normal", NULL); g_ptr_array_add (array, path); path = g_build_filename (g_get_user_cache_dir (), "thumbnails", "large", NULL); g_ptr_array_add (array, path); path = g_build_filename (g_get_user_cache_dir (), "thumbnails", "fail", "gnome-thumbnail-factory", NULL); g_ptr_array_add (array, path); /* cleanup obsolete locations too */ path = g_build_filename (g_get_home_dir (), ".thumbnails", "normal", NULL); g_ptr_array_add (array, path); path = g_build_filename (g_get_home_dir (), ".thumbnails", "large", NULL); g_ptr_array_add (array, path); path = g_build_filename (g_get_home_dir (), ".thumbnails", "fail", "gnome-thumbnail-factory", NULL); g_ptr_array_add (array, path); g_ptr_array_add (array, NULL); return (char **) g_ptr_array_free (array, FALSE); } static void purge_thumbnail_cache (CsdHousekeepingManager *manager) { char **paths; GList *files; PurgeData purge_data; GTimeVal current_time; guint i; g_debug ("housekeeping: checking thumbnail cache size and freshness"); paths = get_thumbnail_dirs (); files = NULL; for (i = 0; paths[i] != NULL; i++) files = read_dir_for_purge (paths[i], files); g_strfreev (paths); g_get_current_time (¤t_time); purge_data.now = current_time.tv_sec; purge_data.max_age = g_settings_get_int (manager->priv->settings, THUMB_AGE_KEY) * 24 * 60 * 60; purge_data.max_size = g_settings_get_int (manager->priv->settings, THUMB_SIZE_KEY) * 1024 * 1024; purge_data.total_size = 0; if (purge_data.max_age >= 0) g_list_foreach (files, (GFunc) purge_old_thumbnails, &purge_data); if ((purge_data.total_size > purge_data.max_size) && (purge_data.max_size >= 0)) { GList *scan; files = g_list_sort (files, (GCompareFunc) sort_file_mtime); for (scan = files; scan && (purge_data.total_size > purge_data.max_size); scan = scan->next) { ThumbData *info = scan->data; g_unlink (info->path); purge_data.total_size -= info->size; } } g_list_foreach (files, (GFunc) thumb_data_free, NULL); g_list_free (files); } static gboolean do_cleanup (CsdHousekeepingManager *manager) { purge_thumbnail_cache (manager); return TRUE; } static gboolean do_cleanup_once (CsdHousekeepingManager *manager) { do_cleanup (manager); manager->priv->short_term_cb = 0; return FALSE; } static void do_cleanup_soon (CsdHousekeepingManager *manager) { if (manager->priv->short_term_cb == 0) { g_debug ("housekeeping: will tidy up in 2 minutes"); manager->priv->short_term_cb = g_timeout_add_seconds (INTERVAL_TWO_MINUTES, (GSourceFunc) do_cleanup_once, manager); } } static void settings_changed_callback (GSettings *settings, const char *key, CsdHousekeepingManager *manager) { do_cleanup_soon (manager); } gboolean csd_housekeeping_manager_start (CsdHousekeepingManager *manager, GError **error) { g_debug ("Starting housekeeping manager"); cinnamon_settings_profile_start (NULL); csd_ldsm_setup (FALSE); manager->priv->settings = g_settings_new (THUMB_PREFIX); g_signal_connect (G_OBJECT (manager->priv->settings), "changed", G_CALLBACK (settings_changed_callback), manager); /* Clean once, a few minutes after start-up */ do_cleanup_soon (manager); /* Clean periodically, on a daily basis. */ manager->priv->long_term_cb = g_timeout_add_seconds (INTERVAL_ONCE_A_DAY, (GSourceFunc) do_cleanup, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_housekeeping_manager_stop (CsdHousekeepingManager *manager) { CsdHousekeepingManagerPrivate *p = manager->priv; g_debug ("Stopping housekeeping manager"); if (p->short_term_cb) { g_source_remove (p->short_term_cb); p->short_term_cb = 0; } if (p->long_term_cb) { g_source_remove (p->long_term_cb); p->long_term_cb = 0; /* Do a clean-up on shutdown if and only if the size or age limits have been set to paranoid levels (zero) */ if ((g_settings_get_int (p->settings, THUMB_AGE_KEY) == 0) || (g_settings_get_int (p->settings, THUMB_SIZE_KEY) == 0)) { do_cleanup (manager); } g_object_unref (p->settings); p->settings = NULL; } csd_ldsm_clean (); } static void csd_housekeeping_manager_class_init (CsdHousekeepingManagerClass *klass) { g_type_class_add_private (klass, sizeof (CsdHousekeepingManagerPrivate)); } static void csd_housekeeping_manager_init (CsdHousekeepingManager *manager) { manager->priv = CSD_HOUSEKEEPING_MANAGER_GET_PRIVATE (manager); } CsdHousekeepingManager * csd_housekeeping_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_HOUSEKEEPING_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_HOUSEKEEPING_MANAGER (manager_object); } cinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-disk-space-test.c0000664000175000017500000000251612625665665025462 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * 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. * */ #include "config.h" #include #include #include "csd-disk-space.h" int main (int argc, char **argv) { GMainLoop *loop; gtk_init (&argc, &argv); notify_init ("csd-disk-space-test"); loop = g_main_loop_new (NULL, FALSE); csd_ldsm_setup (TRUE); g_main_loop_run (loop); csd_ldsm_clean (); g_main_loop_unref (loop); return 0; } cinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-disk-space-helper.c0000664000175000017500000000667512625665665025774 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * Copyright (c) 2008, Novell, Inc. * Copyright (c) 2012, Red Hat, Inc. * * Authors: Vincent Untz * 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 "csd-disk-space-helper.h" gboolean csd_should_ignore_unix_mount (GUnixMountEntry *mount) { const char *fs, *device; guint i; /* This is borrowed from GLib and used as a way to determine * which mounts we should ignore by default. GLib doesn't * expose this in a way that allows it to be used for this * purpose */ /* We also ignore network filesystems */ const gchar *ignore_fs[] = { "adfs", "afs", "auto", "autofs", "autofs4", "cifs", "cxfs", "devfs", "devpts", "ecryptfs", "fdescfs", "gfs", "gfs2", "kernfs", "linprocfs", "linsysfs", "lustre", "lustre_lite", "ncpfs", "nfs", "nfs4", "nfsd", "ocfs2", "proc", "procfs", "ptyfs", "rpc_pipefs", "selinuxfs", "smbfs", "sysfs", "tmpfs", "usbfs", "zfs", NULL }; const gchar *ignore_devices[] = { "none", "sunrpc", "devpts", "nfsd", "/dev/loop", "/dev/vn", NULL }; fs = g_unix_mount_get_fs_type (mount); device = g_unix_mount_get_device_path (mount); for (i = 0; ignore_fs[i] != NULL; i++) if (g_str_equal (ignore_fs[i], fs)) return TRUE; for (i = 0; ignore_devices[i] != NULL; i++) if (g_str_equal (ignore_devices[i], device)) return TRUE; return FALSE; } gboolean csd_is_removable_mount (GUnixMountEntry *mount) { const char *mount_path; char *path; mount_path = g_unix_mount_get_mount_path (mount); if (mount_path == NULL) return FALSE; path = g_strdup_printf ("/run/media/%s", g_get_user_name ()); if (g_str_has_prefix (mount_path, path)) { g_free (path); return TRUE; } g_free (path); return FALSE; } cinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-ldsm-dialog.c0000664000175000017500000005021012625665665024650 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * csd-ldsm-dialog.c * Copyright (C) Chris Coulson 2009 * * 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 "csd-ldsm-dialog.h" #define SETTINGS_HOUSEKEEPING_DIR "org.cinnamon.settings-daemon.plugins.housekeeping" enum { PROP_0, PROP_OTHER_USABLE_PARTITIONS, PROP_OTHER_PARTITIONS, PROP_HAS_TRASH, PROP_SPACE_REMAINING, PROP_PARTITION_NAME, PROP_MOUNT_PATH }; struct CsdLdsmDialogPrivate { GtkWidget *primary_label; GtkWidget *secondary_label; GtkWidget *ignore_check_button; gboolean other_usable_partitions; gboolean other_partitions; gboolean has_trash; gint64 space_remaining; gchar *partition_name; gchar *mount_path; }; #define CSD_LDSM_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_LDSM_DIALOG, CsdLdsmDialogPrivate)) static void csd_ldsm_dialog_class_init (CsdLdsmDialogClass *klass); static void csd_ldsm_dialog_init (CsdLdsmDialog *dialog); G_DEFINE_TYPE (CsdLdsmDialog, csd_ldsm_dialog, GTK_TYPE_DIALOG); static const gchar* csd_ldsm_dialog_get_checkbutton_text (CsdLdsmDialog *dialog) { g_return_val_if_fail (CSD_IS_LDSM_DIALOG (dialog), NULL); if (dialog->priv->other_partitions) return _("Don't show any warnings again for this file system"); else return _("Don't show any warnings again"); } static gchar* csd_ldsm_dialog_get_primary_text (CsdLdsmDialog *dialog) { gchar *primary_text, *free_space; g_return_val_if_fail (CSD_IS_LDSM_DIALOG (dialog), NULL); free_space = g_format_size (dialog->priv->space_remaining); if (dialog->priv->other_partitions) { primary_text = g_strdup_printf (_("The volume \"%s\" has only %s disk space remaining."), dialog->priv->partition_name, free_space); } else { primary_text = g_strdup_printf (_("This computer has only %s disk space remaining."), free_space); } g_free (free_space); return primary_text; } static const gchar* csd_ldsm_dialog_get_secondary_text (CsdLdsmDialog *dialog) { g_return_val_if_fail (CSD_IS_LDSM_DIALOG (dialog), NULL); if (dialog->priv->other_usable_partitions) { if (dialog->priv->has_trash) { return _("You can free up disk space by emptying the Trash, removing " \ "unused programs or files, or moving files to another disk or partition."); } else { return _("You can free up disk space by removing unused programs or files, " \ "or by moving files to another disk or partition."); } } else { if (dialog->priv->has_trash) { return _("You can free up disk space by emptying the Trash, removing unused " \ "programs or files, or moving files to an external disk."); } else { return _("You can free up disk space by removing unused programs or files, " \ "or by moving files to an external disk."); } } } static gint ignore_path_compare (gconstpointer a, gconstpointer b) { return g_strcmp0 ((const gchar *)a, (const gchar *)b); } static gboolean update_ignore_paths (GSList **ignore_paths, const gchar *mount_path, gboolean ignore) { GSList *found; gchar *path_to_remove; found = g_slist_find_custom (*ignore_paths, mount_path, (GCompareFunc) ignore_path_compare); if (ignore && (found == NULL)) { *ignore_paths = g_slist_prepend (*ignore_paths, g_strdup (mount_path)); return TRUE; } if (!ignore && (found != NULL)) { path_to_remove = found->data; *ignore_paths = g_slist_remove (*ignore_paths, path_to_remove); g_free (path_to_remove); return TRUE; } return FALSE; } static void ignore_check_button_toggled_cb (GtkToggleButton *button, gpointer user_data) { CsdLdsmDialog *dialog = (CsdLdsmDialog *)user_data; GSettings *settings; gchar **settings_list; gboolean ignore, updated; gint i; GSList *ignore_paths = NULL; settings = g_settings_new (SETTINGS_HOUSEKEEPING_DIR); settings_list = g_settings_get_strv (settings, "ignore-paths"); for (i = 0; i < G_N_ELEMENTS (settings_list); i++) { if (settings_list[i] != NULL) ignore_paths = g_slist_append (ignore_paths, g_strdup (settings_list[i])); } ignore = gtk_toggle_button_get_active (button); updated = update_ignore_paths (&ignore_paths, dialog->priv->mount_path, ignore); g_strfreev (settings_list); if (updated) { GSList *l; GPtrArray *array = g_ptr_array_new (); for (l = ignore_paths; l != NULL; l = l->next) g_ptr_array_add (array, l->data); g_ptr_array_add (array, NULL); if (!g_settings_set_strv (settings, "ignore-paths", (const gchar **) array->pdata)) { g_warning ("Cannot change ignore preference - failed to commit changes"); } g_ptr_array_free (array, FALSE); } g_slist_foreach (ignore_paths, (GFunc) g_free, NULL); g_slist_free (ignore_paths); g_object_unref (settings); } static void csd_ldsm_dialog_init (CsdLdsmDialog *dialog) { GtkWidget *main_vbox, *text_vbox, *hbox; GtkWidget *image; dialog->priv = CSD_LDSM_DIALOG_GET_PRIVATE (dialog); main_vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); /* Set up all the window stuff here */ gtk_window_set_title (GTK_WINDOW (dialog), _("Low Disk Space")); gtk_window_set_icon_name (GTK_WINDOW (dialog), GTK_STOCK_DIALOG_WARNING); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); gtk_window_set_urgency_hint (GTK_WINDOW (dialog), TRUE); gtk_window_set_focus_on_map (GTK_WINDOW (dialog), FALSE); gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); /* Create the image */ image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG); gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0); /* Create the labels */ dialog->priv->primary_label = gtk_label_new (NULL); gtk_label_set_line_wrap (GTK_LABEL (dialog->priv->primary_label), TRUE); gtk_label_set_single_line_mode (GTK_LABEL (dialog->priv->primary_label), FALSE); gtk_misc_set_alignment (GTK_MISC (dialog->priv->primary_label), 0.0, 0.0); dialog->priv->secondary_label = gtk_label_new (NULL); gtk_label_set_line_wrap (GTK_LABEL (dialog->priv->secondary_label), TRUE); gtk_label_set_single_line_mode (GTK_LABEL (dialog->priv->secondary_label), FALSE); gtk_misc_set_alignment (GTK_MISC (dialog->priv->secondary_label), 0.0, 0.0); /* Create the check button to ignore future warnings */ dialog->priv->ignore_check_button = gtk_check_button_new (); /* The button should be inactive if the dialog was just called. * I suppose it could be possible for the user to manually edit the GSettings key between * the mount being checked and the dialog appearing, but I don't think it matters * too much */ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->ignore_check_button), FALSE); g_signal_connect (dialog->priv->ignore_check_button, "toggled", G_CALLBACK (ignore_check_button_toggled_cb), dialog); /* Now set up the dialog's GtkBox's' */ gtk_box_set_spacing (GTK_BOX (main_vbox), 14); hbox = gtk_hbox_new (FALSE, 12); gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); text_vbox = gtk_vbox_new (FALSE, 12); gtk_box_pack_start (GTK_BOX (text_vbox), dialog->priv->primary_label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (text_vbox), dialog->priv->secondary_label, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (text_vbox), dialog->priv->ignore_check_button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), text_vbox, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0); /* Set up the action area */ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dialog))), 6); gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_action_area (GTK_DIALOG (dialog))), 5); gtk_widget_show_all (hbox); } static void csd_ldsm_dialog_finalize (GObject *object) { CsdLdsmDialog *self; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_LDSM_DIALOG (object)); self = CSD_LDSM_DIALOG (object); if (self->priv->partition_name) g_free (self->priv->partition_name); if (self->priv->mount_path) g_free (self->priv->mount_path); G_OBJECT_CLASS (csd_ldsm_dialog_parent_class)->finalize (object); } static void csd_ldsm_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsdLdsmDialog *self; g_return_if_fail (CSD_IS_LDSM_DIALOG (object)); self = CSD_LDSM_DIALOG (object); switch (prop_id) { case PROP_OTHER_USABLE_PARTITIONS: self->priv->other_usable_partitions = g_value_get_boolean (value); break; case PROP_OTHER_PARTITIONS: self->priv->other_partitions = g_value_get_boolean (value); break; case PROP_HAS_TRASH: self->priv->has_trash = g_value_get_boolean (value); break; case PROP_SPACE_REMAINING: self->priv->space_remaining = g_value_get_int64 (value); break; case PROP_PARTITION_NAME: self->priv->partition_name = g_value_dup_string (value); break; case PROP_MOUNT_PATH: self->priv->mount_path = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_ldsm_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsdLdsmDialog *self; g_return_if_fail (CSD_IS_LDSM_DIALOG (object)); self = CSD_LDSM_DIALOG (object); switch (prop_id) { case PROP_OTHER_USABLE_PARTITIONS: g_value_set_boolean (value, self->priv->other_usable_partitions); break; case PROP_OTHER_PARTITIONS: g_value_set_boolean (value, self->priv->other_partitions); break; case PROP_HAS_TRASH: g_value_set_boolean (value, self->priv->has_trash); break; case PROP_SPACE_REMAINING: g_value_set_int64 (value, self->priv->space_remaining); break; case PROP_PARTITION_NAME: g_value_set_string (value, self->priv->partition_name); break; case PROP_MOUNT_PATH: g_value_set_string (value, self->priv->mount_path); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_ldsm_dialog_class_init (CsdLdsmDialogClass *klass) { GObjectClass* object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_ldsm_dialog_finalize; object_class->set_property = csd_ldsm_dialog_set_property; object_class->get_property = csd_ldsm_dialog_get_property; g_object_class_install_property (object_class, PROP_OTHER_USABLE_PARTITIONS, g_param_spec_boolean ("other-usable-partitions", "other-usable-partitions", "Set to TRUE if there are other usable partitions on the system", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_OTHER_PARTITIONS, g_param_spec_boolean ("other-partitions", "other-partitions", "Set to TRUE if there are other partitions on the system", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_HAS_TRASH, g_param_spec_boolean ("has-trash", "has-trash", "Set to TRUE if the partition has files in it's trash folder that can be deleted", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_SPACE_REMAINING, g_param_spec_int64 ("space-remaining", "space-remaining", "Specify how much space is remaining in bytes", G_MININT64, G_MAXINT64, 0, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_PARTITION_NAME, g_param_spec_string ("partition-name", "partition-name", "Specify the name of the partition", "Unknown", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_MOUNT_PATH, g_param_spec_string ("mount-path", "mount-path", "Specify the mount path for the partition", "Unknown", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_type_class_add_private (klass, sizeof (CsdLdsmDialogPrivate)); } CsdLdsmDialog* csd_ldsm_dialog_new (gboolean other_usable_partitions, gboolean other_partitions, gboolean display_baobab, gboolean display_empty_trash, gint64 space_remaining, const gchar *partition_name, const gchar *mount_path) { CsdLdsmDialog *dialog; GtkWidget *button_empty_trash, *button_ignore, *button_analyze; GtkWidget *empty_trash_image, *analyze_image, *ignore_image; gchar *primary_text, *primary_text_markup; const gchar *secondary_text, *checkbutton_text; dialog = CSD_LDSM_DIALOG (g_object_new (CSD_TYPE_LDSM_DIALOG, "other-usable-partitions", other_usable_partitions, "other-partitions", other_partitions, "has-trash", display_empty_trash, "space-remaining", space_remaining, "partition-name", partition_name, "mount-path", mount_path, NULL)); /* Add some buttons */ if (dialog->priv->has_trash) { button_empty_trash = gtk_dialog_add_button (GTK_DIALOG (dialog), _("Empty Trash"), CSD_LDSM_DIALOG_RESPONSE_EMPTY_TRASH); empty_trash_image = gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (button_empty_trash), empty_trash_image); } if (display_baobab) { button_analyze = gtk_dialog_add_button (GTK_DIALOG (dialog), _("Examine…"), CSD_LDSM_DIALOG_RESPONSE_ANALYZE); analyze_image = gtk_image_new_from_icon_name ("baobab", GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (button_analyze), analyze_image); } button_ignore = gtk_dialog_add_button (GTK_DIALOG (dialog), _("Ignore"), GTK_RESPONSE_CANCEL); ignore_image = gtk_image_new_from_stock (GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON); gtk_button_set_image (GTK_BUTTON (button_ignore), ignore_image); gtk_widget_grab_default (button_ignore); /* Set the label text */ primary_text = csd_ldsm_dialog_get_primary_text (dialog); primary_text_markup = g_markup_printf_escaped ("%s", primary_text); gtk_label_set_markup (GTK_LABEL (dialog->priv->primary_label), primary_text_markup); secondary_text = csd_ldsm_dialog_get_secondary_text (dialog); gtk_label_set_text (GTK_LABEL (dialog->priv->secondary_label), secondary_text); checkbutton_text = csd_ldsm_dialog_get_checkbutton_text (dialog); gtk_button_set_label (GTK_BUTTON (dialog->priv->ignore_check_button), checkbutton_text); g_free (primary_text); g_free (primary_text_markup); return dialog; } cinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-disk-space.h0000664000175000017500000000223212625665665024505 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * 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 __CSD_DISK_SPACE_H #define __CSD_DISK_SPACE_H #include G_BEGIN_DECLS void csd_ldsm_setup (gboolean check_now); void csd_ldsm_clean (void); /* for the test */ void csd_ldsm_show_empty_trash (void); G_END_DECLS #endif /* __CSD_DISK_SPACE_H */ cinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-disk-space-helper.h0000664000175000017500000000242612625665665025767 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * Copyright (c) 2008, Novell, Inc. * Copyright (c) 2012, Red Hat, Inc. * * Authors: Vincent Untz * 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_DISK_SPACE_HELPER_H #define __CSD_DISK_SPACE_HELPER_H #include #include G_BEGIN_DECLS gboolean csd_should_ignore_unix_mount (GUnixMountEntry *mount); gboolean csd_is_removable_mount (GUnixMountEntry *mount); G_END_DECLS #endif /* __CSD_DISK_SPACE_HELPER_H */ cinnamon-settings-daemon-2.8.3/plugins/housekeeping/housekeeping.cinnamon-settings-plugin.in0000664000175000017500000000041512625665665031514 0ustar fabiofabio[Cinnamon Settings Plugin] Module=housekeeping IAge=0 _Name=Housekeeping _Description=Automatically prunes thumbnail caches and other transient files, and warns about low disk space Authors=Michael J. Chudobiak Copyright=Copyright © 2008 Michael J. Chudobiak Website= cinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-disk-space.c0000664000175000017500000007150612625665665024512 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * vim: set et sw=8 ts=8: * * 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. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "csd-disk-space.h" #include "csd-ldsm-dialog.h" #include "csd-disk-space-helper.h" #define GIGABYTE 1024 * 1024 * 1024 #define CHECK_EVERY_X_SECONDS 60 #define DISK_SPACE_ANALYZER "baobab" #define SETTINGS_HOUSEKEEPING_DIR "org.cinnamon.settings-daemon.plugins.housekeeping" #define SETTINGS_FREE_PC_NOTIFY_KEY "free-percent-notify" #define SETTINGS_FREE_PC_NOTIFY_AGAIN_KEY "free-percent-notify-again" #define SETTINGS_FREE_SIZE_NO_NOTIFY "free-size-gb-no-notify" #define SETTINGS_MIN_NOTIFY_PERIOD "min-notify-period" #define SETTINGS_IGNORE_PATHS "ignore-paths" typedef struct { GUnixMountEntry *mount; struct statvfs buf; time_t notify_time; } LdsmMountInfo; static GHashTable *ldsm_notified_hash = NULL; static unsigned int ldsm_timeout_id = 0; static GUnixMountMonitor *ldsm_monitor = NULL; static double free_percent_notify = 0.05; static double free_percent_notify_again = 0.01; static unsigned int free_size_gb_no_notify = 2; static unsigned int min_notify_period = 10; static GSList *ignore_paths = NULL; static GSettings *settings = NULL; static CsdLdsmDialog *dialog = NULL; static NotifyNotification *notification = NULL; static guint64 *time_read; static gchar* ldsm_get_fs_id_for_path (const gchar *path) { GFile *file; GFileInfo *fileinfo; gchar *attr_id_fs; file = g_file_new_for_path (path); fileinfo = g_file_query_info (file, G_FILE_ATTRIBUTE_ID_FILESYSTEM, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL); if (fileinfo) { attr_id_fs = g_strdup (g_file_info_get_attribute_string (fileinfo, G_FILE_ATTRIBUTE_ID_FILESYSTEM)); g_object_unref (fileinfo); } else { attr_id_fs = NULL; } g_object_unref (file); return attr_id_fs; } static gboolean ldsm_mount_has_trash (LdsmMountInfo *mount) { const gchar *user_data_dir; gchar *user_data_attr_id_fs; gchar *path_attr_id_fs; gboolean mount_uses_user_trash = FALSE; gchar *trash_files_dir; gboolean has_trash = FALSE; GDir *dir; const gchar *path; user_data_dir = g_get_user_data_dir (); user_data_attr_id_fs = ldsm_get_fs_id_for_path (user_data_dir); path = g_unix_mount_get_mount_path (mount->mount); path_attr_id_fs = ldsm_get_fs_id_for_path (path); if (g_strcmp0 (user_data_attr_id_fs, path_attr_id_fs) == 0) { /* The volume that is low on space is on the same volume as our home * directory. This means the trash is at $XDG_DATA_HOME/Trash, * not at the root of the volume which is full. */ mount_uses_user_trash = TRUE; } g_free (user_data_attr_id_fs); g_free (path_attr_id_fs); /* I can't think of a better way to find out if a volume has any trash. Any suggestions? */ if (mount_uses_user_trash) { trash_files_dir = g_build_filename (g_get_user_data_dir (), "Trash", "files", NULL); } else { gchar *uid; uid = g_strdup_printf ("%d", getuid ()); trash_files_dir = g_build_filename (path, ".Trash", uid, "files", NULL); if (!g_file_test (trash_files_dir, G_FILE_TEST_IS_DIR)) { gchar *trash_dir; g_free (trash_files_dir); trash_dir = g_strdup_printf (".Trash-%s", uid); trash_files_dir = g_build_filename (path, trash_dir, "files", NULL); g_free (trash_dir); if (!g_file_test (trash_files_dir, G_FILE_TEST_IS_DIR)) { g_free (trash_files_dir); g_free (uid); return has_trash; } } g_free (uid); } dir = g_dir_open (trash_files_dir, 0, NULL); if (dir) { if (g_dir_read_name (dir)) has_trash = TRUE; g_dir_close (dir); } g_free (trash_files_dir); return has_trash; } static void ldsm_analyze_path (const gchar *path) { const gchar *argv[] = { DISK_SPACE_ANALYZER, path, NULL }; g_spawn_async (NULL, (gchar **) argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL); } static gboolean server_has_actions (void) { gboolean has; GList *caps; GList *l; caps = notify_get_server_caps (); if (caps == NULL) { fprintf (stderr, "Failed to receive server caps.\n"); return FALSE; } l = g_list_find_custom (caps, "actions", (GCompareFunc)strcmp); has = l != NULL; g_list_foreach (caps, (GFunc) g_free, NULL); g_list_free (caps); return has; } static void ignore_callback (NotifyNotification *n, const char *action) { g_assert (action != NULL); g_assert (strcmp (action, "ignore") == 0); /* Do nothing */ notify_notification_close (n, NULL); } static void examine_callback (NotifyNotification *n, const char *action, const char *path) { g_assert (action != NULL); g_assert (strcmp (action, "examine") == 0); ldsm_analyze_path (path); notify_notification_close (n, NULL); } static void nemo_empty_trash_cb (GObject *object, GAsyncResult *res, gpointer _unused) { GDBusProxy *proxy = G_DBUS_PROXY (object); GError *error = NULL; g_dbus_proxy_call_finish (proxy, res, &error); if (error != NULL) { g_warning ("Unable to call EmptyTrash() on the Nemo DBus interface: %s", error->message); g_error_free (error); } /* clean up the proxy object */ g_object_unref (proxy); } static void nemo_proxy_ready_cb (GObject *object, GAsyncResult *res, gpointer _unused) { GDBusProxy *proxy = NULL; GError *error = NULL; proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (proxy == NULL) { g_warning ("Unable to create a proxy object for the Nemo DBus interface: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, "EmptyTrash", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, nemo_empty_trash_cb, NULL); } void csd_ldsm_show_empty_trash (void) { /* prepare the Nemo proxy object */ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.Nemo", "/org/Nemo", "org.Nemo.FileOperations", NULL, nemo_proxy_ready_cb, NULL); } static void empty_trash_callback (NotifyNotification *n, const char *action) { g_assert (action != NULL); g_assert (strcmp (action, "empty-trash") == 0); csd_ldsm_show_empty_trash (); notify_notification_close (n, NULL); } static void on_notification_closed (NotifyNotification *n) { g_object_unref (notification); notification = NULL; } static gboolean ldsm_notify_for_mount (LdsmMountInfo *mount, gboolean multiple_volumes, gboolean other_usable_volumes) { gchar *name, *program; gint64 free_space; gint response; gboolean has_trash; gboolean has_disk_analyzer; gboolean retval = TRUE; gchar *path; /* Don't show a notice if one is already displayed */ if (dialog != NULL || notification != NULL) return retval; name = g_unix_mount_guess_name (mount->mount); free_space = (gint64) mount->buf.f_frsize * (gint64) mount->buf.f_bavail; has_trash = ldsm_mount_has_trash (mount); path = g_strdup (g_unix_mount_get_mount_path (mount->mount)); program = g_find_program_in_path (DISK_SPACE_ANALYZER); has_disk_analyzer = (program != NULL); g_free (program); if (server_has_actions ()) { char *free_space_str; char *summary; char *body; free_space_str = g_format_size (free_space); if (multiple_volumes) { summary = g_strdup_printf (_("Low Disk Space on \"%s\""), name); if (has_trash) { body = g_strdup_printf (_("The volume \"%s\" has only %s disk space remaining. You may free up some space by emptying the trash."), name, free_space_str); } else { body = g_strdup_printf (_("The volume \"%s\" has only %s disk space remaining."), name, free_space_str); } } else { summary = g_strdup (_("Low Disk Space")); if (has_trash) { body = g_strdup_printf (_("This computer has only %s disk space remaining. You may free up some space by emptying the trash."), free_space_str); } else { body = g_strdup_printf (_("This computer has only %s disk space remaining."), free_space_str); } } g_free (free_space_str); notification = notify_notification_new (summary, body, "drive-harddisk-symbolic"); g_free (summary); g_free (body); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); notify_notification_set_app_name (notification, _("Disk space")); notify_notification_set_hint (notification, "transient", g_variant_new_boolean (TRUE)); notify_notification_set_urgency (notification, NOTIFY_URGENCY_CRITICAL); notify_notification_set_timeout (notification, NOTIFY_EXPIRES_DEFAULT); if (has_disk_analyzer) { notify_notification_add_action (notification, "examine", _("Examine"), (NotifyActionCallback) examine_callback, g_strdup (path), g_free); } if (has_trash) { notify_notification_add_action (notification, "empty-trash", _("Empty Trash"), (NotifyActionCallback) empty_trash_callback, NULL, NULL); } notify_notification_add_action (notification, "ignore", _("Ignore"), (NotifyActionCallback) ignore_callback, NULL, NULL); notify_notification_set_category (notification, "device"); if (!notify_notification_show (notification, NULL)) { g_warning ("failed to send disk space notification\n"); } } else { dialog = csd_ldsm_dialog_new (other_usable_volumes, multiple_volumes, has_disk_analyzer, has_trash, free_space, name, path); g_object_ref (G_OBJECT (dialog)); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog)); dialog = NULL; switch (response) { case GTK_RESPONSE_CANCEL: retval = FALSE; break; case CSD_LDSM_DIALOG_RESPONSE_ANALYZE: retval = FALSE; ldsm_analyze_path (path); break; case CSD_LDSM_DIALOG_RESPONSE_EMPTY_TRASH: retval = TRUE; csd_ldsm_show_empty_trash (); break; case GTK_RESPONSE_NONE: case GTK_RESPONSE_DELETE_EVENT: retval = TRUE; break; default: g_assert_not_reached (); } } g_free (name); g_free (path); return retval; } static gboolean ldsm_mount_has_space (LdsmMountInfo *mount) { gdouble free_space; free_space = (double) mount->buf.f_bavail / (double) mount->buf.f_blocks; /* enough free space, nothing to do */ if (free_space > free_percent_notify) return TRUE; if (((gint64) mount->buf.f_frsize * (gint64) mount->buf.f_bavail) > ((gint64) free_size_gb_no_notify * GIGABYTE)) return TRUE; /* If we got here, then this volume is low on space */ return FALSE; } static gboolean ldsm_mount_is_virtual (LdsmMountInfo *mount) { if (mount->buf.f_blocks == 0) { /* Filesystems with zero blocks are virtual */ return TRUE; } return FALSE; } static gint ldsm_ignore_path_compare (gconstpointer a, gconstpointer b) { return g_strcmp0 ((const gchar *)a, (const gchar *)b); } static gboolean ldsm_mount_is_user_ignore (const gchar *path) { if (g_slist_find_custom (ignore_paths, path, (GCompareFunc) ldsm_ignore_path_compare) != NULL) return TRUE; else return FALSE; } static void ldsm_free_mount_info (gpointer data) { LdsmMountInfo *mount = data; g_return_if_fail (mount != NULL); g_unix_mount_free (mount->mount); g_free (mount); } static void ldsm_maybe_warn_mounts (GList *mounts, gboolean multiple_volumes, gboolean other_usable_volumes) { GList *l; gboolean done = FALSE; for (l = mounts; l != NULL; l = l->next) { LdsmMountInfo *mount_info = l->data; LdsmMountInfo *previous_mount_info; gdouble free_space; gdouble previous_free_space; time_t curr_time; const gchar *path; gboolean show_notify; if (done) { /* Don't show any more dialogs if the user took action with the last one. The user action * might free up space on multiple volumes, making the next dialog redundant. */ ldsm_free_mount_info (mount_info); continue; } path = g_unix_mount_get_mount_path (mount_info->mount); previous_mount_info = g_hash_table_lookup (ldsm_notified_hash, path); if (previous_mount_info != NULL) previous_free_space = (gdouble) previous_mount_info->buf.f_bavail / (gdouble) previous_mount_info->buf.f_blocks; free_space = (gdouble) mount_info->buf.f_bavail / (gdouble) mount_info->buf.f_blocks; if (previous_mount_info == NULL) { /* We haven't notified for this mount yet */ show_notify = TRUE; mount_info->notify_time = time (NULL); g_hash_table_replace (ldsm_notified_hash, g_strdup (path), mount_info); } else if ((previous_free_space - free_space) > free_percent_notify_again) { /* We've notified for this mount before and free space has decreased sufficiently since last time to notify again */ curr_time = time (NULL); if (difftime (curr_time, previous_mount_info->notify_time) > (gdouble)(min_notify_period * 60)) { show_notify = TRUE; mount_info->notify_time = curr_time; } else { /* It's too soon to show the dialog again. However, we still replace the LdsmMountInfo * struct in the hash table, but give it the notfiy time from the previous dialog. * This will stop the notification from reappearing unnecessarily as soon as the timeout expires. */ show_notify = FALSE; mount_info->notify_time = previous_mount_info->notify_time; } g_hash_table_replace (ldsm_notified_hash, g_strdup (path), mount_info); } else { /* We've notified for this mount before, but the free space hasn't decreased sufficiently to notify again */ ldsm_free_mount_info (mount_info); show_notify = FALSE; } if (show_notify) { if (ldsm_notify_for_mount (mount_info, multiple_volumes, other_usable_volumes)) done = TRUE; } } } static gboolean ldsm_check_all_mounts (gpointer data) { GList *mounts; GList *l; GList *check_mounts = NULL; GList *full_mounts = NULL; guint number_of_mounts; guint number_of_full_mounts; gboolean multiple_volumes = FALSE; gboolean other_usable_volumes = FALSE; /* We iterate through the static mounts in /etc/fstab first, seeing if * they're mounted by checking if the GUnixMountPoint has a corresponding GUnixMountEntry. * Iterating through the static mounts means we automatically ignore dynamically mounted media. */ mounts = g_unix_mount_points_get (time_read); for (l = mounts; l != NULL; l = l->next) { GUnixMountPoint *mount_point = l->data; GUnixMountEntry *mount; LdsmMountInfo *mount_info; const gchar *path; path = g_unix_mount_point_get_mount_path (mount_point); mount = g_unix_mount_at (path, time_read); g_unix_mount_point_free (mount_point); if (mount == NULL) { /* The GUnixMountPoint is not mounted */ continue; } mount_info = g_new0 (LdsmMountInfo, 1); mount_info->mount = mount; path = g_unix_mount_get_mount_path (mount); if (g_unix_mount_is_readonly (mount)) { ldsm_free_mount_info (mount_info); continue; } if (ldsm_mount_is_user_ignore (g_unix_mount_get_mount_path (mount))) { ldsm_free_mount_info (mount_info); continue; } if (csd_should_ignore_unix_mount (mount)) { ldsm_free_mount_info (mount_info); continue; } if (statvfs (path, &mount_info->buf) != 0) { ldsm_free_mount_info (mount_info); continue; } if (ldsm_mount_is_virtual (mount_info)) { ldsm_free_mount_info (mount_info); continue; } check_mounts = g_list_prepend (check_mounts, mount_info); } g_list_free (mounts); number_of_mounts = g_list_length (check_mounts); if (number_of_mounts > 1) multiple_volumes = TRUE; for (l = check_mounts; l != NULL; l = l->next) { LdsmMountInfo *mount_info = l->data; if (!ldsm_mount_has_space (mount_info)) { full_mounts = g_list_prepend (full_mounts, mount_info); } else { g_hash_table_remove (ldsm_notified_hash, g_unix_mount_get_mount_path (mount_info->mount)); ldsm_free_mount_info (mount_info); } } number_of_full_mounts = g_list_length (full_mounts); if (number_of_mounts > number_of_full_mounts) other_usable_volumes = TRUE; ldsm_maybe_warn_mounts (full_mounts, multiple_volumes, other_usable_volumes); g_list_free (check_mounts); g_list_free (full_mounts); return TRUE; } static gboolean ldsm_is_hash_item_not_in_mounts (gpointer key, gpointer value, gpointer user_data) { GList *l; for (l = (GList *) user_data; l != NULL; l = l->next) { GUnixMountEntry *mount = l->data; const char *path; path = g_unix_mount_get_mount_path (mount); if (strcmp (path, key) == 0) return FALSE; } return TRUE; } static void ldsm_mounts_changed (GObject *monitor, gpointer data) { GList *mounts; /* remove the saved data for mounts that got removed */ mounts = g_unix_mounts_get (time_read); g_hash_table_foreach_remove (ldsm_notified_hash, ldsm_is_hash_item_not_in_mounts, mounts); g_list_free_full (mounts, (GDestroyNotify) g_unix_mount_free); /* check the status now, for the new mounts */ ldsm_check_all_mounts (NULL); /* and reset the timeout */ if (ldsm_timeout_id) { g_source_remove (ldsm_timeout_id); ldsm_timeout_id = 0; } ldsm_timeout_id = g_timeout_add_seconds (CHECK_EVERY_X_SECONDS, ldsm_check_all_mounts, NULL); } static gboolean ldsm_is_hash_item_in_ignore_paths (gpointer key, gpointer value, gpointer user_data) { return ldsm_mount_is_user_ignore (key); } static void csd_ldsm_get_config (void) { gchar **settings_list; free_percent_notify = g_settings_get_double (settings, SETTINGS_FREE_PC_NOTIFY_KEY); if (free_percent_notify >= 1 || free_percent_notify < 0) { g_warning ("Invalid configuration of free_percent_notify: %f\n" \ "Using sensible default", free_percent_notify); free_percent_notify = 0.05; } free_percent_notify_again = g_settings_get_double (settings, SETTINGS_FREE_PC_NOTIFY_AGAIN_KEY); if (free_percent_notify_again >= 1 || free_percent_notify_again < 0) { g_warning ("Invalid configuration of free_percent_notify_again: %f\n" \ "Using sensible default\n", free_percent_notify_again); free_percent_notify_again = 0.01; } free_size_gb_no_notify = g_settings_get_int (settings, SETTINGS_FREE_SIZE_NO_NOTIFY); min_notify_period = g_settings_get_int (settings, SETTINGS_MIN_NOTIFY_PERIOD); if (ignore_paths != NULL) { g_slist_foreach (ignore_paths, (GFunc) g_free, NULL); g_slist_free (ignore_paths); ignore_paths = NULL; } settings_list = g_settings_get_strv (settings, SETTINGS_IGNORE_PATHS); if (settings_list != NULL) { gint i; for (i = 0; i < G_N_ELEMENTS (settings_list); i++) { if (settings_list[i] != NULL) ignore_paths = g_slist_append (ignore_paths, g_strdup (settings_list[i])); } /* Make sure we dont leave stale entries in ldsm_notified_hash */ g_hash_table_foreach_remove (ldsm_notified_hash, ldsm_is_hash_item_in_ignore_paths, NULL); g_strfreev (settings_list); } } static void csd_ldsm_update_config (GSettings *settings, const gchar *key, gpointer user_data) { csd_ldsm_get_config (); } void csd_ldsm_setup (gboolean check_now) { if (ldsm_notified_hash || ldsm_timeout_id || ldsm_monitor) { g_warning ("Low disk space monitor already initialized."); return; } ldsm_notified_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, ldsm_free_mount_info); settings = g_settings_new (SETTINGS_HOUSEKEEPING_DIR); csd_ldsm_get_config (); g_signal_connect (G_OBJECT (settings), "changed", G_CALLBACK (csd_ldsm_update_config), NULL); ldsm_monitor = g_unix_mount_monitor_new (); g_unix_mount_monitor_set_rate_limit (ldsm_monitor, 1000); g_signal_connect (ldsm_monitor, "mounts-changed", G_CALLBACK (ldsm_mounts_changed), NULL); if (check_now) ldsm_check_all_mounts (NULL); ldsm_timeout_id = g_timeout_add_seconds (CHECK_EVERY_X_SECONDS, ldsm_check_all_mounts, NULL); } void csd_ldsm_clean (void) { if (ldsm_timeout_id) { g_source_remove (ldsm_timeout_id); ldsm_timeout_id = 0; } if (ldsm_notified_hash) g_hash_table_destroy (ldsm_notified_hash); ldsm_notified_hash = NULL; if (ldsm_monitor) g_object_unref (ldsm_monitor); ldsm_monitor = NULL; if (settings != NULL) { g_object_unref (settings); } if (dialog) { gtk_widget_destroy (GTK_WIDGET (dialog)); dialog = NULL; } if (notification != NULL) { notify_notification_close (notification, NULL); notification = NULL; } if (ignore_paths) { g_slist_foreach (ignore_paths, (GFunc) g_free, NULL); g_slist_free (ignore_paths); } } cinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-ldsm-dialog.h0000664000175000017500000000510212625665665024655 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * csd-ldsm-dialog.c * Copyright (C) Chris Coulson 2009 * * 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_LDSM_DIALOG_H_ #define _CSD_LDSM_DIALOG_H_ #include #include G_BEGIN_DECLS #define CSD_TYPE_LDSM_DIALOG (csd_ldsm_dialog_get_type ()) #define CSD_LDSM_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSD_TYPE_LDSM_DIALOG, CsdLdsmDialog)) #define CSD_LDSM_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSD_TYPE_LDSM_DIALOG, CsdLdsmDialogClass)) #define CSD_IS_LDSM_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSD_TYPE_LDSM_DIALOG)) #define CSD_IS_LDSM_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSD_TYPE_LDSM_DIALOG)) #define CSD_LDSM_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CSD_TYPE_LDSM_DIALOG, CsdLdsmDialogClass)) enum { CSD_LDSM_DIALOG_RESPONSE_EMPTY_TRASH = -20, CSD_LDSM_DIALOG_RESPONSE_ANALYZE = -21 }; typedef struct CsdLdsmDialogPrivate CsdLdsmDialogPrivate; typedef struct _CsdLdsmDialogClass CsdLdsmDialogClass; typedef struct _CsdLdsmDialog CsdLdsmDialog; struct _CsdLdsmDialogClass { GtkDialogClass parent_class; }; struct _CsdLdsmDialog { GtkDialog parent_instance; CsdLdsmDialogPrivate *priv; }; GType csd_ldsm_dialog_get_type (void) G_GNUC_CONST; CsdLdsmDialog * csd_ldsm_dialog_new (gboolean other_usable_partitions, gboolean other_partitions, gboolean display_baobab, gboolean display_empty_trash, gint64 space_remaining, const gchar *partition_name, const gchar *mount_path); G_END_DECLS #endif /* _CSD_LDSM_DIALOG_H_ */ cinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-housekeeping-plugin.c0000664000175000017500000000643612625665665026451 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Michael J. Chudobiak * * 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 "cinnamon-settings-plugin.h" #include "csd-housekeeping-plugin.h" #include "csd-housekeeping-manager.h" struct CsdHousekeepingPluginPrivate { CsdHousekeepingManager *manager; }; #define CSD_HOUSEKEEPING_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_HOUSEKEEPING_PLUGIN, CsdHousekeepingPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdHousekeepingPlugin, csd_housekeeping_plugin) static void csd_housekeeping_plugin_init (CsdHousekeepingPlugin *plugin) { plugin->priv = CSD_HOUSEKEEPING_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdHousekeepingPlugin initializing"); plugin->priv->manager = csd_housekeeping_manager_new (); } static void csd_housekeeping_plugin_finalize (GObject *object) { CsdHousekeepingPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_HOUSEKEEPING_PLUGIN (object)); g_debug ("CsdHousekeepingPlugin finalizing"); plugin = CSD_HOUSEKEEPING_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_housekeeping_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating housekeeping plugin"); error = NULL; res = csd_housekeeping_manager_start (CSD_HOUSEKEEPING_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start housekeeping manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating housekeeping plugin"); csd_housekeeping_manager_stop (CSD_HOUSEKEEPING_PLUGIN (plugin)->priv->manager); } static void csd_housekeeping_plugin_class_init (CsdHousekeepingPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_housekeeping_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdHousekeepingPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/housekeeping/Makefile.am0000664000175000017500000000331512625665665023601 0ustar fabiofabioplugin_name = housekeeping COMMON_FILES = \ csd-disk-space.c \ csd-disk-space.h \ csd-ldsm-dialog.c \ csd-ldsm-dialog.h \ csd-disk-space-helper.h \ csd-disk-space-helper.c noinst_PROGRAMS = csd-disk-space-test csd-empty-trash-test csd_disk_space_test_SOURCES = \ csd-disk-space-test.c \ $(COMMON_FILES) csd_disk_space_test_LDADD = $(SETTINGS_PLUGIN_LIBS) $(GIOUNIX_LIBS) $(LIBNOTIFY_LIBS) csd_disk_space_test_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(GIOUNIX_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(AM_CFLAGS) csd_empty_trash_test_SOURCES = \ csd-empty-trash-test.c \ $(COMMON_FILES) csd_empty_trash_test_LDADD = $(SETTINGS_PLUGIN_LIBS) $(GIOUNIX_LIBS) $(LIBNOTIFY_LIBS) csd_empty_trash_test_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(GIOUNIX_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(AM_CFLAGS) plugin_LTLIBRARIES = libhousekeeping.la libhousekeeping_la_SOURCES = \ $(COMMON_FILES) \ csd-housekeeping-manager.c \ csd-housekeeping-manager.h \ csd-housekeeping-plugin.c \ csd-housekeeping-plugin.h libhousekeeping_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libhousekeeping_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(GIOUNIX_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(AM_CFLAGS) libhousekeeping_la_LDFLAGS = $(CSD_PLUGIN_LDFLAGS) libhousekeeping_la_LIBADD = $(SETTINGS_PLUGIN_LIBS) $(GIOUNIX_LIBS) $(LIBNOTIFY_LIBS) plugin_in_files = housekeeping.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = $(plugin_in_files) CLEANFILES = $(plugin_DATA) DISTCLEANFILES = $(plugin_DATA) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/housekeeping/csd-housekeeping-plugin.h0000664000175000017500000000445712625665665026457 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Michael J. Chudobiak * * 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_HOUSEKEEPING_PLUGIN_H__ #define __CSD_HOUSEKEEPING_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_HOUSEKEEPING_PLUGIN (csd_housekeeping_plugin_get_type ()) #define CSD_HOUSEKEEPING_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_HOUSEKEEPING_PLUGIN, CsdHousekeepingPlugin)) #define CSD_HOUSEKEEPING_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_HOUSEKEEPING_PLUGIN, CsdHousekeepingPluginClass)) #define CSD_IS_HOUSEKEEPING_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_HOUSEKEEPING_PLUGIN)) #define CSD_IS_HOUSEKEEPING_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_HOUSEKEEPING_PLUGIN)) #define CSD_HOUSEKEEPING_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_HOUSEKEEPING_PLUGIN, CsdHousekeepingPluginClass)) typedef struct CsdHousekeepingPluginPrivate CsdHousekeepingPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdHousekeepingPluginPrivate *priv; } CsdHousekeepingPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdHousekeepingPluginClass; GType csd_housekeeping_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_HOUSEKEEPING_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/color/0000775000175000017500000000000012625665665020173 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/color/gcm-dmi.c0000664000175000017500000001206312625665665021656 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include "gcm-dmi.h" static void gcm_dmi_finalize (GObject *object); #define GCM_DMI_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCM_TYPE_DMI, GcmDmiPrivate)) struct _GcmDmiPrivate { gchar *name; gchar *version; gchar *vendor; }; static gpointer gcm_dmi_object = NULL; G_DEFINE_TYPE (GcmDmi, gcm_dmi, G_TYPE_OBJECT) static gchar * gcm_dmi_get_from_filename (const gchar *filename) { gboolean ret; GError *error = NULL; gchar *data = NULL; /* get the contents */ ret = g_file_get_contents (filename, &data, NULL, &error); if (!ret) { if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) g_warning ("failed to get contents of %s: %s", filename, error->message); g_error_free (error); } /* process the random chars and trailing spaces */ if (data != NULL) { g_strdelimit (data, "\t_", ' '); g_strdelimit (data, "\n\r", '\0'); g_strchomp (data); } /* don't return an empty string */ if (data != NULL && data[0] == '\0') { g_free (data); data = NULL; } return data; } static gchar * gcm_dmi_get_from_filenames (const gchar * const * filenames) { guint i; gchar *tmp = NULL; /* try each one in preference order */ for (i = 0; filenames[i] != NULL; i++) { tmp = gcm_dmi_get_from_filename (filenames[i]); if (tmp != NULL) break; } return tmp; } const gchar * gcm_dmi_get_name (GcmDmi *dmi) { g_return_val_if_fail (GCM_IS_DMI (dmi), NULL); return dmi->priv->name; } const gchar * gcm_dmi_get_version (GcmDmi *dmi) { g_return_val_if_fail (GCM_IS_DMI (dmi), NULL); return dmi->priv->version; } const gchar * gcm_dmi_get_vendor (GcmDmi *dmi) { g_return_val_if_fail (GCM_IS_DMI (dmi), NULL); return dmi->priv->vendor; } static void gcm_dmi_class_init (GcmDmiClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gcm_dmi_finalize; g_type_class_add_private (klass, sizeof (GcmDmiPrivate)); } static void gcm_dmi_init (GcmDmi *dmi) { #if defined(__linux__) const gchar *sysfs_name[] = { "/sys/class/dmi/id/product_name", "/sys/class/dmi/id/board_name", NULL}; const gchar *sysfs_version[] = { "/sys/class/dmi/id/product_version", "/sys/class/dmi/id/chassis_version", "/sys/class/dmi/id/board_version", NULL}; const gchar *sysfs_vendor[] = { "/sys/class/dmi/id/sys_vendor", "/sys/class/dmi/id/chassis_vendor", "/sys/class/dmi/id/board_vendor", NULL}; #else #warning Please add dmi support for your OS const gchar *sysfs_name[] = { NULL }; const gchar *sysfs_version[] = { NULL }; const gchar *sysfs_vendor[] = { NULL }; #endif dmi->priv = GCM_DMI_GET_PRIVATE (dmi); /* get all the possible data now */ dmi->priv->name = gcm_dmi_get_from_filenames (sysfs_name); dmi->priv->version = gcm_dmi_get_from_filenames (sysfs_version); dmi->priv->vendor = gcm_dmi_get_from_filenames (sysfs_vendor); } static void gcm_dmi_finalize (GObject *object) { GcmDmi *dmi = GCM_DMI (object); g_free (dmi->priv->name); g_free (dmi->priv->version); g_free (dmi->priv->vendor); G_OBJECT_CLASS (gcm_dmi_parent_class)->finalize (object); } GcmDmi * gcm_dmi_new (void) { if (gcm_dmi_object != NULL) { g_object_ref (gcm_dmi_object); } else { gcm_dmi_object = g_object_new (GCM_TYPE_DMI, NULL); g_object_add_weak_pointer (gcm_dmi_object, &gcm_dmi_object); } return GCM_DMI (gcm_dmi_object); } cinnamon-settings-daemon-2.8.3/plugins/color/gcm-edid.h0000664000175000017500000000725312625665665022024 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009-2010 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GCM_EDID_H #define __GCM_EDID_H #include #include G_BEGIN_DECLS #define GCM_TYPE_EDID (gcm_edid_get_type ()) #define GCM_EDID(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GCM_TYPE_EDID, GcmEdid)) #define GCM_EDID_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GCM_TYPE_EDID, GcmEdidClass)) #define GCM_IS_EDID(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GCM_TYPE_EDID)) #define GCM_IS_EDID_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GCM_TYPE_EDID)) #define GCM_EDID_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GCM_TYPE_EDID, GcmEdidClass)) #define GCM_EDID_ERROR (gcm_edid_error_quark ()) typedef struct _GcmEdidPrivate GcmEdidPrivate; typedef struct _GcmEdid GcmEdid; typedef struct _GcmEdidClass GcmEdidClass; struct _GcmEdid { GObject parent; GcmEdidPrivate *priv; }; struct _GcmEdidClass { GObjectClass parent_class; }; enum { GCM_EDID_ERROR_FAILED_TO_PARSE }; GType gcm_edid_get_type (void); GQuark gcm_edid_error_quark (void); GcmEdid *gcm_edid_new (void); void gcm_edid_reset (GcmEdid *edid); gboolean gcm_edid_parse (GcmEdid *edid, const guint8 *data, gsize length, GError **error); const gchar *gcm_edid_get_monitor_name (GcmEdid *edid); const gchar *gcm_edid_get_vendor_name (GcmEdid *edid); const gchar *gcm_edid_get_serial_number (GcmEdid *edid); const gchar *gcm_edid_get_eisa_id (GcmEdid *edid); const gchar *gcm_edid_get_checksum (GcmEdid *edid); const gchar *gcm_edid_get_pnp_id (GcmEdid *edid); guint gcm_edid_get_width (GcmEdid *edid); guint gcm_edid_get_height (GcmEdid *edid); gfloat gcm_edid_get_gamma (GcmEdid *edid); const CdColorYxy *gcm_edid_get_red (GcmEdid *edid); const CdColorYxy *gcm_edid_get_green (GcmEdid *edid); const CdColorYxy *gcm_edid_get_blue (GcmEdid *edid); const CdColorYxy *gcm_edid_get_white (GcmEdid *edid); G_END_DECLS #endif /* __GCM_EDID_H */ cinnamon-settings-daemon-2.8.3/plugins/color/gcm-dmi.h0000664000175000017500000000422612625665665021665 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009-2010 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GCM_DMI_H #define __GCM_DMI_H #include G_BEGIN_DECLS #define GCM_TYPE_DMI (gcm_dmi_get_type ()) #define GCM_DMI(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GCM_TYPE_DMI, GcmDmi)) #define GCM_DMI_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GCM_TYPE_DMI, GcmDmiClass)) #define GCM_IS_DMI(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GCM_TYPE_DMI)) #define GCM_IS_DMI_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GCM_TYPE_DMI)) #define GCM_DMI_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GCM_TYPE_DMI, GcmDmiClass)) typedef struct _GcmDmiPrivate GcmDmiPrivate; typedef struct _GcmDmi GcmDmi; typedef struct _GcmDmiClass GcmDmiClass; struct _GcmDmi { GObject parent; GcmDmiPrivate *priv; }; struct _GcmDmiClass { GObjectClass parent_class; }; GType gcm_dmi_get_type (void); GcmDmi *gcm_dmi_new (void); const gchar *gcm_dmi_get_name (GcmDmi *dmi); const gchar *gcm_dmi_get_version (GcmDmi *dmi); const gchar *gcm_dmi_get_vendor (GcmDmi *dmi); G_END_DECLS #endif /* __GCM_DMI_H */ cinnamon-settings-daemon-2.8.3/plugins/color/csd-color-plugin.h0000664000175000017500000000430612625665665023530 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2011 Richard Hughes * * 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_COLOR_PLUGIN_H__ #define __CSD_COLOR_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_COLOR_PLUGIN (csd_color_plugin_get_type ()) #define CSD_COLOR_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_COLOR_PLUGIN, CsdColorPlugin)) #define CSD_COLOR_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_COLOR_PLUGIN, CsdColorPluginClass)) #define CSD_IS_COLOR_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_COLOR_PLUGIN)) #define CSD_IS_COLOR_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_COLOR_PLUGIN)) #define CSD_COLOR_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_COLOR_PLUGIN, CsdColorPluginClass)) typedef struct CsdColorPluginPrivate CsdColorPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdColorPluginPrivate *priv; } CsdColorPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdColorPluginClass; GType csd_color_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_COLOR_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/color/csd-color-manager.c0000664000175000017500000025305112625665665023642 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2011 Richard Hughes * * 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 #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include "cinnamon-settings-profile.h" #include "cinnamon-settings-session.h" #include "csd-color-manager.h" #include "gcm-profile-store.h" #include "gcm-dmi.h" #include "gcm-edid.h" #define CSD_COLOR_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_COLOR_MANAGER, CsdColorManagerPrivate)) #define GCM_SESSION_NOTIFY_TIMEOUT 30000 /* ms */ #define GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD "recalibrate-printer-threshold" #define GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD "recalibrate-display-threshold" struct CsdColorManagerPrivate { CinnamonSettingsSession *session; CdClient *client; GSettings *settings; GcmProfileStore *profile_store; GcmDmi *dmi; GnomeRRScreen *x11_screen; GHashTable *edid_cache; GdkWindow *gdk_window; CinnamonSettingsSessionState session_state; GHashTable *device_assign_hash; }; enum { PROP_0, }; static void csd_color_manager_class_init (CsdColorManagerClass *klass); static void csd_color_manager_init (CsdColorManager *color_manager); static void csd_color_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdColorManager, csd_color_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; /* see http://www.oyranos.org/wiki/index.php?title=ICC_Profiles_in_X_Specification_0.3 */ #define GCM_ICC_PROFILE_IN_X_VERSION_MAJOR 0 #define GCM_ICC_PROFILE_IN_X_VERSION_MINOR 3 typedef struct { guint32 red; guint32 green; guint32 blue; } GnomeRROutputClutItem; GQuark csd_color_manager_error_quark (void) { static GQuark quark = 0; if (!quark) quark = g_quark_from_static_string ("csd_color_manager_error"); return quark; } static GcmEdid * gcm_session_get_output_edid (CsdColorManager *manager, GnomeRROutput *output, GError **error) { const guint8 *data; gsize size; GcmEdid *edid = NULL; gboolean ret; /* can we find it in the cache */ edid = g_hash_table_lookup (manager->priv->edid_cache, gnome_rr_output_get_name (output)); if (edid != NULL) { g_object_ref (edid); goto out; } /* parse edid */ data = gnome_rr_output_get_edid_data (output, &size); if (data == NULL || size == 0) { g_set_error_literal (error, GNOME_RR_ERROR, GNOME_RR_ERROR_UNKNOWN, "unable to get EDID for output"); goto out; } edid = gcm_edid_new (); ret = gcm_edid_parse (edid, data, size, error); if (!ret) { g_object_unref (edid); edid = NULL; goto out; } /* add to cache */ g_hash_table_insert (manager->priv->edid_cache, g_strdup (gnome_rr_output_get_name (output)), g_object_ref (edid)); out: return edid; } static gboolean gcm_session_screen_set_icc_profile (CsdColorManager *manager, const gchar *filename, GError **error) { gboolean ret; gchar *data = NULL; gsize length; guint version_data; CsdColorManagerPrivate *priv = manager->priv; g_return_val_if_fail (filename != NULL, FALSE); g_debug ("setting root window ICC profile atom from %s", filename); /* get contents of file */ ret = g_file_get_contents (filename, &data, &length, error); if (!ret) goto out; /* set profile property */ gdk_property_change (priv->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE"), gdk_atom_intern_static_string ("CARDINAL"), 8, GDK_PROP_MODE_REPLACE, (const guchar *) data, length); /* set version property */ version_data = GCM_ICC_PROFILE_IN_X_VERSION_MAJOR * 100 + GCM_ICC_PROFILE_IN_X_VERSION_MINOR * 1; gdk_property_change (priv->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE_IN_X_VERSION"), gdk_atom_intern_static_string ("CARDINAL"), 8, GDK_PROP_MODE_REPLACE, (const guchar *) &version_data, 1); out: g_free (data); return ret; } static gchar * gcm_session_get_output_id (CsdColorManager *manager, GnomeRROutput *output) { const gchar *name; const gchar *serial; const gchar *vendor; GcmEdid *edid = NULL; GString *device_id; GError *error = NULL; /* all output devices are prefixed with this */ device_id = g_string_new ("xrandr"); /* get the output EDID if possible */ edid = gcm_session_get_output_edid (manager, output, &error); if (edid == NULL) { g_debug ("no edid for %s [%s], falling back to connection name", gnome_rr_output_get_name (output), error->message); g_error_free (error); g_string_append_printf (device_id, "-%s", gnome_rr_output_get_name (output)); goto out; } /* check EDID data is okay to use */ vendor = gcm_edid_get_vendor_name (edid); name = gcm_edid_get_monitor_name (edid); serial = gcm_edid_get_serial_number (edid); if (vendor == NULL && name == NULL && serial == NULL) { g_debug ("edid invalid for %s, falling back to connection name", gnome_rr_output_get_name (output)); g_string_append_printf (device_id, "-%s", gnome_rr_output_get_name (output)); goto out; } /* use EDID data */ if (vendor != NULL) g_string_append_printf (device_id, "-%s", vendor); if (name != NULL) g_string_append_printf (device_id, "-%s", name); if (serial != NULL) g_string_append_printf (device_id, "-%s", serial); out: if (edid != NULL) g_object_unref (edid); return g_string_free (device_id, FALSE); } static GnomeRROutput * gcm_session_get_output_by_edid_checksum (GnomeRRScreen *screen, const gchar *edid_md5, GError **error) { const guint8 *data; gchar *checksum; GnomeRROutput *output = NULL; GnomeRROutput **outputs; gsize size; guint i; outputs = gnome_rr_screen_list_outputs (screen); if (outputs == NULL) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "Failed to get outputs"); goto out; } /* find the output */ for (i = 0; outputs[i] != NULL && output == NULL; i++) { /* get edid */ data = gnome_rr_output_get_edid_data (outputs[i], &size); if (data == NULL || size < 0x6c) continue; checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, data, 0x6c); if (g_strcmp0 (checksum, edid_md5) == 0) output = outputs[i]; g_free (checksum); } if (output == NULL) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "no connected output with that edid hash"); } out: return output; } typedef struct { CsdColorManager *manager; CdProfile *profile; CdDevice *device; guint32 output_id; } GcmSessionAsyncHelper; static void gcm_session_async_helper_free (GcmSessionAsyncHelper *helper) { if (helper->manager != NULL) g_object_unref (helper->manager); if (helper->profile != NULL) g_object_unref (helper->profile); if (helper->device != NULL) g_object_unref (helper->device); g_free (helper); } static void gcm_session_profile_assign_add_profile_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDevice *device = CD_DEVICE (object); gboolean ret; GError *error = NULL; GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data; /* add the profile to the device */ ret = cd_device_add_profile_finish (device, res, &error); if (!ret) { /* this will fail if the profile is already added */ g_debug ("failed to assign auto-edid profile to device %s: %s", cd_device_get_id (device), error->message); g_error_free (error); goto out; } /* phew! */ g_debug ("successfully assigned %s to %s", cd_profile_get_object_path (helper->profile), cd_device_get_object_path (device)); out: gcm_session_async_helper_free (helper); } static void gcm_session_profile_assign_device_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDevice *device = CD_DEVICE (object); gboolean ret; GError *error = NULL; GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data; /* get properties */ ret = cd_device_connect_finish (device, res, &error); if (!ret) { g_warning ("cannot connect to device: %s", error->message); g_error_free (error); gcm_session_async_helper_free (helper); goto out; } /* add the profile to the device */ cd_device_add_profile (device, CD_DEVICE_RELATION_SOFT, helper->profile, NULL, gcm_session_profile_assign_add_profile_cb, helper); out: return; } static void gcm_session_profile_assign_find_device_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdClient *client = CD_CLIENT (object); CdDevice *device = NULL; GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data; GError *error = NULL; device = cd_client_find_device_finish (client, res, &error); if (device == NULL) { g_warning ("not found device which should have been added: %s", error->message); g_error_free (error); gcm_session_async_helper_free (helper); goto out; } /* get properties */ cd_device_connect (device, NULL, gcm_session_profile_assign_device_connect_cb, helper); out: if (device != NULL) g_object_unref (device); } static void gcm_session_profile_assign_profile_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdProfile *profile = CD_PROFILE (object); const gchar *edid_md5; gboolean ret; gchar *device_id = NULL; GcmSessionAsyncHelper *helper; GError *error = NULL; GHashTable *metadata = NULL; GnomeRROutput *output = NULL; CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); /* get properties */ ret = cd_profile_connect_finish (profile, res, &error); if (!ret) { g_warning ("cannot connect to profile: %s", error->message); g_error_free (error); goto out; } /* does the profile have EDID metadata? */ metadata = cd_profile_get_metadata (profile); edid_md5 = g_hash_table_lookup (metadata, CD_PROFILE_METADATA_EDID_MD5); if (edid_md5 == NULL) goto out; /* get the GnomeRROutput for the edid */ output = gcm_session_get_output_by_edid_checksum (manager->priv->x11_screen, edid_md5, &error); if (output == NULL) { g_debug ("edid hash %s ignored: %s", edid_md5, error->message); g_error_free (error); goto out; } /* get the CdDevice for this ID */ helper = g_new0 (GcmSessionAsyncHelper, 1); helper->manager = g_object_ref (manager); helper->profile = g_object_ref (profile); device_id = gcm_session_get_output_id (manager, output); cd_client_find_device (manager->priv->client, device_id, NULL, gcm_session_profile_assign_find_device_cb, helper); out: g_free (device_id); if (metadata != NULL) g_hash_table_unref (metadata); } static void gcm_session_profile_added_assign_cb (CdClient *client, CdProfile *profile, CsdColorManager *manager) { cd_profile_connect (profile, NULL, gcm_session_profile_assign_profile_connect_cb, manager); } static cmsBool _cmsWriteTagTextAscii (cmsHPROFILE lcms_profile, cmsTagSignature sig, const gchar *text) { cmsBool ret; cmsMLU *mlu = cmsMLUalloc (0, 1); cmsMLUsetASCII (mlu, "EN", "us", text); ret = cmsWriteTag (lcms_profile, sig, mlu); cmsMLUfree (mlu); return ret; } static gboolean gcm_utils_mkdir_for_filename (const gchar *filename, GError **error) { gboolean ret = FALSE; GFile *file; GFile *parent_dir = NULL; /* get parent directory */ file = g_file_new_for_path (filename); parent_dir = g_file_get_parent (file); if (parent_dir == NULL) { g_set_error (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "could not get parent dir %s", filename); goto out; } /* ensure desination does not already exist */ ret = g_file_query_exists (parent_dir, NULL); if (ret) goto out; ret = g_file_make_directory_with_parents (parent_dir, NULL, error); if (!ret) goto out; out: if (file != NULL) g_object_unref (file); if (parent_dir != NULL) g_object_unref (parent_dir); return ret; } #ifdef HAVE_NEW_LCMS static wchar_t * utf8_to_wchar_t (const char *src) { size_t len; size_t converted; wchar_t *buf = NULL; len = mbstowcs (NULL, src, 0); if (len == (size_t) -1) { g_warning ("Invalid UTF-8 in string %s", src); goto out; } len += 1; buf = g_malloc (sizeof (wchar_t) * len); converted = mbstowcs (buf, src, len - 1); g_assert (converted != -1); buf[converted] = '\0'; out: return buf; } static cmsBool _cmsDictAddEntryAscii (cmsHANDLE dict, const gchar *key, const gchar *value) { cmsBool ret = FALSE; wchar_t *mb_key = NULL; wchar_t *mb_value = NULL; mb_key = utf8_to_wchar_t (key); if (mb_key == NULL) goto out; mb_value = utf8_to_wchar_t (value); if (mb_value == NULL) goto out; ret = cmsDictAddEntry (dict, mb_key, mb_value, NULL, NULL); out: g_free (mb_key); g_free (mb_value); return ret; } #endif /* HAVE_NEW_LCMS */ static gboolean gcm_apply_create_icc_profile_for_edid (CsdColorManager *manager, GcmEdid *edid, const gchar *filename, GError **error) { const CdColorYxy *tmp; cmsCIExyYTRIPLE chroma; cmsCIExyY white_point; cmsHPROFILE lcms_profile = NULL; cmsToneCurve *transfer_curve[3] = { NULL, NULL, NULL }; const gchar *data; gboolean ret = FALSE; gchar *str; gfloat edid_gamma; gfloat localgamma; #ifdef HAVE_NEW_LCMS cmsHANDLE dict = NULL; #endif CsdColorManagerPrivate *priv = manager->priv; /* ensure the per-user directory exists */ ret = gcm_utils_mkdir_for_filename (filename, error); if (!ret) goto out; /* copy color data from our structures */ tmp = gcm_edid_get_red (edid); chroma.Red.x = tmp->x; chroma.Red.y = tmp->y; tmp = gcm_edid_get_green (edid); chroma.Green.x = tmp->x; chroma.Green.y = tmp->y; tmp = gcm_edid_get_blue (edid); chroma.Blue.x = tmp->x; chroma.Blue.y = tmp->y; tmp = gcm_edid_get_white (edid); white_point.x = tmp->x; white_point.y = tmp->y; white_point.Y = 1.0; /* estimate the transfer function for the gamma */ localgamma = gcm_edid_get_gamma (edid); transfer_curve[0] = transfer_curve[1] = transfer_curve[2] = cmsBuildGamma (NULL, localgamma); /* create our generated profile */ lcms_profile = cmsCreateRGBProfile (&white_point, &chroma, transfer_curve); if (lcms_profile == NULL) { g_set_error (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to create profile"); goto out; } cmsSetColorSpace (lcms_profile, cmsSigRgbData); cmsSetPCS (lcms_profile, cmsSigXYZData); cmsSetHeaderRenderingIntent (lcms_profile, INTENT_PERCEPTUAL); cmsSetDeviceClass (lcms_profile, cmsSigDisplayClass); /* copyright */ ret = _cmsWriteTagTextAscii (lcms_profile, cmsSigCopyrightTag, /* deliberately not translated */ "This profile is free of known copyright restrictions."); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write copyright"); goto out; } /* set model */ data = gcm_edid_get_monitor_name (edid); if (data == NULL) data = gcm_dmi_get_name (priv->dmi); if (data == NULL) data = "Unknown monitor"; ret = _cmsWriteTagTextAscii (lcms_profile, cmsSigDeviceModelDescTag, data); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write model"); goto out; } /* write title */ ret = _cmsWriteTagTextAscii (lcms_profile, cmsSigProfileDescriptionTag, data); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write description"); goto out; } /* get manufacturer */ data = gcm_edid_get_vendor_name (edid); if (data == NULL) data = gcm_dmi_get_vendor (priv->dmi); if (data == NULL) data = "Unknown vendor"; ret = _cmsWriteTagTextAscii (lcms_profile, cmsSigDeviceMfgDescTag, data); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write manufacturer"); goto out; } #ifdef HAVE_NEW_LCMS /* just create a new dict */ dict = cmsDictAlloc (NULL); /* set the framework creator metadata */ _cmsDictAddEntryAscii (dict, CD_PROFILE_METADATA_CMF_PRODUCT, PACKAGE_NAME); _cmsDictAddEntryAscii (dict, CD_PROFILE_METADATA_CMF_BINARY, PACKAGE_NAME); _cmsDictAddEntryAscii (dict, CD_PROFILE_METADATA_CMF_VERSION, PACKAGE_VERSION); /* set the data source so we don't ever prompt the user to * recalibrate (as the EDID data won't have changed) */ _cmsDictAddEntryAscii (dict, CD_PROFILE_METADATA_DATA_SOURCE, CD_PROFILE_METADATA_DATA_SOURCE_EDID); /* set 'ICC meta Tag for Monitor Profiles' data */ _cmsDictAddEntryAscii (dict, "EDID_md5", gcm_edid_get_checksum (edid)); data = gcm_edid_get_monitor_name (edid); if (data != NULL) _cmsDictAddEntryAscii (dict, "EDID_model", data); data = gcm_edid_get_serial_number (edid); if (data != NULL) _cmsDictAddEntryAscii (dict, "EDID_serial", data); data = gcm_edid_get_pnp_id (edid); if (data != NULL) _cmsDictAddEntryAscii (dict, "EDID_mnft", data); data = gcm_edid_get_vendor_name (edid); if (data != NULL) _cmsDictAddEntryAscii (dict, "EDID_manufacturer", data); edid_gamma = gcm_edid_get_gamma (edid); if (edid_gamma > 0.0 && edid_gamma < 10.0) { str = g_strdup_printf ("%f", edid_gamma); _cmsDictAddEntryAscii (dict, "EDID_gamma", str); g_free (str); } /* also add the primaries */ str = g_strdup_printf ("%f", chroma.Red.x); _cmsDictAddEntryAscii (dict, "EDID_red_x", str); g_free (str); str = g_strdup_printf ("%f", chroma.Red.y); _cmsDictAddEntryAscii (dict, "EDID_red_y", str); g_free (str); str = g_strdup_printf ("%f", chroma.Green.x); _cmsDictAddEntryAscii (dict, "EDID_green_x", str); g_free (str); str = g_strdup_printf ("%f", chroma.Green.y); _cmsDictAddEntryAscii (dict, "EDID_green_y", str); g_free (str); str = g_strdup_printf ("%f", chroma.Blue.x); _cmsDictAddEntryAscii (dict, "EDID_blue_x", str); g_free (str); str = g_strdup_printf ("%f", chroma.Blue.y); _cmsDictAddEntryAscii (dict, "EDID_blue_y", str); g_free (str); /* write new tag */ ret = cmsWriteTag (lcms_profile, cmsSigMetaTag, dict); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write profile metadata"); goto out; } #endif /* HAVE_NEW_LCMS */ /* write profile id */ ret = cmsMD5computeID (lcms_profile); if (!ret) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to write profile id"); goto out; } /* save, TODO: get error */ cmsSaveProfileToFile (lcms_profile, filename); ret = TRUE; out: #ifdef HAVE_NEW_LCMS if (dict != NULL) cmsDictFree (dict); #endif if (*transfer_curve != NULL) cmsFreeToneCurve (*transfer_curve); return ret; } static GPtrArray * gcm_session_generate_vcgt (CdProfile *profile, guint size) { GnomeRROutputClutItem *tmp; GPtrArray *array = NULL; const cmsToneCurve **vcgt; cmsFloat32Number in; guint i; const gchar *filename; cmsHPROFILE lcms_profile = NULL; /* invalid size */ if (size == 0) goto out; /* not an actual profile */ filename = cd_profile_get_filename (profile); if (filename == NULL) goto out; /* open file */ lcms_profile = cmsOpenProfileFromFile (filename, "r"); if (lcms_profile == NULL) goto out; /* get tone curves from profile */ vcgt = cmsReadTag (lcms_profile, cmsSigVcgtTag); if (vcgt == NULL || vcgt[0] == NULL) { g_debug ("profile does not have any VCGT data"); goto out; } /* create array */ array = g_ptr_array_new_with_free_func (g_free); for (i = 0; i < size; i++) { in = (gdouble) i / (gdouble) (size - 1); tmp = g_new0 (GnomeRROutputClutItem, 1); tmp->red = cmsEvalToneCurveFloat(vcgt[0], in) * (gdouble) 0xffff; tmp->green = cmsEvalToneCurveFloat(vcgt[1], in) * (gdouble) 0xffff; tmp->blue = cmsEvalToneCurveFloat(vcgt[2], in) * (gdouble) 0xffff; g_ptr_array_add (array, tmp); } out: if (lcms_profile != NULL) cmsCloseProfile (lcms_profile); return array; } static guint cinnamon_rr_output_get_gamma_size (GnomeRROutput *output) { GnomeRRCrtc *crtc; gint len = 0; crtc = gnome_rr_output_get_crtc (output); if (crtc == NULL) return 0; gnome_rr_crtc_get_gamma (crtc, &len, NULL, NULL, NULL); return (guint) len; } static gboolean gcm_session_output_set_gamma (GnomeRROutput *output, GPtrArray *array, GError **error) { gboolean ret = TRUE; guint16 *red = NULL; guint16 *green = NULL; guint16 *blue = NULL; guint i; GnomeRROutputClutItem *data; GnomeRRCrtc *crtc; /* no length? */ if (array->len == 0) { ret = FALSE; g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "no data in the CLUT array"); goto out; } /* convert to a type X understands */ red = g_new (guint16, array->len); green = g_new (guint16, array->len); blue = g_new (guint16, array->len); for (i = 0; i < array->len; i++) { data = g_ptr_array_index (array, i); red[i] = data->red; green[i] = data->green; blue[i] = data->blue; } /* send to LUT */ crtc = gnome_rr_output_get_crtc (output); if (crtc == NULL) { ret = FALSE; g_set_error (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to get ctrc for %s", gnome_rr_output_get_name (output)); goto out; } gnome_rr_crtc_set_gamma (crtc, array->len, red, green, blue); out: g_free (red); g_free (green); g_free (blue); return ret; } static gboolean gcm_session_device_set_gamma (GnomeRROutput *output, CdProfile *profile, GError **error) { gboolean ret = FALSE; guint size; GPtrArray *clut = NULL; /* create a lookup table */ size = cinnamon_rr_output_get_gamma_size (output); if (size == 0) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "gamma size is zero"); goto out; } clut = gcm_session_generate_vcgt (profile, size); if (clut == NULL) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to generate vcgt"); goto out; } /* apply the vcgt to this output */ ret = gcm_session_output_set_gamma (output, clut, error); if (!ret) goto out; out: if (clut != NULL) g_ptr_array_unref (clut); return ret; } static gboolean gcm_session_device_reset_gamma (GnomeRROutput *output, GError **error) { gboolean ret; guint i; guint size; guint32 value; GPtrArray *clut; GnomeRROutputClutItem *data; /* create a linear ramp */ g_debug ("falling back to dummy ramp"); clut = g_ptr_array_new_with_free_func (g_free); size = cinnamon_rr_output_get_gamma_size (output); if (size == 0) { ret = FALSE; g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "gamma size is zero"); goto out; } for (i = 0; i < size; i++) { value = (i * 0xffff) / (size - 1); data = g_new0 (GnomeRROutputClutItem, 1); data->red = value; data->green = value; data->blue = value; g_ptr_array_add (clut, data); } /* apply the vcgt to this output */ ret = gcm_session_output_set_gamma (output, clut, error); if (!ret) goto out; out: g_ptr_array_unref (clut); return ret; } static GnomeRROutput * gcm_session_get_x11_output_by_id (CsdColorManager *manager, const gchar *device_id, GError **error) { gchar *output_id; GnomeRROutput *output = NULL; GnomeRROutput **outputs = NULL; guint i; CsdColorManagerPrivate *priv = manager->priv; /* search all X11 outputs for the device id */ outputs = gnome_rr_screen_list_outputs (priv->x11_screen); if (outputs == NULL) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "Failed to get outputs"); goto out; } for (i = 0; outputs[i] != NULL && output == NULL; i++) { if (!gnome_rr_output_is_connected (outputs[i])) continue; output_id = gcm_session_get_output_id (manager, outputs[i]); if (g_strcmp0 (output_id, device_id) == 0) output = outputs[i]; g_free (output_id); } if (output == NULL) { g_set_error (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "Failed to find output %s", device_id); } out: return output; } /* this function is more complicated than it should be, due to the * fact that XOrg sometimes assigns no primary devices when using * "xrandr --auto" or when the version of RANDR is < 1.3 */ static gboolean gcm_session_use_output_profile_for_screen (CsdColorManager *manager, GnomeRROutput *output) { gboolean has_laptop = FALSE; gboolean has_primary = FALSE; GnomeRROutput **outputs; GnomeRROutput *connected = NULL; guint i; /* do we have any screens marked as primary */ outputs = gnome_rr_screen_list_outputs (manager->priv->x11_screen); if (outputs == NULL || outputs[0] == NULL) { g_warning ("failed to get outputs"); return FALSE; } for (i = 0; outputs[i] != NULL; i++) { if (!gnome_rr_output_is_connected (outputs[i])) continue; if (connected == NULL) connected = outputs[i]; if (gnome_rr_output_get_is_primary (outputs[i])) has_primary = TRUE; if (gnome_rr_output_is_laptop (outputs[i])) has_laptop = TRUE; } /* we have an assigned primary device, are we that? */ if (has_primary) return gnome_rr_output_get_is_primary (output); /* choosing the internal panel is probably sane */ if (has_laptop) return gnome_rr_output_is_laptop (output); /* we have to choose one, so go for the first connected device */ if (connected != NULL) return gnome_rr_output_get_id (connected) == gnome_rr_output_get_id (output); return FALSE; } /* TODO: remove when we can dep on a released version of colord */ #ifndef CD_PROFILE_METADATA_SCREEN_BRIGHTNESS #define CD_PROFILE_METADATA_SCREEN_BRIGHTNESS "SCREEN_brightness" #endif #define CSD_DBUS_SERVICE "org.cinnamon.SettingsDaemon" #define CSD_DBUS_INTERFACE_POWER_SCREEN "org.cinnamon.SettingsDaemon.Power.Screen" #define CSD_DBUS_PATH_POWER "/org/cinnamon/SettingsDaemon/Power" static void gcm_session_set_output_percentage_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GDBusConnection *connection = G_DBUS_CONNECTION (source_object); GError *error = NULL; GVariant *retval; retval = g_dbus_connection_call_finish (connection, res, &error); if (retval == NULL) { g_warning ("failed to set output brightness: %s", error->message); g_error_free (error); return; } g_variant_unref (retval); } static void gcm_session_set_output_percentage (guint percentage) { GDBusConnection *connection; /* get a ref to the existing bus connection */ connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); if (connection == NULL) return; g_dbus_connection_call (connection, CSD_DBUS_SERVICE, CSD_DBUS_PATH_POWER, CSD_DBUS_INTERFACE_POWER_SCREEN, "SetPercentage", g_variant_new ("(u)", percentage), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, gcm_session_set_output_percentage_cb, NULL); g_object_unref (connection); } static void gcm_session_device_assign_profile_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdProfile *profile = CD_PROFILE (object); const gchar *brightness_profile; const gchar *filename; gboolean ret; GError *error = NULL; GnomeRROutput *output; guint brightness_percentage; GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data; CsdColorManager *manager = CSD_COLOR_MANAGER (helper->manager); /* get properties */ ret = cd_profile_connect_finish (profile, res, &error); if (!ret) { g_warning ("failed to connect to profile: %s", error->message); g_error_free (error); goto out; } /* get the filename */ filename = cd_profile_get_filename (profile); g_assert (filename != NULL); /* get the output (can't save in helper as GnomeRROutput isn't * a GObject, just a pointer */ output = gnome_rr_screen_get_output_by_id (manager->priv->x11_screen, helper->output_id); if (output == NULL) goto out; /* if output is a laptop screen and the profile has a * calibration brightness then set this new brightness */ brightness_profile = cd_profile_get_metadata_item (profile, CD_PROFILE_METADATA_SCREEN_BRIGHTNESS); if (gnome_rr_output_is_laptop (output) && brightness_profile != NULL) { /* the percentage is stored in the profile metadata as * a string, not ideal, but it's all we have... */ brightness_percentage = atoi (brightness_profile); gcm_session_set_output_percentage (brightness_percentage); } /* set the _ICC_PROFILE atom */ ret = gcm_session_use_output_profile_for_screen (manager, output); if (ret) { ret = gcm_session_screen_set_icc_profile (manager, filename, &error); if (!ret) { g_warning ("failed to set screen _ICC_PROFILE: %s", error->message); g_clear_error (&error); } } /* create a vcgt for this icc file */ ret = cd_profile_get_has_vcgt (profile); if (ret) { ret = gcm_session_device_set_gamma (output, profile, &error); if (!ret) { g_warning ("failed to set %s gamma tables: %s", cd_device_get_id (helper->device), error->message); g_error_free (error); goto out; } } else { ret = gcm_session_device_reset_gamma (output, &error); if (!ret) { g_warning ("failed to reset %s gamma tables: %s", cd_device_get_id (helper->device), error->message); g_error_free (error); goto out; } } out: gcm_session_async_helper_free (helper); } static void gcm_session_device_assign_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDeviceKind kind; CdProfile *profile = NULL; gboolean ret; gchar *autogen_filename = NULL; gchar *autogen_path = NULL; GcmEdid *edid = NULL; GnomeRROutput *output = NULL; GError *error = NULL; const gchar *xrandr_id; GcmSessionAsyncHelper *helper; CdDevice *device = CD_DEVICE (object); CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); CsdColorManagerPrivate *priv = manager->priv; /* remove from assign array */ g_hash_table_remove (manager->priv->device_assign_hash, cd_device_get_object_path (device)); /* get properties */ ret = cd_device_connect_finish (device, res, &error); if (!ret) { g_warning ("failed to connect to device: %s", error->message); g_error_free (error); goto out; } /* check we care */ kind = cd_device_get_kind (device); if (kind != CD_DEVICE_KIND_DISPLAY) goto out; g_debug ("need to assign display device %s", cd_device_get_id (device)); /* get the GnomeRROutput for the device id */ xrandr_id = cd_device_get_id (device); output = gcm_session_get_x11_output_by_id (manager, xrandr_id, &error); if (output == NULL) { g_warning ("no %s device found: %s", cd_device_get_id (device), error->message); g_error_free (error); goto out; } /* create profile from device edid if it exists */ edid = gcm_session_get_output_edid (manager, output, &error); if (edid == NULL) { g_warning ("unable to get EDID for %s: %s", cd_device_get_id (device), error->message); g_clear_error (&error); } else { autogen_filename = g_strdup_printf ("edid-%s.icc", gcm_edid_get_checksum (edid)); autogen_path = g_build_filename (g_get_user_data_dir (), "icc", autogen_filename, NULL); if (g_file_test (autogen_path, G_FILE_TEST_EXISTS)) { g_debug ("auto-profile edid %s exists", autogen_path); } else { g_debug ("auto-profile edid does not exist, creating as %s", autogen_path); ret = gcm_apply_create_icc_profile_for_edid (manager, edid, autogen_path, &error); if (!ret) { g_warning ("failed to create profile from EDID data: %s", error->message); g_clear_error (&error); } } } /* get the default profile for the device */ profile = cd_device_get_default_profile (device); if (profile == NULL) { g_debug ("%s has no default profile to set", cd_device_get_id (device)); /* the default output? */ if (gnome_rr_output_get_is_primary (output)) { gdk_property_delete (priv->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE")); gdk_property_delete (priv->gdk_window, gdk_atom_intern_static_string ("_ICC_PROFILE_IN_X_VERSION")); } /* reset, as we want linear profiles for profiling */ ret = gcm_session_device_reset_gamma (output, &error); if (!ret) { g_warning ("failed to reset %s gamma tables: %s", cd_device_get_id (device), error->message); g_error_free (error); goto out; } goto out; } /* get properties */ helper = g_new0 (GcmSessionAsyncHelper, 1); helper->output_id = gnome_rr_output_get_id (output); helper->manager = g_object_ref (manager); helper->device = g_object_ref (device); cd_profile_connect (profile, NULL, gcm_session_device_assign_profile_connect_cb, helper); out: g_free (autogen_filename); g_free (autogen_path); if (edid != NULL) g_object_unref (edid); if (profile != NULL) g_object_unref (profile); } static void gcm_session_device_assign (CsdColorManager *manager, CdDevice *device) { const gchar *key; gpointer found; /* are we already assigning this device */ key = cd_device_get_object_path (device); found = g_hash_table_lookup (manager->priv->device_assign_hash, key); if (found != NULL) { g_debug ("assign for %s already in progress", key); return; } g_hash_table_insert (manager->priv->device_assign_hash, g_strdup (key), GINT_TO_POINTER (TRUE)); cd_device_connect (device, NULL, gcm_session_device_assign_connect_cb, manager); } static void gcm_session_device_added_assign_cb (CdClient *client, CdDevice *device, CsdColorManager *manager) { gcm_session_device_assign (manager, device); } static void gcm_session_device_changed_assign_cb (CdClient *client, CdDevice *device, CsdColorManager *manager) { g_debug ("%s changed", cd_device_get_object_path (device)); gcm_session_device_assign (manager, device); } static void gcm_session_create_device_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDevice *device; GError *error = NULL; device = cd_client_create_device_finish (CD_CLIENT (object), res, &error); if (device == NULL) { if (error->domain != CD_CLIENT_ERROR || error->code != CD_CLIENT_ERROR_ALREADY_EXISTS) { g_warning ("failed to create device: %s", error->message); } g_error_free (error); return; } g_object_unref (device); } static void gcm_session_add_x11_output (CsdColorManager *manager, GnomeRROutput *output) { const gchar *model = NULL; const gchar *serial = NULL; const gchar *vendor = NULL; gboolean ret; gchar *device_id = NULL; GcmEdid *edid; GError *error = NULL; GHashTable *device_props = NULL; CsdColorManagerPrivate *priv = manager->priv; /* try to get edid */ edid = gcm_session_get_output_edid (manager, output, &error); if (edid == NULL) { g_warning ("failed to get edid: %s", error->message); g_clear_error (&error); } /* prefer DMI data for the internal output */ ret = gnome_rr_output_is_laptop (output); if (ret) { model = gcm_dmi_get_name (priv->dmi); vendor = gcm_dmi_get_vendor (priv->dmi); } /* use EDID data if we have it */ if (edid != NULL) { if (model == NULL) model = gcm_edid_get_monitor_name (edid); if (vendor == NULL) vendor = gcm_edid_get_vendor_name (edid); if (serial == NULL) serial = gcm_edid_get_serial_number (edid); } /* ensure mandatory fields are set */ if (model == NULL) model = gnome_rr_output_get_name (output); if (vendor == NULL) vendor = "unknown"; if (serial == NULL) serial = "unknown"; device_id = gcm_session_get_output_id (manager, output); g_debug ("output %s added", device_id); device_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_KIND, (gpointer) cd_device_kind_to_string (CD_DEVICE_KIND_DISPLAY)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_MODE, (gpointer) cd_device_mode_to_string (CD_DEVICE_MODE_PHYSICAL)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_COLORSPACE, (gpointer) cd_colorspace_to_string (CD_COLORSPACE_RGB)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_VENDOR, (gpointer) vendor); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_MODEL, (gpointer) model); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_SERIAL, (gpointer) serial); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_METADATA_XRANDR_NAME, (gpointer) gnome_rr_output_get_name (output)); g_hash_table_insert (device_props, (gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY, gnome_rr_output_get_is_primary (output) ? (gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY_PRIMARY : (gpointer) CD_DEVICE_METADATA_OUTPUT_PRIORITY_SECONDARY); /* set this so we can call the device a 'Laptop Screen' in the * control center main panel */ if (gnome_rr_output_is_laptop (output)) { g_hash_table_insert (device_props, (gpointer) CD_DEVICE_PROPERTY_EMBEDDED, NULL); } cd_client_create_device (priv->client, device_id, CD_OBJECT_SCOPE_TEMP, device_props, NULL, gcm_session_create_device_cb, manager); g_free (device_id); if (device_props != NULL) g_hash_table_unref (device_props); if (edid != NULL) g_object_unref (edid); } static void cinnamon_rr_screen_output_added_cb (GnomeRRScreen *screen, GnomeRROutput *output, CsdColorManager *manager) { gcm_session_add_x11_output (manager, output); } static void gcm_session_screen_removed_delete_device_cb (GObject *object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; /* deleted device */ ret = cd_client_delete_device_finish (CD_CLIENT (object), res, &error); if (!ret) { g_warning ("failed to delete device: %s", error->message); g_error_free (error); } } static void gcm_session_screen_removed_find_device_cb (GObject *object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CdDevice *device; CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); device = cd_client_find_device_finish (manager->priv->client, res, &error); if (device == NULL) { g_warning ("failed to find device: %s", error->message); g_error_free (error); return; } g_debug ("output %s found, and will be removed", cd_device_get_object_path (device)); cd_client_delete_device (manager->priv->client, device, NULL, gcm_session_screen_removed_delete_device_cb, manager); g_object_unref (device); } static void cinnamon_rr_screen_output_removed_cb (GnomeRRScreen *screen, GnomeRROutput *output, CsdColorManager *manager) { g_debug ("output %s removed", gnome_rr_output_get_name (output)); g_hash_table_remove (manager->priv->edid_cache, gnome_rr_output_get_name (output)); cd_client_find_device_by_property (manager->priv->client, CD_DEVICE_METADATA_XRANDR_NAME, gnome_rr_output_get_name (output), NULL, gcm_session_screen_removed_find_device_cb, manager); } static void gcm_session_get_devices_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdDevice *device; GError *error = NULL; GPtrArray *array; guint i; CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); array = cd_client_get_devices_finish (CD_CLIENT (object), res, &error); if (array == NULL) { g_warning ("failed to get devices: %s", error->message); g_error_free (error); goto out; } for (i = 0; i < array->len; i++) { device = g_ptr_array_index (array, i); gcm_session_device_assign (manager, device); } out: if (array != NULL) g_ptr_array_unref (array); } static void gcm_session_profile_gamma_find_device_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdClient *client = CD_CLIENT (object); CdDevice *device = NULL; GError *error = NULL; CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); device = cd_client_find_device_by_property_finish (client, res, &error); if (device == NULL) { g_warning ("could not find device: %s", error->message); g_error_free (error); goto out; } /* get properties */ cd_device_connect (device, NULL, gcm_session_device_assign_connect_cb, manager); out: if (device != NULL) g_object_unref (device); } /* We have to reset the gamma tables each time as if the primary output * has changed then different crtcs are going to be used. * See https://bugzilla.gnome.org/show_bug.cgi?id=660164 for an example */ static void cinnamon_rr_screen_output_changed_cb (GnomeRRScreen *screen, CsdColorManager *manager) { GnomeRROutput **outputs; CsdColorManagerPrivate *priv = manager->priv; guint i; /* get X11 outputs */ outputs = gnome_rr_screen_list_outputs (priv->x11_screen); if (outputs == NULL) { g_warning ("failed to get outputs"); return; } for (i = 0; outputs[i] != NULL; i++) { if (!gnome_rr_output_is_connected (outputs[i])) continue; /* get CdDevice for this output */ cd_client_find_device_by_property (manager->priv->client, CD_DEVICE_METADATA_XRANDR_NAME, gnome_rr_output_get_name (outputs[i]), NULL, gcm_session_profile_gamma_find_device_cb, manager); } } static void gcm_session_client_connect_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; GnomeRROutput **outputs; guint i; CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); CsdColorManagerPrivate *priv = manager->priv; /* connected */ g_debug ("connected to colord"); ret = cd_client_connect_finish (manager->priv->client, res, &error); if (!ret) { g_warning ("failed to connect to colord: %s", error->message); g_error_free (error); return; } /* is there an available colord instance? */ ret = cd_client_get_has_server (manager->priv->client); if (!ret) { g_warning ("There is no colord server available"); goto out; } /* add profiles */ gcm_profile_store_search (priv->profile_store); /* add screens */ gnome_rr_screen_refresh (priv->x11_screen, &error); if (error != NULL) { g_warning ("failed to refresh: %s", error->message); g_error_free (error); goto out; } /* get X11 outputs */ outputs = gnome_rr_screen_list_outputs (priv->x11_screen); if (outputs == NULL) { g_warning ("failed to get outputs"); goto out; } for (i = 0; outputs[i] != NULL; i++) { if (gnome_rr_output_is_connected (outputs[i])) gcm_session_add_x11_output (manager, outputs[i]); } /* only connect when colord is awake */ g_signal_connect (priv->x11_screen, "output-connected", G_CALLBACK (cinnamon_rr_screen_output_added_cb), manager); g_signal_connect (priv->x11_screen, "output-disconnected", G_CALLBACK (cinnamon_rr_screen_output_removed_cb), manager); g_signal_connect (priv->x11_screen, "changed", G_CALLBACK (cinnamon_rr_screen_output_changed_cb), manager); g_signal_connect (priv->client, "profile-added", G_CALLBACK (gcm_session_profile_added_assign_cb), manager); g_signal_connect (priv->client, "device-added", G_CALLBACK (gcm_session_device_added_assign_cb), manager); g_signal_connect (priv->client, "device-changed", G_CALLBACK (gcm_session_device_changed_assign_cb), manager); /* set for each device that already exist */ cd_client_get_devices (priv->client, NULL, gcm_session_get_devices_cb, manager); out: return; } gboolean csd_color_manager_start (CsdColorManager *manager, GError **error) { CsdColorManagerPrivate *priv = manager->priv; gboolean ret = FALSE; g_debug ("Starting color manager"); cinnamon_settings_profile_start (NULL); /* coldplug the list of screens */ priv->x11_screen = gnome_rr_screen_new (gdk_screen_get_default (), error); if (priv->x11_screen == NULL) goto out; cd_client_connect (priv->client, NULL, gcm_session_client_connect_cb, manager); /* success */ ret = TRUE; out: cinnamon_settings_profile_end (NULL); return ret; } void csd_color_manager_stop (CsdColorManager *manager) { g_debug ("Stopping color manager"); g_return_if_fail (manager->priv != NULL); if (manager->priv->settings != NULL) { g_object_unref (manager->priv->settings); manager->priv->settings = NULL; } if (manager->priv->client != NULL) { g_object_unref (manager->priv->client); manager->priv->client = NULL; } if (manager->priv->profile_store != NULL) { g_object_unref (manager->priv->profile_store); manager->priv->profile_store = NULL; } if (manager->priv->dmi != NULL) { g_object_unref (manager->priv->dmi); manager->priv->dmi = NULL; } if (manager->priv->session != NULL) { g_object_unref (manager->priv->session); manager->priv->session = NULL; } if (manager->priv->edid_cache != NULL) { g_hash_table_destroy (manager->priv->edid_cache); manager->priv->edid_cache = NULL; } if (manager->priv->device_assign_hash != NULL) { g_hash_table_destroy (manager->priv->device_assign_hash); manager->priv->device_assign_hash = NULL; } if (manager->priv->x11_screen != NULL) g_object_unref (manager->priv->x11_screen); manager->priv->x11_screen = NULL; } static void gcm_session_exec_control_center (CsdColorManager *manager) { gboolean ret; GError *error = NULL; GAppInfo *app_info; GdkAppLaunchContext *launch_context; /* setup the launch context so the startup notification is correct */ launch_context = gdk_display_get_app_launch_context (gdk_display_get_default ()); app_info = g_app_info_create_from_commandline (BINDIR "/cinnamon-settings color", "cinnamon-settings", G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION, &error); if (app_info == NULL) { g_warning ("failed to create application info: %s", error->message); g_error_free (error); goto out; } /* launch cinnamon-settings */ ret = g_app_info_launch (app_info, NULL, G_APP_LAUNCH_CONTEXT (launch_context), &error); if (!ret) { g_warning ("failed to launch cinnamon-settings: %s", error->message); g_error_free (error); goto out; } out: g_object_unref (launch_context); if (app_info != NULL) g_object_unref (app_info); } static void gcm_session_notify_cb (NotifyNotification *notification, gchar *action, gpointer user_data) { CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); if (g_strcmp0 (action, "recalibrate") == 0) { notify_notification_close (notification, NULL); gcm_session_exec_control_center (manager); } } static void closed_cb (NotifyNotification *notification, gpointer data) { g_object_unref (notification); } static gboolean gcm_session_notify_recalibrate (CsdColorManager *manager, const gchar *title, const gchar *message, CdDeviceKind kind) { gboolean ret; GError *error = NULL; NotifyNotification *notification; CsdColorManagerPrivate *priv = manager->priv; /* show a bubble */ notification = notify_notification_new (title, message, "preferences-color"); notify_notification_set_timeout (notification, GCM_SESSION_NOTIFY_TIMEOUT); notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW); notify_notification_set_app_name (notification, _("Color")); /* TRANSLATORS: button: this is to open GCM */ notify_notification_add_action (notification, "recalibrate", _("Recalibrate now"), gcm_session_notify_cb, priv, NULL); g_signal_connect (notification, "closed", G_CALLBACK (closed_cb), NULL); ret = notify_notification_show (notification, &error); if (!ret) { g_warning ("failed to show notification: %s", error->message); g_error_free (error); } return ret; } static gchar * gcm_session_device_get_title (CdDevice *device) { const gchar *vendor; const gchar *model; model = cd_device_get_model (device); vendor = cd_device_get_vendor (device); if (model != NULL && vendor != NULL) return g_strdup_printf ("%s - %s", vendor, model); if (vendor != NULL) return g_strdup (vendor); if (model != NULL) return g_strdup (model); return g_strdup (cd_device_get_id (device)); } static void gcm_session_notify_device (CsdColorManager *manager, CdDevice *device) { CdDeviceKind kind; const gchar *title; gchar *device_title = NULL; gchar *message; guint threshold; glong since; CsdColorManagerPrivate *priv = manager->priv; /* TRANSLATORS: this is when the device has not been recalibrated in a while */ title = _("Recalibration required"); device_title = gcm_session_device_get_title (device); /* check we care */ kind = cd_device_get_kind (device); if (kind == CD_DEVICE_KIND_DISPLAY) { /* get from GSettings */ threshold = g_settings_get_uint (priv->settings, GCM_SETTINGS_RECALIBRATE_DISPLAY_THRESHOLD); /* TRANSLATORS: this is when the display has not been recalibrated in a while */ message = g_strdup_printf (_("The display '%s' should be recalibrated soon."), device_title); } else { /* get from GSettings */ threshold = g_settings_get_uint (priv->settings, GCM_SETTINGS_RECALIBRATE_PRINTER_THRESHOLD); /* TRANSLATORS: this is when the printer has not been recalibrated in a while */ message = g_strdup_printf (_("The printer '%s' should be recalibrated soon."), device_title); } /* check if we need to notify */ since = (g_get_real_time () - cd_device_get_modified (device)) / G_USEC_PER_SEC; if (threshold > since) gcm_session_notify_recalibrate (manager, title, message, kind); g_free (device_title); g_free (message); } static void gcm_session_profile_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { const gchar *filename; gboolean ret; gchar *basename = NULL; const gchar *data_source; GError *error = NULL; CdProfile *profile = CD_PROFILE (object); GcmSessionAsyncHelper *helper = (GcmSessionAsyncHelper *) user_data; CsdColorManager *manager = CSD_COLOR_MANAGER (helper->manager); ret = cd_profile_connect_finish (profile, res, &error); if (!ret) { g_warning ("failed to connect to profile: %s", error->message); g_error_free (error); goto out; } /* ensure it's a profile generated by us */ data_source = cd_profile_get_metadata_item (profile, CD_PROFILE_METADATA_DATA_SOURCE); if (data_source == NULL) { /* existing profiles from gnome-color-manager < 3.1 * won't have the extra metadata values added */ filename = cd_profile_get_filename (profile); if (filename == NULL) goto out; basename = g_path_get_basename (filename); if (!g_str_has_prefix (basename, "GCM")) { g_debug ("not a GCM profile for %s: %s", cd_device_get_id (helper->device), filename); goto out; } /* ensure it's been created from a calibration, rather than from * auto-EDID */ } else if (g_strcmp0 (data_source, CD_PROFILE_METADATA_DATA_SOURCE_CALIB) != 0) { g_debug ("not a calib profile for %s", cd_device_get_id (helper->device)); goto out; } /* handle device */ gcm_session_notify_device (manager, helper->device); out: gcm_session_async_helper_free (helper); g_free (basename); } static void gcm_session_device_connect_cb (GObject *object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; CdDeviceKind kind; CdProfile *profile = NULL; CdDevice *device = CD_DEVICE (object); CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); GcmSessionAsyncHelper *helper; ret = cd_device_connect_finish (device, res, &error); if (!ret) { g_warning ("failed to connect to device: %s", error->message); g_error_free (error); goto out; } /* check we care */ kind = cd_device_get_kind (device); if (kind != CD_DEVICE_KIND_DISPLAY && kind != CD_DEVICE_KIND_PRINTER) goto out; /* ensure we have a profile */ profile = cd_device_get_default_profile (device); if (profile == NULL) { g_debug ("no profile set for %s", cd_device_get_id (device)); goto out; } /* connect to the profile */ helper = g_new0 (GcmSessionAsyncHelper, 1); helper->manager = g_object_ref (manager); helper->device = g_object_ref (device); cd_profile_connect (profile, NULL, gcm_session_profile_connect_cb, helper); out: if (profile != NULL) g_object_unref (profile); } static void gcm_session_device_added_notify_cb (CdClient *client, CdDevice *device, CsdColorManager *manager) { /* connect to the device to get properties */ cd_device_connect (device, NULL, gcm_session_device_connect_cb, manager); } static gchar * gcm_session_get_precooked_md5 (cmsHPROFILE lcms_profile) { cmsUInt8Number profile_id[16]; gboolean md5_precooked = FALSE; guint i; gchar *md5 = NULL; /* check to see if we have a pre-cooked MD5 */ cmsGetHeaderProfileID (lcms_profile, profile_id); for (i = 0; i < 16; i++) { if (profile_id[i] != 0) { md5_precooked = TRUE; break; } } if (!md5_precooked) goto out; /* convert to a hex string */ md5 = g_new0 (gchar, 32 + 1); for (i = 0; i < 16; i++) g_snprintf (md5 + i*2, 3, "%02x", profile_id[i]); out: return md5; } static gchar * gcm_session_get_md5_for_filename (const gchar *filename, GError **error) { gboolean ret; gchar *checksum = NULL; gchar *data = NULL; gsize length; cmsHPROFILE lcms_profile = NULL; /* get the internal profile id, if it exists */ lcms_profile = cmsOpenProfileFromFile (filename, "r"); if (lcms_profile == NULL) { g_set_error_literal (error, CSD_COLOR_MANAGER_ERROR, CSD_COLOR_MANAGER_ERROR_FAILED, "failed to load: not an ICC profile"); goto out; } checksum = gcm_session_get_precooked_md5 (lcms_profile); if (checksum != NULL) goto out; /* generate checksum */ ret = g_file_get_contents (filename, &data, &length, error); if (!ret) goto out; checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, (const guchar *) data, length); out: g_free (data); if (lcms_profile != NULL) cmsCloseProfile (lcms_profile); return checksum; } static void gcm_session_create_profile_cb (GObject *object, GAsyncResult *res, gpointer user_data) { CdProfile *profile; GError *error = NULL; CdClient *client = CD_CLIENT (object); profile = cd_client_create_profile_finish (client, res, &error); if (profile == NULL) { if (error->domain != CD_CLIENT_ERROR || error->code != CD_CLIENT_ERROR_ALREADY_EXISTS) g_warning ("%s", error->message); g_error_free (error); return; } g_object_unref (profile); } static void gcm_session_profile_store_added_cb (GcmProfileStore *profile_store, const gchar *filename, CsdColorManager *manager) { gchar *checksum = NULL; gchar *profile_id = NULL; GError *error = NULL; GHashTable *profile_props = NULL; CsdColorManagerPrivate *priv = manager->priv; g_debug ("profile %s added", filename); /* generate ID */ checksum = gcm_session_get_md5_for_filename (filename, &error); if (checksum == NULL) { g_debug ("failed to get profile checksum for %s: %s", filename, error->message); g_error_free (error); goto out; } profile_id = g_strdup_printf ("icc-%s", checksum); profile_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); g_hash_table_insert (profile_props, CD_PROFILE_PROPERTY_FILENAME, (gpointer) filename); g_hash_table_insert (profile_props, CD_PROFILE_METADATA_FILE_CHECKSUM, (gpointer) checksum); cd_client_create_profile (priv->client, profile_id, CD_OBJECT_SCOPE_TEMP, profile_props, NULL, gcm_session_create_profile_cb, manager); out: g_free (checksum); g_free (profile_id); if (profile_props != NULL) g_hash_table_unref (profile_props); } static void gcm_session_delete_profile_cb (GObject *object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; CdClient *client = CD_CLIENT (object); ret = cd_client_delete_profile_finish (client, res, &error); if (!ret) { g_warning ("%s", error->message); g_error_free (error); } } static void gcm_session_find_profile_by_filename_cb (GObject *object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CdProfile *profile; CdClient *client = CD_CLIENT (object); CsdColorManager *manager = CSD_COLOR_MANAGER (user_data); profile = cd_client_find_profile_by_filename_finish (client, res, &error); if (profile == NULL) { g_warning ("%s", error->message); g_error_free (error); goto out; } /* remove it from colord */ cd_client_delete_profile (manager->priv->client, profile, NULL, gcm_session_delete_profile_cb, manager); out: if (profile != NULL) g_object_unref (profile); } static void gcm_session_profile_store_removed_cb (GcmProfileStore *profile_store, const gchar *filename, CsdColorManager *manager) { /* find the ID for the filename */ g_debug ("filename %s removed", filename); cd_client_find_profile_by_filename (manager->priv->client, filename, NULL, gcm_session_find_profile_by_filename_cb, manager); } static void gcm_session_sensor_added_cb (CdClient *client, CdSensor *sensor, CsdColorManager *manager) { ca_context_play (ca_gtk_context_get (), 0, CA_PROP_EVENT_ID, "device-added", /* TRANSLATORS: this is the application name */ CA_PROP_APPLICATION_NAME, _("Cinnamon Settings Daemon Color Plugin"), /* TRANSLATORS: this is a sound description */ CA_PROP_EVENT_DESCRIPTION, _("Color calibration device added"), NULL); /* open up the color prefs window */ gcm_session_exec_control_center (manager); } static void gcm_session_sensor_removed_cb (CdClient *client, CdSensor *sensor, CsdColorManager *manager) { ca_context_play (ca_gtk_context_get (), 0, CA_PROP_EVENT_ID, "device-removed", /* TRANSLATORS: this is the application name */ CA_PROP_APPLICATION_NAME, _("Cinnamon Settings Daemon Color Plugin"), /* TRANSLATORS: this is a sound description */ CA_PROP_EVENT_DESCRIPTION, _("Color calibration device removed"), NULL); } static void gcm_session_active_changed_cb (CinnamonSettingsSession *session, GParamSpec *pspec, CsdColorManager *manager) { CinnamonSettingsSessionState state_new; CsdColorManagerPrivate *priv = manager->priv; /* not yet connected to the daemon */ if (!cd_client_get_connected (priv->client)) return; /* When doing the fast-user-switch into a new account, load the * new users chosen profiles. * * If this is the first time the CinnamonSettingsSession has been * loaded, then we'll get a change from unknown to active * and we want to avoid reprobing the devices for that. */ state_new = cinnamon_settings_session_get_state (session); if (priv->session_state != CINNAMON_SETTINGS_SESSION_STATE_UNKNOWN && state_new == CINNAMON_SETTINGS_SESSION_STATE_ACTIVE) { g_debug ("Done switch to new account, reload devices"); cd_client_get_devices (manager->priv->client, NULL, gcm_session_get_devices_cb, manager); } priv->session_state = state_new; } static void csd_color_manager_class_init (CsdColorManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_color_manager_finalize; g_type_class_add_private (klass, sizeof (CsdColorManagerPrivate)); } static void csd_color_manager_init (CsdColorManager *manager) { CsdColorManagerPrivate *priv; priv = manager->priv = CSD_COLOR_MANAGER_GET_PRIVATE (manager); /* track the active session */ priv->session = cinnamon_settings_session_new (); priv->session_state = cinnamon_settings_session_get_state (priv->session); g_signal_connect (priv->session, "notify::state", G_CALLBACK (gcm_session_active_changed_cb), manager); /* set the _ICC_PROFILE atoms on the root screen */ priv->gdk_window = gdk_screen_get_root_window (gdk_screen_get_default ()); /* parsing the EDID is expensive */ priv->edid_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); /* we don't want to assign devices multiple times at startup */ priv->device_assign_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /* use DMI data for internal panels */ priv->dmi = gcm_dmi_new (); priv->settings = g_settings_new ("org.cinnamon.settings-daemon.plugins.color"); priv->client = cd_client_new (); g_signal_connect (priv->client, "device-added", G_CALLBACK (gcm_session_device_added_notify_cb), manager); g_signal_connect (priv->client, "sensor-added", G_CALLBACK (gcm_session_sensor_added_cb), manager); g_signal_connect (priv->client, "sensor-removed", G_CALLBACK (gcm_session_sensor_removed_cb), manager); /* have access to all user profiles */ priv->profile_store = gcm_profile_store_new (); g_signal_connect (priv->profile_store, "added", G_CALLBACK (gcm_session_profile_store_added_cb), manager); g_signal_connect (priv->profile_store, "removed", G_CALLBACK (gcm_session_profile_store_removed_cb), manager); } static void csd_color_manager_finalize (GObject *object) { g_return_if_fail (object != NULL); G_OBJECT_CLASS (csd_color_manager_parent_class)->finalize (object); } CsdColorManager * csd_color_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_COLOR_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_COLOR_MANAGER (manager_object); } cinnamon-settings-daemon-2.8.3/plugins/color/gcm-profile-store.c0000664000175000017500000004534712625665665023712 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include "gcm-profile-store.h" static void gcm_profile_store_finalize (GObject *object); #define GCM_PROFILE_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCM_TYPE_PROFILE_STORE, GcmProfileStorePrivate)) struct _GcmProfileStorePrivate { GPtrArray *filename_array; GPtrArray *directory_array; GCancellable *cancellable; }; enum { SIGNAL_ADDED, SIGNAL_REMOVED, SIGNAL_CHANGED, SIGNAL_LAST }; static guint signals[SIGNAL_LAST] = { 0 }; G_DEFINE_TYPE (GcmProfileStore, gcm_profile_store, G_TYPE_OBJECT) static void gcm_profile_store_search_path (GcmProfileStore *profile_store, const gchar *path, guint depth); static void gcm_profile_store_process_child (GcmProfileStore *profile_store, const gchar *path, GFileInfo *info); #define GCM_PROFILE_STORE_MAX_RECURSION_LEVELS 2 typedef struct { gchar *path; GFileMonitor *monitor; guint depth; } GcmProfileStoreDirHelper; static void gcm_profile_store_helper_free (GcmProfileStoreDirHelper *helper) { g_free (helper->path); if (helper->monitor != NULL) g_object_unref (helper->monitor); g_free (helper); } static const gchar * gcm_profile_store_find_filename (GcmProfileStore *profile_store, const gchar *filename) { const gchar *tmp; guint i; GPtrArray *array = profile_store->priv->filename_array; for (i=0; ilen; i++) { tmp = g_ptr_array_index (array, i); if (g_strcmp0 (filename, tmp) == 0) return tmp; } return NULL; } static GcmProfileStoreDirHelper * gcm_profile_store_find_directory (GcmProfileStore *profile_store, const gchar *path) { GcmProfileStoreDirHelper *tmp; guint i; GPtrArray *array = profile_store->priv->directory_array; for (i=0; ilen; i++) { tmp = g_ptr_array_index (array, i); if (g_strcmp0 (path, tmp->path) == 0) return tmp; } return NULL; } static gboolean gcm_profile_store_remove_profile (GcmProfileStore *profile_store, const gchar *filename) { gboolean ret = FALSE; const gchar *tmp; gchar *filename_dup = NULL; GcmProfileStorePrivate *priv = profile_store->priv; /* find exact pointer */ tmp = gcm_profile_store_find_filename (profile_store, filename); if (tmp == NULL) goto out; /* dup so we can emit the signal */ filename_dup = g_strdup (tmp); ret = g_ptr_array_remove (priv->filename_array, (gpointer)tmp); if (!ret) { g_warning ("failed to remove %s", filename); goto out; } /* emit a signal */ g_debug ("emit removed: %s", filename_dup); g_signal_emit (profile_store, signals[SIGNAL_REMOVED], 0, filename_dup); out: g_free (filename_dup); return ret; } static void gcm_profile_store_add_profile (GcmProfileStore *profile_store, const gchar *filename) { GcmProfileStorePrivate *priv = profile_store->priv; /* add to list */ g_ptr_array_add (priv->filename_array, g_strdup (filename)); /* emit a signal */ g_debug ("emit add: %s", filename); g_signal_emit (profile_store, signals[SIGNAL_ADDED], 0, filename); } static void gcm_profile_store_created_query_info_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GFileInfo *info; GError *error = NULL; gchar *path; GFile *file = G_FILE (source_object); GFile *parent; GcmProfileStore *profile_store = GCM_PROFILE_STORE (user_data); info = g_file_query_info_finish (file, res, &error); if (info == NULL) { g_warning ("failed to get info about deleted file: %s", error->message); g_error_free (error); return; } parent = g_file_get_parent (file); path = g_file_get_path (parent); gcm_profile_store_process_child (profile_store, path, info); g_free (path); g_object_unref (info); g_object_unref (parent); } static void gcm_profile_store_remove_from_prefix (GcmProfileStore *profile_store, const gchar *prefix) { guint i; const gchar *path; GcmProfileStorePrivate *priv = profile_store->priv; for (i = 0; i < priv->filename_array->len; i++) { path = g_ptr_array_index (priv->filename_array, i); if (g_str_has_prefix (path, prefix)) { g_debug ("auto-removed %s as path removed", path); gcm_profile_store_remove_profile (profile_store, path); } } } static void gcm_profile_store_file_monitor_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, GcmProfileStore *profile_store) { gchar *path = NULL; gchar *parent_path = NULL; const gchar *tmp; GcmProfileStoreDirHelper *helper; /* profile was deleted */ if (event_type == G_FILE_MONITOR_EVENT_DELETED) { /* we can either have two things here, a directory or a * file. We can't call g_file_query_info_async() as the * inode doesn't exist anymore */ path = g_file_get_path (file); tmp = gcm_profile_store_find_filename (profile_store, path); if (tmp != NULL) { /* is a file */ gcm_profile_store_remove_profile (profile_store, path); goto out; } /* is a directory, urgh. Remove all profiles there. */ gcm_profile_store_remove_from_prefix (profile_store, path); helper = gcm_profile_store_find_directory (profile_store, path); if (helper != NULL) { g_ptr_array_remove (profile_store->priv->directory_array, helper); } goto out; } /* only care about created objects */ if (event_type == G_FILE_MONITOR_EVENT_CREATED) { g_file_query_info_async (file, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, G_PRIORITY_LOW, NULL, gcm_profile_store_created_query_info_cb, profile_store); goto out; } out: g_free (path); g_free (parent_path); } static void gcm_profile_store_process_child (GcmProfileStore *profile_store, const gchar *path, GFileInfo *info) { gchar *full_path = NULL; const gchar *name; GcmProfileStoreDirHelper *helper; /* check we're not in a loop */ helper = gcm_profile_store_find_directory (profile_store, path); if (helper == NULL) goto out; if (helper->depth > GCM_PROFILE_STORE_MAX_RECURSION_LEVELS) { g_warning ("recursing more than %i levels deep is insane", GCM_PROFILE_STORE_MAX_RECURSION_LEVELS); goto out; } /* make the compete path */ name = g_file_info_get_name (info); full_path = g_build_filename (path, name, NULL); /* if a directory */ if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { gcm_profile_store_search_path (profile_store, full_path, helper->depth + 1); goto out; } /* ignore temp files */ if (g_strrstr (full_path, ".goutputstream") != NULL) { g_debug ("ignoring gvfs temporary file"); goto out; } /* is a file */ gcm_profile_store_add_profile (profile_store, full_path); out: g_free (full_path); } static void gcm_profile_store_next_files_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GList *files; GList *f; GError *error = NULL; GFileInfo *info; GFile *file; gchar *path; GFileEnumerator *enumerator = G_FILE_ENUMERATOR (source_object); GcmProfileStore *profile_store = GCM_PROFILE_STORE (user_data); files = g_file_enumerator_next_files_finish (enumerator, res, &error); if (files == NULL) { /* special value, meaning "no more files to process" */ return; } if (error != NULL) { g_warning ("failed to get data about enumerated directory: %s", error->message); g_error_free (error); return; } /* get each file */ file = g_file_enumerator_get_container (enumerator); path = g_file_get_path (file); for (f = files; f != NULL; f = f->next) { info = G_FILE_INFO (f->data); gcm_profile_store_process_child (profile_store, path, info); } /* continue to get the rest of the data in chunks */ g_file_enumerator_next_files_async (enumerator, 5, G_PRIORITY_LOW, profile_store->priv->cancellable, gcm_profile_store_next_files_cb, user_data); g_free (path); g_list_foreach (files, (GFunc) g_object_unref, NULL); g_list_free (files); } static void gcm_profile_store_enumerate_children_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; GFileEnumerator *enumerator; GcmProfileStore *profile_store = GCM_PROFILE_STORE (user_data); enumerator = g_file_enumerate_children_finish (G_FILE (source_object), res, &error); if (enumerator == NULL) { GcmProfileStoreDirHelper *helper; gchar *path = NULL; path = g_file_get_path (G_FILE (source_object)); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) g_debug ("failed to enumerate directory %s: %s", path, error->message); else g_warning ("failed to enumerate directory %s: %s", path, error->message); helper = gcm_profile_store_find_directory (profile_store, path); if (helper) g_ptr_array_remove (profile_store->priv->directory_array, helper); g_error_free (error); g_free (path); return; } /* get the first chunk of data */ g_file_enumerator_next_files_async (enumerator, 5, G_PRIORITY_LOW, profile_store->priv->cancellable, gcm_profile_store_next_files_cb, user_data); g_object_unref (enumerator); } static void gcm_profile_store_search_path (GcmProfileStore *profile_store, const gchar *path, guint depth) { GFile *file = NULL; GError *error = NULL; GcmProfileStoreDirHelper *helper; file = g_file_new_for_path (path); /* add an inotify watch if not already added */ helper = gcm_profile_store_find_directory (profile_store, path); if (helper == NULL) { helper = g_new0 (GcmProfileStoreDirHelper, 1); helper->depth = depth; helper->path = g_strdup (path); helper->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, &error); if (helper->monitor == NULL) { g_debug ("failed to monitor path: %s", error->message); g_error_free (error); gcm_profile_store_helper_free (helper); goto out; } g_signal_connect (helper->monitor, "changed", G_CALLBACK(gcm_profile_store_file_monitor_changed_cb), profile_store); g_ptr_array_add (profile_store->priv->directory_array, helper); } /* get contents of directory */ g_file_enumerate_children_async (file, G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, G_PRIORITY_LOW, profile_store->priv->cancellable, gcm_profile_store_enumerate_children_cb, profile_store); out: g_object_unref (file); } static gboolean gcm_profile_store_mkdir_with_parents (const gchar *filename, GCancellable *cancellable, GError **error) { gboolean ret; GFile *file; /* ensure destination exists */ file = g_file_new_for_path (filename); ret = g_file_make_directory_with_parents (file, cancellable, error); g_object_unref (file); return ret; } gboolean gcm_profile_store_search (GcmProfileStore *profile_store) { gchar *path; gboolean ret; GError *error = NULL; /* get Linux per-user profiles */ path = g_build_filename (g_get_user_data_dir (), "icc", NULL); ret = gcm_profile_store_mkdir_with_parents (path, profile_store->priv->cancellable, &error); if (!ret && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { g_warning ("failed to create directory on startup: %s", error->message); } else { gcm_profile_store_search_path (profile_store, path, 0); } g_free (path); g_clear_error (&error); /* get per-user profiles from obsolete location */ path = g_build_filename (g_get_home_dir (), ".color", "icc", NULL); gcm_profile_store_search_path (profile_store, path, 0); g_free (path); return TRUE; } static void gcm_profile_store_class_init (GcmProfileStoreClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gcm_profile_store_finalize; signals[SIGNAL_ADDED] = g_signal_new ("added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcmProfileStoreClass, added), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); signals[SIGNAL_REMOVED] = g_signal_new ("removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcmProfileStoreClass, removed), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); g_type_class_add_private (klass, sizeof (GcmProfileStorePrivate)); } static void gcm_profile_store_init (GcmProfileStore *profile_store) { profile_store->priv = GCM_PROFILE_STORE_GET_PRIVATE (profile_store); profile_store->priv->cancellable = g_cancellable_new (); profile_store->priv->filename_array = g_ptr_array_new_with_free_func (g_free); profile_store->priv->directory_array = g_ptr_array_new_with_free_func ((GDestroyNotify) gcm_profile_store_helper_free); } static void gcm_profile_store_finalize (GObject *object) { GcmProfileStore *profile_store = GCM_PROFILE_STORE (object); GcmProfileStorePrivate *priv = profile_store->priv; g_cancellable_cancel (profile_store->priv->cancellable); g_object_unref (profile_store->priv->cancellable); g_ptr_array_unref (priv->filename_array); g_ptr_array_unref (priv->directory_array); G_OBJECT_CLASS (gcm_profile_store_parent_class)->finalize (object); } GcmProfileStore * gcm_profile_store_new (void) { GcmProfileStore *profile_store; profile_store = g_object_new (GCM_TYPE_PROFILE_STORE, NULL); return GCM_PROFILE_STORE (profile_store); } cinnamon-settings-daemon-2.8.3/plugins/color/test-data/0000775000175000017500000000000012625665665022061 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/color/test-data/LG-L225W-External.bin0000664000175000017500000000020012625665665025376 0ustar fabiofabioÿÿÿÿÿÿmcV^† ê/xêÔ%¤UI›'PT§k€••€@qO|. `@0 6Ú(!90b'@h°6Ú(ý8KS üL225W tcinnamon-settings-daemon-2.8.3/plugins/color/test-data/Lenovo-T61-Internal.bin0000664000175000017500000000020012625665665026127 0ustar fabiofabioÿÿÿÿÿÿ$M‡(€!x Íu‘UO‹&!PT¨/à`@ @KÏ·'à`@ @Kϳ 2³ (L£X3þLTN154P2-L05 §cinnamon-settings-daemon-2.8.3/plugins/color/gcm-self-test.c0000664000175000017500000000774612625665665023027 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2007-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include "gcm-edid.h" #include "gcm-dmi.h" static void gcm_test_dmi_func (void) { GcmDmi *dmi; dmi = gcm_dmi_new (); g_assert (dmi != NULL); g_assert (gcm_dmi_get_name (dmi) != NULL); g_assert (gcm_dmi_get_vendor (dmi) != NULL); g_object_unref (dmi); } static void gcm_test_edid_func (void) { GcmEdid *edid; gchar *data; gboolean ret; GError *error = NULL; gsize length = 0; edid = gcm_edid_new (); g_assert (edid != NULL); /* LG 21" LCD panel */ ret = g_file_get_contents (TESTDATADIR "/LG-L225W-External.bin", &data, &length, &error); g_assert_no_error (error); g_assert (ret); ret = gcm_edid_parse (edid, (const guint8 *) data, length, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpstr (gcm_edid_get_monitor_name (edid), ==, "L225W"); g_assert_cmpstr (gcm_edid_get_vendor_name (edid), ==, "Goldstar Company Ltd"); g_assert_cmpstr (gcm_edid_get_serial_number (edid), ==, "34398"); g_assert_cmpstr (gcm_edid_get_eisa_id (edid), ==, NULL); g_assert_cmpstr (gcm_edid_get_checksum (edid), ==, "0bb44865bb29984a4bae620656c31368"); g_assert_cmpstr (gcm_edid_get_pnp_id (edid), ==, "GSM"); g_assert_cmpint (gcm_edid_get_height (edid), ==, 30); g_assert_cmpint (gcm_edid_get_width (edid), ==, 47); g_assert_cmpfloat (gcm_edid_get_gamma (edid), >=, 2.2f - 0.01); g_assert_cmpfloat (gcm_edid_get_gamma (edid), <, 2.2f + 0.01); g_free (data); /* Lenovo T61 internal Panel */ ret = g_file_get_contents (TESTDATADIR "/Lenovo-T61-Internal.bin", &data, &length, &error); g_assert_no_error (error); g_assert (ret); ret = gcm_edid_parse (edid, (const guint8 *) data, length, &error); g_assert_no_error (error); g_assert (ret); g_assert_cmpstr (gcm_edid_get_monitor_name (edid), ==, NULL); g_assert_cmpstr (gcm_edid_get_vendor_name (edid), ==, "IBM France"); g_assert_cmpstr (gcm_edid_get_serial_number (edid), ==, NULL); g_assert_cmpstr (gcm_edid_get_eisa_id (edid), ==, "LTN154P2-L05"); g_assert_cmpstr (gcm_edid_get_checksum (edid), ==, "e1865128c7cd5e5ed49ecfc8102f6f9c"); g_assert_cmpstr (gcm_edid_get_pnp_id (edid), ==, "IBM"); g_assert_cmpint (gcm_edid_get_height (edid), ==, 21); g_assert_cmpint (gcm_edid_get_width (edid), ==, 33); g_assert_cmpfloat (gcm_edid_get_gamma (edid), >=, 2.2f - 0.01); g_assert_cmpfloat (gcm_edid_get_gamma (edid), <, 2.2f + 0.01); g_free (data); g_object_unref (edid); } int main (int argc, char **argv) { gtk_init (&argc, &argv); g_test_init (&argc, &argv, NULL); g_test_add_func ("/color/dmi", gcm_test_dmi_func); g_test_add_func ("/color/edid", gcm_test_edid_func); return g_test_run (); } cinnamon-settings-daemon-2.8.3/plugins/color/csd-color-plugin.c0000664000175000017500000000616712625665665023532 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2011 Richard Hughes * * 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 "cinnamon-settings-plugin.h" #include "csd-color-plugin.h" #include "csd-color-manager.h" struct CsdColorPluginPrivate { CsdColorManager *manager; }; #define CSD_COLOR_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_COLOR_PLUGIN, CsdColorPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdColorPlugin, csd_color_plugin) static void csd_color_plugin_init (CsdColorPlugin *plugin) { plugin->priv = CSD_COLOR_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdColorPlugin initializing"); plugin->priv->manager = csd_color_manager_new (); } static void csd_color_plugin_finalize (GObject *object) { CsdColorPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_COLOR_PLUGIN (object)); g_debug ("CsdColorPlugin finalizing"); plugin = CSD_COLOR_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_color_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating color plugin"); error = NULL; res = csd_color_manager_start (CSD_COLOR_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start color manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating color plugin"); csd_color_manager_stop (CSD_COLOR_PLUGIN (plugin)->priv->manager); } static void csd_color_plugin_class_init (CsdColorPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_color_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdColorPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/color/gcm-profile-store.h0000664000175000017500000000467312625665665023714 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2009-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GCM_PROFILE_STORE_H #define __GCM_PROFILE_STORE_H #include G_BEGIN_DECLS #define GCM_TYPE_PROFILE_STORE (gcm_profile_store_get_type ()) #define GCM_PROFILE_STORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GCM_TYPE_PROFILE_STORE, GcmProfileStore)) #define GCM_PROFILE_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GCM_TYPE_PROFILE_STORE, GcmProfileStoreClass)) #define GCM_IS_PROFILE_STORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GCM_TYPE_PROFILE_STORE)) #define GCM_IS_PROFILE_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GCM_TYPE_PROFILE_STORE)) #define GCM_PROFILE_STORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GCM_TYPE_PROFILE_STORE, GcmProfileStoreClass)) typedef struct _GcmProfileStorePrivate GcmProfileStorePrivate; typedef struct _GcmProfileStore GcmProfileStore; typedef struct _GcmProfileStoreClass GcmProfileStoreClass; struct _GcmProfileStore { GObject parent; GcmProfileStorePrivate *priv; }; struct _GcmProfileStoreClass { GObjectClass parent_class; void (* added) (const gchar *filename); void (* removed) (const gchar *filename); }; GType gcm_profile_store_get_type (void); GcmProfileStore *gcm_profile_store_new (void); gboolean gcm_profile_store_search (GcmProfileStore *profile_store); G_END_DECLS #endif /* __GCM_PROFILE_STORE_H */ cinnamon-settings-daemon-2.8.3/plugins/color/color.cinnamon-settings-plugin.in0000664000175000017500000000026612625665665026600 0ustar fabiofabio[Cinnamon Settings Plugin] Module=color IAge=0 _Name=Color _Description=Color plugin Authors=Richard Hughes Copyright=Copyright © 2011 Richard Hughes Website= cinnamon-settings-daemon-2.8.3/plugins/color/csd-color-manager.h0000664000175000017500000000477012625665665023651 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2011 Richard Hughes * * 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_COLOR_MANAGER_H #define __CSD_COLOR_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_COLOR_MANAGER (csd_color_manager_get_type ()) #define CSD_COLOR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_COLOR_MANAGER, CsdColorManager)) #define CSD_COLOR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_COLOR_MANAGER, CsdColorManagerClass)) #define CSD_IS_COLOR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_COLOR_MANAGER)) #define CSD_IS_COLOR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_COLOR_MANAGER)) #define CSD_COLOR_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_COLOR_MANAGER, CsdColorManagerClass)) #define CSD_COLOR_MANAGER_ERROR (csd_color_manager_error_quark ()) typedef struct CsdColorManagerPrivate CsdColorManagerPrivate; typedef struct { GObject parent; CsdColorManagerPrivate *priv; } CsdColorManager; typedef struct { GObjectClass parent_class; } CsdColorManagerClass; enum { CSD_COLOR_MANAGER_ERROR_FAILED }; GType csd_color_manager_get_type (void); GQuark csd_color_manager_error_quark (void); CsdColorManager * csd_color_manager_new (void); gboolean csd_color_manager_start (CsdColorManager *manager, GError **error); void csd_color_manager_stop (CsdColorManager *manager); G_END_DECLS #endif /* __CSD_COLOR_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/color/Makefile.am0000664000175000017500000000321412625665665022227 0ustar fabiofabioplugin_name = color plugin_LTLIBRARIES = \ libcolor.la libcolor_la_SOURCES = \ gcm-profile-store.c \ gcm-profile-store.h \ gcm-dmi.c \ gcm-dmi.h \ gcm-edid.c \ gcm-edid.h \ csd-color-manager.c \ csd-color-manager.h \ csd-color-plugin.c \ csd-color-plugin.h libcolor_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DBINDIR=\"$(bindir)\" \ $(AM_CPPFLAGS) libcolor_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(COLOR_CFLAGS) \ $(LCMS_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(AM_CFLAGS) libcolor_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) libcolor_la_LIBADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(COLOR_LIBS) \ $(LCMS_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(LIBNOTIFY_LIBS) check_PROGRAMS = \ gcm-self-test gcm_self_test_CPPFLAGS = \ -DTESTDATADIR=\""$(top_srcdir)/plugins/color/test-data"\" \ $(AM_CPPFLAGS) gcm_self_test_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(COLOR_CFLAGS) \ $(PLUGIN_CFLAGS) \ $(AM_CFLAGS) gcm_self_test_SOURCES = \ gcm-dmi.c \ gcm-dmi.h \ gcm-edid.c \ gcm-edid.h \ gcm-self-test.c gcm_self_test_LDADD = \ $(COLOR_LIBS) \ $(LCMS_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ -lm TESTS = gcm-self-test plugin_in_files = \ color.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) \ test-data/Lenovo-T61-Internal.bin \ test-data/LG-L225W-External.bin CLEANFILES = \ $(plugin_DATA) DISTCLEANFILES = \ $(plugin_DATA) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/color/gcm-edid.c0000664000175000017500000003432512625665665022017 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2008 Soren Sandmann * Copyright (C) 2009-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include "gcm-edid.h" static void gcm_edid_finalize (GObject *object); #define GCM_EDID_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCM_TYPE_EDID, GcmEdidPrivate)) struct _GcmEdidPrivate { gchar *monitor_name; gchar *vendor_name; gchar *serial_number; gchar *eisa_id; gchar *checksum; gchar *pnp_id; guint width; guint height; gfloat gamma; CdColorYxy *red; CdColorYxy *green; CdColorYxy *blue; CdColorYxy *white; GnomePnpIds *pnp_ids; }; G_DEFINE_TYPE (GcmEdid, gcm_edid, G_TYPE_OBJECT) #define GCM_EDID_OFFSET_PNPID 0x08 #define GCM_EDID_OFFSET_SERIAL 0x0c #define GCM_EDID_OFFSET_SIZE 0x15 #define GCM_EDID_OFFSET_GAMMA 0x17 #define GCM_EDID_OFFSET_DATA_BLOCKS 0x36 #define GCM_EDID_OFFSET_LAST_BLOCK 0x6c #define GCM_EDID_OFFSET_EXTENSION_BLOCK_COUNT 0x7e #define GCM_DESCRIPTOR_DISPLAY_PRODUCT_NAME 0xfc #define GCM_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER 0xff #define GCM_DESCRIPTOR_COLOR_MANAGEMENT_DATA 0xf9 #define GCM_DESCRIPTOR_ALPHANUMERIC_DATA_STRING 0xfe #define GCM_DESCRIPTOR_COLOR_POINT 0xfb GQuark gcm_edid_error_quark (void) { static GQuark quark = 0; if (!quark) quark = g_quark_from_static_string ("gcm_edid_error"); return quark; } const gchar * gcm_edid_get_monitor_name (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->monitor_name; } const gchar * gcm_edid_get_vendor_name (GcmEdid *edid) { GcmEdidPrivate *priv = edid->priv; g_return_val_if_fail (GCM_IS_EDID (edid), NULL); if (priv->vendor_name == NULL) priv->vendor_name = gnome_pnp_ids_get_pnp_id (priv->pnp_ids, priv->pnp_id); return priv->vendor_name; } const gchar * gcm_edid_get_serial_number (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->serial_number; } const gchar * gcm_edid_get_eisa_id (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->eisa_id; } const gchar * gcm_edid_get_checksum (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->checksum; } const gchar * gcm_edid_get_pnp_id (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->pnp_id; } guint gcm_edid_get_width (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), 0); return edid->priv->width; } guint gcm_edid_get_height (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), 0); return edid->priv->height; } gfloat gcm_edid_get_gamma (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), 0.0f); return edid->priv->gamma; } const CdColorYxy * gcm_edid_get_red (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->red; } const CdColorYxy * gcm_edid_get_green (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->green; } const CdColorYxy * gcm_edid_get_blue (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->blue; } const CdColorYxy * gcm_edid_get_white (GcmEdid *edid) { g_return_val_if_fail (GCM_IS_EDID (edid), NULL); return edid->priv->white; } void gcm_edid_reset (GcmEdid *edid) { GcmEdidPrivate *priv = edid->priv; g_return_if_fail (GCM_IS_EDID (edid)); /* free old data */ g_free (priv->monitor_name); g_free (priv->vendor_name); g_free (priv->serial_number); g_free (priv->eisa_id); g_free (priv->checksum); /* do not deallocate, just blank */ priv->pnp_id[0] = '\0'; /* set to default values */ priv->monitor_name = NULL; priv->vendor_name = NULL; priv->serial_number = NULL; priv->eisa_id = NULL; priv->checksum = NULL; priv->width = 0; priv->height = 0; priv->gamma = 0.0f; } static gint gcm_edid_get_bit (gint in, gint bit) { return (in & (1 << bit)) >> bit; } /** * gcm_edid_get_bits: **/ static gint gcm_edid_get_bits (gint in, gint begin, gint end) { gint mask = (1 << (end - begin + 1)) - 1; return (in >> begin) & mask; } /** * gcm_edid_decode_fraction: **/ static gdouble gcm_edid_decode_fraction (gint high, gint low) { gdouble result = 0.0; gint i; high = (high << 2) | low; for (i = 0; i < 10; ++i) result += gcm_edid_get_bit (high, i) * pow (2, i - 10); return result; } static gchar * gcm_edid_parse_string (const guint8 *data) { gchar *text; guint i; guint replaced = 0; /* this is always 12 bytes, but we can't guarantee it's null * terminated or not junk. */ text = g_strndup ((const gchar *) data, 12); /* remove insane newline chars */ g_strdelimit (text, "\n\r", '\0'); /* remove spaces */ g_strchomp (text); /* nothing left? */ if (text[0] == '\0') { g_free (text); text = NULL; goto out; } /* ensure string is printable */ for (i = 0; text[i] != '\0'; i++) { if (!g_ascii_isprint (text[i])) { text[i] = '-'; replaced++; } } /* if the string is junk, ignore the string */ if (replaced > 4) { g_free (text); text = NULL; goto out; } out: return text; } gboolean gcm_edid_parse (GcmEdid *edid, const guint8 *data, gsize length, GError **error) { gboolean ret = TRUE; guint i; GcmEdidPrivate *priv = edid->priv; guint32 serial; gchar *tmp; /* check header */ if (length < 128) { g_set_error_literal (error, GCM_EDID_ERROR, GCM_EDID_ERROR_FAILED_TO_PARSE, "EDID length is too small"); ret = FALSE; goto out; } if (data[0] != 0x00 || data[1] != 0xff) { g_set_error_literal (error, GCM_EDID_ERROR, GCM_EDID_ERROR_FAILED_TO_PARSE, "Failed to parse EDID header"); ret = FALSE; goto out; } /* free old data */ gcm_edid_reset (edid); /* decode the PNP ID from three 5 bit words packed into 2 bytes * /--08--\/--09--\ * 7654321076543210 * |\---/\---/\---/ * R C1 C2 C3 */ priv->pnp_id[0] = 'A' + ((data[GCM_EDID_OFFSET_PNPID+0] & 0x7c) / 4) - 1; priv->pnp_id[1] = 'A' + ((data[GCM_EDID_OFFSET_PNPID+0] & 0x3) * 8) + ((data[GCM_EDID_OFFSET_PNPID+1] & 0xe0) / 32) - 1; priv->pnp_id[2] = 'A' + (data[GCM_EDID_OFFSET_PNPID+1] & 0x1f) - 1; /* maybe there isn't a ASCII serial number descriptor, so use this instead */ serial = (guint32) data[GCM_EDID_OFFSET_SERIAL+0]; serial += (guint32) data[GCM_EDID_OFFSET_SERIAL+1] * 0x100; serial += (guint32) data[GCM_EDID_OFFSET_SERIAL+2] * 0x10000; serial += (guint32) data[GCM_EDID_OFFSET_SERIAL+3] * 0x1000000; if (serial > 0) priv->serial_number = g_strdup_printf ("%" G_GUINT32_FORMAT, serial); /* get the size */ priv->width = data[GCM_EDID_OFFSET_SIZE+0]; priv->height = data[GCM_EDID_OFFSET_SIZE+1]; /* we don't care about aspect */ if (priv->width == 0 || priv->height == 0) { priv->width = 0; priv->height = 0; } /* get gamma */ if (data[GCM_EDID_OFFSET_GAMMA] == 0xff) { priv->gamma = 1.0f; } else { priv->gamma = ((gfloat) data[GCM_EDID_OFFSET_GAMMA] / 100) + 1; } /* get color red */ priv->red->x = gcm_edid_decode_fraction (data[0x1b], gcm_edid_get_bits (data[0x19], 6, 7)); priv->red->y = gcm_edid_decode_fraction (data[0x1c], gcm_edid_get_bits (data[0x19], 5, 4)); /* get color green */ priv->green->x = gcm_edid_decode_fraction (data[0x1d], gcm_edid_get_bits (data[0x19], 2, 3)); priv->green->y = gcm_edid_decode_fraction (data[0x1e], gcm_edid_get_bits (data[0x19], 0, 1)); /* get color blue */ priv->blue->x = gcm_edid_decode_fraction (data[0x1f], gcm_edid_get_bits (data[0x1a], 6, 7)); priv->blue->y = gcm_edid_decode_fraction (data[0x20], gcm_edid_get_bits (data[0x1a], 4, 5)); /* get color white */ priv->white->x = gcm_edid_decode_fraction (data[0x21], gcm_edid_get_bits (data[0x1a], 2, 3)); priv->white->y = gcm_edid_decode_fraction (data[0x22], gcm_edid_get_bits (data[0x1a], 0, 1)); /* parse EDID data */ for (i = GCM_EDID_OFFSET_DATA_BLOCKS; i <= GCM_EDID_OFFSET_LAST_BLOCK; i += 18) { /* ignore pixel clock data */ if (data[i] != 0) continue; if (data[i+2] != 0) continue; /* any useful blocks? */ if (data[i+3] == GCM_DESCRIPTOR_DISPLAY_PRODUCT_NAME) { tmp = gcm_edid_parse_string (&data[i+5]); if (tmp != NULL) { g_free (priv->monitor_name); priv->monitor_name = tmp; } } else if (data[i+3] == GCM_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) { tmp = gcm_edid_parse_string (&data[i+5]); if (tmp != NULL) { g_free (priv->serial_number); priv->serial_number = tmp; } } else if (data[i+3] == GCM_DESCRIPTOR_COLOR_MANAGEMENT_DATA) { g_warning ("failing to parse color management data"); } else if (data[i+3] == GCM_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) { tmp = gcm_edid_parse_string (&data[i+5]); if (tmp != NULL) { g_free (priv->eisa_id); priv->eisa_id = tmp; } } else if (data[i+3] == GCM_DESCRIPTOR_COLOR_POINT) { if (data[i+3+9] != 0xff) { /* extended EDID block(1) which contains * a better gamma value */ priv->gamma = ((gfloat) data[i+3+9] / 100) + 1; } if (data[i+3+14] != 0xff) { /* extended EDID block(2) which contains * a better gamma value */ priv->gamma = ((gfloat) data[i+3+9] / 100) + 1; } } } /* calculate checksum */ priv->checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5, data, length); out: return ret; } static void gcm_edid_class_init (GcmEdidClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gcm_edid_finalize; g_type_class_add_private (klass, sizeof (GcmEdidPrivate)); } static void gcm_edid_init (GcmEdid *edid) { edid->priv = GCM_EDID_GET_PRIVATE (edid); edid->priv->pnp_ids = gnome_pnp_ids_new (); edid->priv->pnp_id = g_new0 (gchar, 4); edid->priv->red = cd_color_yxy_new (); edid->priv->green = cd_color_yxy_new (); edid->priv->blue = cd_color_yxy_new (); edid->priv->white = cd_color_yxy_new (); } static void gcm_edid_finalize (GObject *object) { GcmEdid *edid = GCM_EDID (object); GcmEdidPrivate *priv = edid->priv; g_free (priv->monitor_name); g_free (priv->vendor_name); g_free (priv->serial_number); g_free (priv->eisa_id); g_free (priv->checksum); g_free (priv->pnp_id); cd_color_yxy_free (priv->white); cd_color_yxy_free (priv->red); cd_color_yxy_free (priv->green); cd_color_yxy_free (priv->blue); g_object_unref (priv->pnp_ids); G_OBJECT_CLASS (gcm_edid_parent_class)->finalize (object); } GcmEdid * gcm_edid_new (void) { GcmEdid *edid; edid = g_object_new (GCM_TYPE_EDID, NULL); return GCM_EDID (edid); } cinnamon-settings-daemon-2.8.3/plugins/media-keys/0000775000175000017500000000000012625665665021105 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/media-keys/csd-marshal.c0000664000175000017500000001117412625665665023453 0ustar fabiofabio #ifndef __csd_marshal_MARSHAL_H__ #define __csd_marshal_MARSHAL_H__ #include G_BEGIN_DECLS #ifdef G_ENABLE_DEBUG #define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) #define g_marshal_value_peek_char(v) g_value_get_schar (v) #define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) #define g_marshal_value_peek_int(v) g_value_get_int (v) #define g_marshal_value_peek_uint(v) g_value_get_uint (v) #define g_marshal_value_peek_long(v) g_value_get_long (v) #define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) #define g_marshal_value_peek_int64(v) g_value_get_int64 (v) #define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) #define g_marshal_value_peek_enum(v) g_value_get_enum (v) #define g_marshal_value_peek_flags(v) g_value_get_flags (v) #define g_marshal_value_peek_float(v) g_value_get_float (v) #define g_marshal_value_peek_double(v) g_value_get_double (v) #define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) #define g_marshal_value_peek_param(v) g_value_get_param (v) #define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) #define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) #define g_marshal_value_peek_object(v) g_value_get_object (v) #define g_marshal_value_peek_variant(v) g_value_get_variant (v) #else /* !G_ENABLE_DEBUG */ /* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. * Do not access GValues directly in your code. Instead, use the * g_value_get_*() functions */ #define g_marshal_value_peek_boolean(v) (v)->data[0].v_int #define g_marshal_value_peek_char(v) (v)->data[0].v_int #define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint #define g_marshal_value_peek_int(v) (v)->data[0].v_int #define g_marshal_value_peek_uint(v) (v)->data[0].v_uint #define g_marshal_value_peek_long(v) (v)->data[0].v_long #define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong #define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 #define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 #define g_marshal_value_peek_enum(v) (v)->data[0].v_long #define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong #define g_marshal_value_peek_float(v) (v)->data[0].v_float #define g_marshal_value_peek_double(v) (v)->data[0].v_double #define g_marshal_value_peek_string(v) (v)->data[0].v_pointer #define g_marshal_value_peek_param(v) (v)->data[0].v_pointer #define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer #define g_marshal_value_peek_object(v) (v)->data[0].v_pointer #define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer #endif /* !G_ENABLE_DEBUG */ /* VOID:STRING,STRING (csd-marshal.list:1) */ G_GNUC_INTERNAL void csd_marshal_VOID__STRING_STRING (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); void csd_marshal_VOID__STRING_STRING (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef void (*GMarshalFunc_VOID__STRING_STRING) (gpointer data1, gpointer arg_1, gpointer arg_2, gpointer data2); register GMarshalFunc_VOID__STRING_STRING callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_VOID__STRING_STRING) (marshal_data ? marshal_data : cc->callback); callback (data1, g_marshal_value_peek_string (param_values + 1), g_marshal_value_peek_string (param_values + 2), data2); } G_END_DECLS #endif /* __csd_marshal_MARSHAL_H__ */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/0000775000175000017500000000000012625665665023245 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-pulseaudio-fake.h0000664000175000017500000000217212625665665027253 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. * */ #ifndef __GVC_PULSEAUDIO_FAKE_H #define __GVC_PULSEAUDIO_FAKE_H #ifdef WITH_INTROSPECTION #ifndef PA_API_VERSION #define pa_channel_position_t int #define pa_volume_t guint32 #define pa_context gpointer #endif /* PA_API_VERSION */ #endif /* WITH_INTROSPECTION */ #endif /* __GVC_PULSEAUDIO_FAKE_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-source.c0000664000175000017500000001354212625665665026615 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 "gvc-mixer-source.h" #include "gvc-mixer-stream-private.h" #include "gvc-channel-map-private.h" #define GVC_MIXER_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSourcePrivate)) struct GvcMixerSourcePrivate { gpointer dummy; }; static void gvc_mixer_source_class_init (GvcMixerSourceClass *klass); static void gvc_mixer_source_init (GvcMixerSource *mixer_source); static void gvc_mixer_source_finalize (GObject *object); G_DEFINE_TYPE (GvcMixerSource, gvc_mixer_source, GVC_TYPE_MIXER_STREAM) static gboolean gvc_mixer_source_push_volume (GvcMixerStream *stream, gpointer *op) { pa_operation *o; guint index; const GvcChannelMap *map; pa_context *context; const pa_cvolume *cv; index = gvc_mixer_stream_get_index (stream); map = gvc_mixer_stream_get_channel_map (stream); /* set the volume */ cv = gvc_channel_map_get_cvolume (map); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_source_volume_by_index (context, index, cv, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_source_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } *op = o; return TRUE; } static gboolean gvc_mixer_source_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { pa_operation *o; guint index; pa_context *context; index = gvc_mixer_stream_get_index (stream); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_source_mute_by_index (context, index, is_muted, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_source_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } pa_operation_unref(o); return TRUE; } static gboolean gvc_mixer_source_change_port (GvcMixerStream *stream, const char *port) { pa_operation *o; guint index; pa_context *context; index = gvc_mixer_stream_get_index (stream); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_source_port_by_index (context, index, port, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_source_port_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } pa_operation_unref(o); return TRUE; } static void gvc_mixer_source_class_init (GvcMixerSourceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass); object_class->finalize = gvc_mixer_source_finalize; stream_class->push_volume = gvc_mixer_source_push_volume; stream_class->change_is_muted = gvc_mixer_source_change_is_muted; stream_class->change_port = gvc_mixer_source_change_port; g_type_class_add_private (klass, sizeof (GvcMixerSourcePrivate)); } static void gvc_mixer_source_init (GvcMixerSource *source) { source->priv = GVC_MIXER_SOURCE_GET_PRIVATE (source); } static void gvc_mixer_source_finalize (GObject *object) { GvcMixerSource *mixer_source; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_SOURCE (object)); mixer_source = GVC_MIXER_SOURCE (object); g_return_if_fail (mixer_source->priv != NULL); G_OBJECT_CLASS (gvc_mixer_source_parent_class)->finalize (object); } /** * gvc_mixer_source_new: (skip) * * @context: * @index: * @channel_map: * * Returns: */ GvcMixerStream * gvc_mixer_source_new (pa_context *context, guint index, GvcChannelMap *channel_map) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_SOURCE, "pa-context", context, "index", index, "channel-map", channel_map, NULL); return GVC_MIXER_STREAM (object); } cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.h0000664000175000017500000000432612625665665027423 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. * */ #ifndef __GVC_MIXER_SINK_INPUT_H #define __GVC_MIXER_SINK_INPUT_H #include #include "gvc-mixer-stream.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_SINK_INPUT (gvc_mixer_sink_input_get_type ()) #define GVC_MIXER_SINK_INPUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInput)) #define GVC_MIXER_SINK_INPUT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputClass)) #define GVC_IS_MIXER_SINK_INPUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SINK_INPUT)) #define GVC_IS_MIXER_SINK_INPUT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SINK_INPUT)) #define GVC_MIXER_SINK_INPUT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputClass)) typedef struct GvcMixerSinkInputPrivate GvcMixerSinkInputPrivate; typedef struct { GvcMixerStream parent; GvcMixerSinkInputPrivate *priv; } GvcMixerSinkInput; typedef struct { GvcMixerStreamClass parent_class; } GvcMixerSinkInputClass; GType gvc_mixer_sink_input_get_type (void); GvcMixerStream * gvc_mixer_sink_input_new (pa_context *context, guint index, GvcChannelMap *map); G_END_DECLS #endif /* __GVC_MIXER_SINK_INPUT_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-stream.c0000664000175000017500000010510212625665665026602 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 "gvc-mixer-stream.h" #include "gvc-mixer-stream-private.h" #include "gvc-channel-map-private.h" #define GVC_MIXER_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamPrivate)) static guint32 stream_serial = 1; struct GvcMixerStreamPrivate { pa_context *pa_context; guint id; guint index; gint card_index; GvcChannelMap *channel_map; char *name; char *description; char *application_id; char *icon_name; char *sysfs_path; gboolean is_muted; gboolean can_decibel; gboolean is_event_stream; gboolean is_virtual; pa_volume_t base_volume; pa_operation *change_volume_op; char *port; char *human_port; GList *ports; }; enum { PROP_0, PROP_ID, PROP_PA_CONTEXT, PROP_CHANNEL_MAP, PROP_INDEX, PROP_NAME, PROP_DESCRIPTION, PROP_APPLICATION_ID, PROP_ICON_NAME, PROP_SYSFS_PATH, PROP_VOLUME, PROP_DECIBEL, PROP_IS_MUTED, PROP_CAN_DECIBEL, PROP_IS_EVENT_STREAM, PROP_IS_VIRTUAL, PROP_CARD_INDEX, PROP_PORT, }; static void gvc_mixer_stream_class_init (GvcMixerStreamClass *klass); static void gvc_mixer_stream_init (GvcMixerStream *mixer_stream); static void gvc_mixer_stream_finalize (GObject *object); G_DEFINE_ABSTRACT_TYPE (GvcMixerStream, gvc_mixer_stream, G_TYPE_OBJECT) static guint32 get_next_stream_serial (void) { guint32 serial; serial = stream_serial++; if ((gint32)stream_serial < 0) { stream_serial = 1; } return serial; } pa_context * gvc_mixer_stream_get_pa_context (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return stream->priv->pa_context; } guint gvc_mixer_stream_get_index (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return stream->priv->index; } guint gvc_mixer_stream_get_id (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return stream->priv->id; } const GvcChannelMap * gvc_mixer_stream_get_channel_map (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->channel_map; } /** * gvc_mixer_stream_get_volume: * * @stream: * * Returns: (type guint32) (transfer none): */ pa_volume_t gvc_mixer_stream_get_volume (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME]; } gdouble gvc_mixer_stream_get_decibel (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return pa_sw_volume_to_dB( (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME]); } /** * gvc_mixer_stream_set_volume: * * @stream: * @volume: (type guint32): * * Returns: */ gboolean gvc_mixer_stream_set_volume (GvcMixerStream *stream, pa_volume_t volume) { pa_cvolume cv; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map); pa_cvolume_scale(&cv, volume); if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) { gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE); g_object_notify (G_OBJECT (stream), "volume"); return TRUE; } return FALSE; } gboolean gvc_mixer_stream_set_decibel (GvcMixerStream *stream, gdouble db) { pa_cvolume cv; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map); pa_cvolume_scale(&cv, pa_sw_volume_from_dB(db)); if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) { gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE); g_object_notify (G_OBJECT (stream), "volume"); } return TRUE; } gboolean gvc_mixer_stream_get_is_muted (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); return stream->priv->is_muted; } gboolean gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); return stream->priv->can_decibel; } gboolean gvc_mixer_stream_set_is_muted (GvcMixerStream *stream, gboolean is_muted) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); if (is_muted != stream->priv->is_muted) { stream->priv->is_muted = is_muted; g_object_notify (G_OBJECT (stream), "is-muted"); } return TRUE; } gboolean gvc_mixer_stream_set_can_decibel (GvcMixerStream *stream, gboolean can_decibel) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); if (can_decibel != stream->priv->can_decibel) { stream->priv->can_decibel = can_decibel; g_object_notify (G_OBJECT (stream), "can-decibel"); } return TRUE; } const char * gvc_mixer_stream_get_name (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->name; } const char * gvc_mixer_stream_get_description (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->description; } gboolean gvc_mixer_stream_set_name (GvcMixerStream *stream, const char *name) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_free (stream->priv->name); stream->priv->name = g_strdup (name); g_object_notify (G_OBJECT (stream), "name"); return TRUE; } gboolean gvc_mixer_stream_set_description (GvcMixerStream *stream, const char *description) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_free (stream->priv->description); stream->priv->description = g_strdup (description); g_object_notify (G_OBJECT (stream), "description"); return TRUE; } gboolean gvc_mixer_stream_is_event_stream (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); return stream->priv->is_event_stream; } gboolean gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream, gboolean is_event_stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); stream->priv->is_event_stream = is_event_stream; g_object_notify (G_OBJECT (stream), "is-event-stream"); return TRUE; } gboolean gvc_mixer_stream_is_virtual (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); return stream->priv->is_virtual; } gboolean gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream, gboolean is_virtual) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); stream->priv->is_virtual = is_virtual; g_object_notify (G_OBJECT (stream), "is-virtual"); return TRUE; } const char * gvc_mixer_stream_get_application_id (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->application_id; } gboolean gvc_mixer_stream_set_application_id (GvcMixerStream *stream, const char *application_id) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_free (stream->priv->application_id); stream->priv->application_id = g_strdup (application_id); g_object_notify (G_OBJECT (stream), "application-id"); return TRUE; } static void on_channel_map_volume_changed (GvcChannelMap *channel_map, gboolean set, GvcMixerStream *stream) { if (set == TRUE) gvc_mixer_stream_push_volume (stream); g_object_notify (G_OBJECT (stream), "volume"); } static gboolean gvc_mixer_stream_set_channel_map (GvcMixerStream *stream, GvcChannelMap *channel_map) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); if (channel_map != NULL) { g_object_ref (channel_map); } if (stream->priv->channel_map != NULL) { g_signal_handlers_disconnect_by_func (stream->priv->channel_map, on_channel_map_volume_changed, stream); g_object_unref (stream->priv->channel_map); } stream->priv->channel_map = channel_map; if (stream->priv->channel_map != NULL) { g_signal_connect (stream->priv->channel_map, "volume-changed", G_CALLBACK (on_channel_map_volume_changed), stream); g_object_notify (G_OBJECT (stream), "channel-map"); } return TRUE; } const char * gvc_mixer_stream_get_icon_name (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->icon_name; } const char * gvc_mixer_stream_get_sysfs_path (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->sysfs_path; } /** * gvc_mixer_stream_get_gicon: * @stream: a #GvcMixerStream * * Returns: (transfer full): a new #GIcon */ GIcon * gvc_mixer_stream_get_gicon (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); if (stream->priv->icon_name == NULL) return NULL; return g_themed_icon_new_with_default_fallbacks (stream->priv->icon_name); } gboolean gvc_mixer_stream_set_icon_name (GvcMixerStream *stream, const char *icon_name) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_free (stream->priv->icon_name); stream->priv->icon_name = g_strdup (icon_name); g_object_notify (G_OBJECT (stream), "icon-name"); return TRUE; } gboolean gvc_mixer_stream_set_sysfs_path (GvcMixerStream *stream, const char *sysfs_path) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_free (stream->priv->sysfs_path); stream->priv->sysfs_path = g_strdup (sysfs_path); g_object_notify (G_OBJECT (stream), "sysfs-path"); return TRUE; } /** * gvc_mixer_stream_get_base_volume: * * @stream: * * Returns: (type guint32) (transfer none): */ pa_volume_t gvc_mixer_stream_get_base_volume (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0); return stream->priv->base_volume; } /** * gvc_mixer_stream_set_base_volume: * * @stream: * @base_volume: (type guint32): * * Returns: */ gboolean gvc_mixer_stream_set_base_volume (GvcMixerStream *stream, pa_volume_t base_volume) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); stream->priv->base_volume = base_volume; return TRUE; } const GvcMixerStreamPort * gvc_mixer_stream_get_port (GvcMixerStream *stream) { GList *l; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); g_return_val_if_fail (stream->priv->ports != NULL, NULL); for (l = stream->priv->ports; l != NULL; l = l->next) { GvcMixerStreamPort *p = l->data; if (g_strcmp0 (stream->priv->port, p->port) == 0) { return p; } } g_assert_not_reached (); return NULL; } gboolean gvc_mixer_stream_set_port (GvcMixerStream *stream, const char *port) { GList *l; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_return_val_if_fail (stream->priv->ports != NULL, FALSE); g_free (stream->priv->port); stream->priv->port = g_strdup (port); g_free (stream->priv->human_port); stream->priv->human_port = NULL; for (l = stream->priv->ports; l != NULL; l = l->next) { GvcMixerStreamPort *p = l->data; if (g_str_equal (stream->priv->port, p->port)) { stream->priv->human_port = g_strdup (p->human_port); break; } } g_object_notify (G_OBJECT (stream), "port"); return TRUE; } gboolean gvc_mixer_stream_change_port (GvcMixerStream *stream, const char *port) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); return GVC_MIXER_STREAM_GET_CLASS (stream)->change_port (stream, port); } /** * gvc_mixer_stream_get_ports: * * Return value: (transfer none) (element-type GvcMixerStreamPort): */ const GList * gvc_mixer_stream_get_ports (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL); return stream->priv->ports; } static int sort_ports (GvcMixerStreamPort *a, GvcMixerStreamPort *b) { if (a->priority == b->priority) return 0; if (a->priority > b->priority) return 1; return -1; } /** * gvc_mixer_stream_set_ports: * @ports: (transfer full) (element-type GvcMixerStreamPort): */ gboolean gvc_mixer_stream_set_ports (GvcMixerStream *stream, GList *ports) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); g_return_val_if_fail (stream->priv->ports == NULL, FALSE); stream->priv->ports = g_list_sort (ports, (GCompareFunc) sort_ports); return TRUE; } gint gvc_mixer_stream_get_card_index (GvcMixerStream *stream) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), PA_INVALID_INDEX); return stream->priv->card_index; } gboolean gvc_mixer_stream_set_card_index (GvcMixerStream *stream, gint card_index) { g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); stream->priv->card_index = card_index; g_object_notify (G_OBJECT (stream), "card-index"); return TRUE; } static void gvc_mixer_stream_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcMixerStream *self = GVC_MIXER_STREAM (object); switch (prop_id) { case PROP_PA_CONTEXT: self->priv->pa_context = g_value_get_pointer (value); break; case PROP_INDEX: self->priv->index = g_value_get_ulong (value); break; case PROP_ID: self->priv->id = g_value_get_ulong (value); break; case PROP_CHANNEL_MAP: gvc_mixer_stream_set_channel_map (self, g_value_get_object (value)); break; case PROP_NAME: gvc_mixer_stream_set_name (self, g_value_get_string (value)); break; case PROP_DESCRIPTION: gvc_mixer_stream_set_description (self, g_value_get_string (value)); break; case PROP_APPLICATION_ID: gvc_mixer_stream_set_application_id (self, g_value_get_string (value)); break; case PROP_ICON_NAME: gvc_mixer_stream_set_icon_name (self, g_value_get_string (value)); break; case PROP_SYSFS_PATH: gvc_mixer_stream_set_sysfs_path (self, g_value_get_string (value)); break; case PROP_VOLUME: gvc_mixer_stream_set_volume (self, g_value_get_ulong (value)); break; case PROP_DECIBEL: gvc_mixer_stream_set_decibel (self, g_value_get_double (value)); break; case PROP_IS_MUTED: gvc_mixer_stream_set_is_muted (self, g_value_get_boolean (value)); break; case PROP_IS_EVENT_STREAM: gvc_mixer_stream_set_is_event_stream (self, g_value_get_boolean (value)); break; case PROP_IS_VIRTUAL: gvc_mixer_stream_set_is_virtual (self, g_value_get_boolean (value)); break; case PROP_CAN_DECIBEL: gvc_mixer_stream_set_can_decibel (self, g_value_get_boolean (value)); break; case PROP_PORT: gvc_mixer_stream_set_port (self, g_value_get_string (value)); break; case PROP_CARD_INDEX: self->priv->card_index = g_value_get_long (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_mixer_stream_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcMixerStream *self = GVC_MIXER_STREAM (object); switch (prop_id) { case PROP_PA_CONTEXT: g_value_set_pointer (value, self->priv->pa_context); break; case PROP_INDEX: g_value_set_ulong (value, self->priv->index); break; case PROP_ID: g_value_set_ulong (value, self->priv->id); break; case PROP_CHANNEL_MAP: g_value_set_object (value, self->priv->channel_map); break; case PROP_NAME: g_value_set_string (value, self->priv->name); break; case PROP_DESCRIPTION: g_value_set_string (value, self->priv->description); break; case PROP_APPLICATION_ID: g_value_set_string (value, self->priv->application_id); break; case PROP_ICON_NAME: g_value_set_string (value, self->priv->icon_name); break; case PROP_SYSFS_PATH: g_value_set_string (value, self->priv->sysfs_path); break; case PROP_VOLUME: g_value_set_ulong (value, pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map))); break; case PROP_DECIBEL: g_value_set_double (value, pa_sw_volume_to_dB(pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map)))); break; case PROP_IS_MUTED: g_value_set_boolean (value, self->priv->is_muted); break; case PROP_IS_EVENT_STREAM: g_value_set_boolean (value, self->priv->is_event_stream); break; case PROP_IS_VIRTUAL: g_value_set_boolean (value, self->priv->is_virtual); break; case PROP_CAN_DECIBEL: g_value_set_boolean (value, self->priv->can_decibel); break; case PROP_PORT: g_value_set_string (value, self->priv->port); break; case PROP_CARD_INDEX: g_value_set_long (value, self->priv->card_index); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * gvc_mixer_stream_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerStream *self; object = G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_STREAM (object); self->priv->id = get_next_stream_serial (); return object; } static gboolean gvc_mixer_stream_real_change_port (GvcMixerStream *stream, const char *port) { return FALSE; } static gboolean gvc_mixer_stream_real_push_volume (GvcMixerStream *stream, gpointer *op) { return FALSE; } static gboolean gvc_mixer_stream_real_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { return FALSE; } gboolean gvc_mixer_stream_push_volume (GvcMixerStream *stream) { pa_operation *op; gboolean ret; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); if (stream->priv->is_event_stream != FALSE) return TRUE; g_debug ("Pushing new volume to stream '%s' (%s)", stream->priv->description, stream->priv->name); ret = GVC_MIXER_STREAM_GET_CLASS (stream)->push_volume (stream, (gpointer *) &op); if (ret) { if (stream->priv->change_volume_op != NULL) pa_operation_unref (stream->priv->change_volume_op); stream->priv->change_volume_op = op; } return ret; } gboolean gvc_mixer_stream_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { gboolean ret; g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); ret = GVC_MIXER_STREAM_GET_CLASS (stream)->change_is_muted (stream, is_muted); return ret; } gboolean gvc_mixer_stream_is_running (GvcMixerStream *stream) { if (stream->priv->change_volume_op == NULL) return FALSE; if ((pa_operation_get_state(stream->priv->change_volume_op) == PA_OPERATION_RUNNING)) return TRUE; pa_operation_unref(stream->priv->change_volume_op); stream->priv->change_volume_op = NULL; return FALSE; } static void gvc_mixer_stream_class_init (GvcMixerStreamClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->constructor = gvc_mixer_stream_constructor; gobject_class->finalize = gvc_mixer_stream_finalize; gobject_class->set_property = gvc_mixer_stream_set_property; gobject_class->get_property = gvc_mixer_stream_get_property; klass->push_volume = gvc_mixer_stream_real_push_volume; klass->change_port = gvc_mixer_stream_real_change_port; klass->change_is_muted = gvc_mixer_stream_real_change_is_muted; g_object_class_install_property (gobject_class, PROP_INDEX, g_param_spec_ulong ("index", "Index", "The index for this stream", 0, G_MAXULONG, 0, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_ID, g_param_spec_ulong ("id", "id", "The id for this stream", 0, G_MAXULONG, 0, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_CHANNEL_MAP, g_param_spec_object ("channel-map", "channel map", "The channel map for this stream", GVC_TYPE_CHANNEL_MAP, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_PA_CONTEXT, g_param_spec_pointer ("pa-context", "PulseAudio context", "The PulseAudio context for this stream", G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_VOLUME, g_param_spec_ulong ("volume", "Volume", "The volume for this stream", 0, G_MAXULONG, 0, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_DECIBEL, g_param_spec_double ("decibel", "Decibel", "The decibel level for this stream", -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_NAME, g_param_spec_string ("name", "Name", "Name to display for this stream", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_DESCRIPTION, g_param_spec_string ("description", "Description", "Description to display for this stream", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_APPLICATION_ID, g_param_spec_string ("application-id", "Application identifier", "Application identifier for this stream", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_ICON_NAME, g_param_spec_string ("icon-name", "Icon Name", "Name of icon to display for this stream", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_SYSFS_PATH, g_param_spec_string ("sysfs-path", "Sysfs path", "Sysfs path for the device associated with this stream", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_IS_MUTED, g_param_spec_boolean ("is-muted", "is muted", "Whether stream is muted", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_CAN_DECIBEL, g_param_spec_boolean ("can-decibel", "can decibel", "Whether stream volume can be converted to decibel units", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_IS_EVENT_STREAM, g_param_spec_boolean ("is-event-stream", "is event stream", "Whether stream's role is to play an event", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_IS_VIRTUAL, g_param_spec_boolean ("is-virtual", "is virtual stream", "Whether the stream is virtual", FALSE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_PORT, g_param_spec_string ("port", "Port", "The name of the current port for this stream", NULL, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_CARD_INDEX, g_param_spec_long ("card-index", "Card index", "The index of the card for this stream", PA_INVALID_INDEX, G_MAXLONG, PA_INVALID_INDEX, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (GvcMixerStreamPrivate)); } static void gvc_mixer_stream_init (GvcMixerStream *stream) { stream->priv = GVC_MIXER_STREAM_GET_PRIVATE (stream); } static void free_port (GvcMixerStreamPort *p) { g_free (p->port); g_free (p->human_port); g_free (p); } static void gvc_mixer_stream_finalize (GObject *object) { GvcMixerStream *mixer_stream; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_STREAM (object)); mixer_stream = GVC_MIXER_STREAM (object); g_return_if_fail (mixer_stream->priv != NULL); g_object_unref (mixer_stream->priv->channel_map); mixer_stream->priv->channel_map = NULL; g_free (mixer_stream->priv->name); mixer_stream->priv->name = NULL; g_free (mixer_stream->priv->description); mixer_stream->priv->description = NULL; g_free (mixer_stream->priv->application_id); mixer_stream->priv->application_id = NULL; g_free (mixer_stream->priv->icon_name); mixer_stream->priv->icon_name = NULL; g_free (mixer_stream->priv->sysfs_path); mixer_stream->priv->sysfs_path = NULL; g_free (mixer_stream->priv->port); mixer_stream->priv->port = NULL; g_free (mixer_stream->priv->human_port); mixer_stream->priv->human_port = NULL; g_list_foreach (mixer_stream->priv->ports, (GFunc) free_port, NULL); g_list_free (mixer_stream->priv->ports); mixer_stream->priv->ports = NULL; if (mixer_stream->priv->change_volume_op) { pa_operation_unref(mixer_stream->priv->change_volume_op); mixer_stream->priv->change_volume_op = NULL; } G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->finalize (object); } cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-channel-map-private.h0000664000175000017500000000306112625665665030026 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. * */ #ifndef __GVC_CHANNEL_MAP_PRIVATE_H #define __GVC_CHANNEL_MAP_PRIVATE_H #include #include G_BEGIN_DECLS GvcChannelMap * gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *map); const pa_channel_map * gvc_channel_map_get_pa_channel_map (const GvcChannelMap *map); void gvc_channel_map_volume_changed (GvcChannelMap *map, const pa_cvolume *cv, gboolean set); const pa_cvolume * gvc_channel_map_get_cvolume (const GvcChannelMap *map); G_END_DECLS #endif /* __GVC_CHANNEL_MAP_PRIVATE_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-stream.h0000664000175000017500000001533412625665665026616 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. * */ #ifndef __GVC_MIXER_STREAM_H #define __GVC_MIXER_STREAM_H #include #include "gvc-pulseaudio-fake.h" #include "gvc-channel-map.h" #include G_BEGIN_DECLS #define GVC_TYPE_MIXER_STREAM (gvc_mixer_stream_get_type ()) #define GVC_MIXER_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStream)) #define GVC_MIXER_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_STREAM, GvcMixerStreamClass)) #define GVC_IS_MIXER_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_STREAM)) #define GVC_IS_MIXER_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_STREAM)) #define GVC_MIXER_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamClass)) typedef struct GvcMixerStreamPrivate GvcMixerStreamPrivate; typedef struct { GObject parent; GvcMixerStreamPrivate *priv; } GvcMixerStream; typedef struct { GObjectClass parent_class; /* vtable */ gboolean (*push_volume) (GvcMixerStream *stream, gpointer *operation); gboolean (*change_is_muted) (GvcMixerStream *stream, gboolean is_muted); gboolean (*change_port) (GvcMixerStream *stream, const char *port); } GvcMixerStreamClass; typedef struct { char *port; char *human_port; guint priority; } GvcMixerStreamPort; GType gvc_mixer_stream_get_type (void); guint gvc_mixer_stream_get_index (GvcMixerStream *stream); guint gvc_mixer_stream_get_id (GvcMixerStream *stream); const GvcChannelMap *gvc_mixer_stream_get_channel_map(GvcMixerStream *stream); const GvcMixerStreamPort *gvc_mixer_stream_get_port (GvcMixerStream *stream); const GList * gvc_mixer_stream_get_ports (GvcMixerStream *stream); gboolean gvc_mixer_stream_change_port (GvcMixerStream *stream, const char *port); pa_volume_t gvc_mixer_stream_get_volume (GvcMixerStream *stream); gdouble gvc_mixer_stream_get_decibel (GvcMixerStream *stream); gboolean gvc_mixer_stream_push_volume (GvcMixerStream *stream); pa_volume_t gvc_mixer_stream_get_base_volume (GvcMixerStream *stream); gboolean gvc_mixer_stream_get_is_muted (GvcMixerStream *stream); gboolean gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream); gboolean gvc_mixer_stream_change_is_muted (GvcMixerStream *stream, gboolean is_muted); gboolean gvc_mixer_stream_is_running (GvcMixerStream *stream); const char * gvc_mixer_stream_get_name (GvcMixerStream *stream); const char * gvc_mixer_stream_get_icon_name (GvcMixerStream *stream); const char * gvc_mixer_stream_get_sysfs_path (GvcMixerStream *stream); GIcon * gvc_mixer_stream_get_gicon (GvcMixerStream *stream); const char * gvc_mixer_stream_get_description (GvcMixerStream *stream); const char * gvc_mixer_stream_get_application_id (GvcMixerStream *stream); gboolean gvc_mixer_stream_is_event_stream (GvcMixerStream *stream); gboolean gvc_mixer_stream_is_virtual (GvcMixerStream *stream); gint gvc_mixer_stream_get_card_index (GvcMixerStream *stream); /* private */ gboolean gvc_mixer_stream_set_volume (GvcMixerStream *stream, pa_volume_t volume); gboolean gvc_mixer_stream_set_decibel (GvcMixerStream *stream, gdouble db); gboolean gvc_mixer_stream_set_is_muted (GvcMixerStream *stream, gboolean is_muted); gboolean gvc_mixer_stream_set_can_decibel (GvcMixerStream *stream, gboolean can_decibel); gboolean gvc_mixer_stream_set_name (GvcMixerStream *stream, const char *name); gboolean gvc_mixer_stream_set_description (GvcMixerStream *stream, const char *description); gboolean gvc_mixer_stream_set_icon_name (GvcMixerStream *stream, const char *name); gboolean gvc_mixer_stream_set_sysfs_path (GvcMixerStream *stream, const char *sysfs_path); gboolean gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream, gboolean is_event_stream); gboolean gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream, gboolean is_event_stream); gboolean gvc_mixer_stream_set_application_id (GvcMixerStream *stream, const char *application_id); gboolean gvc_mixer_stream_set_base_volume (GvcMixerStream *stream, pa_volume_t base_volume); gboolean gvc_mixer_stream_set_port (GvcMixerStream *stream, const char *port); gboolean gvc_mixer_stream_set_ports (GvcMixerStream *stream, GList *ports); gboolean gvc_mixer_stream_set_card_index (GvcMixerStream *stream, gint card_index); G_END_DECLS #endif /* __GVC_MIXER_STREAM_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-stream-private.h0000664000175000017500000000214312625665665030260 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. * */ #ifndef __GVC_MIXER_STREAM_PRIVATE_H #define __GVC_MIXER_STREAM_PRIVATE_H #include #include "gvc-channel-map.h" G_BEGIN_DECLS pa_context * gvc_mixer_stream_get_pa_context (GvcMixerStream *stream); G_END_DECLS #endif /* __GVC_MIXER_STREAM_PRIVATE_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.c0000664000175000017500000001643112625665665027375 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 "gvc-mixer-event-role.h" #include "gvc-mixer-stream-private.h" #include "gvc-channel-map-private.h" #define GVC_MIXER_EVENT_ROLE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRolePrivate)) struct GvcMixerEventRolePrivate { char *device; }; enum { PROP_0, PROP_DEVICE }; static void gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass); static void gvc_mixer_event_role_init (GvcMixerEventRole *mixer_event_role); static void gvc_mixer_event_role_finalize (GObject *object); G_DEFINE_TYPE (GvcMixerEventRole, gvc_mixer_event_role, GVC_TYPE_MIXER_STREAM) static gboolean update_settings (GvcMixerEventRole *role, gboolean is_muted, gpointer *op) { pa_operation *o; const GvcChannelMap *map; pa_context *context; pa_ext_stream_restore_info info; map = gvc_mixer_stream_get_channel_map (GVC_MIXER_STREAM(role)); info.volume = *gvc_channel_map_get_cvolume(map); info.name = "sink-input-by-media-role:event"; info.channel_map = *gvc_channel_map_get_pa_channel_map(map); info.device = role->priv->device; info.mute = is_muted; context = gvc_mixer_stream_get_pa_context (GVC_MIXER_STREAM (role)); o = pa_ext_stream_restore_write (context, PA_UPDATE_REPLACE, &info, 1, TRUE, NULL, NULL); if (o == NULL) { g_warning ("pa_ext_stream_restore_write() failed"); return FALSE; } if (op != NULL) *op = o; return TRUE; } static gboolean gvc_mixer_event_role_push_volume (GvcMixerStream *stream, gpointer *op) { return update_settings (GVC_MIXER_EVENT_ROLE (stream), gvc_mixer_stream_get_is_muted (stream), op); } static gboolean gvc_mixer_event_role_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { return update_settings (GVC_MIXER_EVENT_ROLE (stream), is_muted, NULL); } static gboolean gvc_mixer_event_role_set_device (GvcMixerEventRole *role, const char *device) { g_return_val_if_fail (GVC_IS_MIXER_EVENT_ROLE (role), FALSE); g_free (role->priv->device); role->priv->device = g_strdup (device); g_object_notify (G_OBJECT (role), "device"); return TRUE; } static void gvc_mixer_event_role_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object); switch (prop_id) { case PROP_DEVICE: gvc_mixer_event_role_set_device (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_mixer_event_role_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object); switch (prop_id) { case PROP_DEVICE: g_value_set_string (value, self->priv->device); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass); object_class->finalize = gvc_mixer_event_role_finalize; object_class->set_property = gvc_mixer_event_role_set_property; object_class->get_property = gvc_mixer_event_role_get_property; stream_class->push_volume = gvc_mixer_event_role_push_volume; stream_class->change_is_muted = gvc_mixer_event_role_change_is_muted; g_object_class_install_property (object_class, PROP_DEVICE, g_param_spec_string ("device", "Device", "Device", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (GvcMixerEventRolePrivate)); } static void gvc_mixer_event_role_init (GvcMixerEventRole *event_role) { event_role->priv = GVC_MIXER_EVENT_ROLE_GET_PRIVATE (event_role); } static void gvc_mixer_event_role_finalize (GObject *object) { GvcMixerEventRole *mixer_event_role; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_EVENT_ROLE (object)); mixer_event_role = GVC_MIXER_EVENT_ROLE (object); g_return_if_fail (mixer_event_role->priv != NULL); g_free (mixer_event_role->priv->device); G_OBJECT_CLASS (gvc_mixer_event_role_parent_class)->finalize (object); } /** * gvc_mixer_event_role_new: (skip) * * @context: * @index: * @channel_map: * * Returns: */ GvcMixerStream * gvc_mixer_event_role_new (pa_context *context, const char *device, GvcChannelMap *channel_map) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_EVENT_ROLE, "pa-context", context, "index", 0, "device", device, "channel-map", channel_map, NULL); return GVC_MIXER_STREAM (object); } cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-card.h0000664000175000017500000000637012625665665026234 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008-2009 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 __GVC_MIXER_CARD_H #define __GVC_MIXER_CARD_H #include G_BEGIN_DECLS #define GVC_TYPE_MIXER_CARD (gvc_mixer_card_get_type ()) #define GVC_MIXER_CARD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_CARD, GvcMixerCard)) #define GVC_MIXER_CARD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_CARD, GvcMixerCardClass)) #define GVC_IS_MIXER_CARD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_CARD)) #define GVC_IS_MIXER_CARD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_CARD)) #define GVC_MIXER_CARD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardClass)) typedef struct GvcMixerCardPrivate GvcMixerCardPrivate; typedef struct { GObject parent; GvcMixerCardPrivate *priv; } GvcMixerCard; typedef struct { GObjectClass parent_class; /* vtable */ } GvcMixerCardClass; typedef struct { char *profile; char *human_profile; char *status; guint priority; guint n_sinks, n_sources; } GvcMixerCardProfile; GType gvc_mixer_card_get_type (void); guint gvc_mixer_card_get_id (GvcMixerCard *card); guint gvc_mixer_card_get_index (GvcMixerCard *card); const char * gvc_mixer_card_get_name (GvcMixerCard *card); const char * gvc_mixer_card_get_icon_name (GvcMixerCard *card); GvcMixerCardProfile * gvc_mixer_card_get_profile (GvcMixerCard *card); const GList * gvc_mixer_card_get_profiles (GvcMixerCard *card); gboolean gvc_mixer_card_change_profile (GvcMixerCard *card, const char *profile); /* private */ gboolean gvc_mixer_card_set_name (GvcMixerCard *card, const char *name); gboolean gvc_mixer_card_set_icon_name (GvcMixerCard *card, const char *name); gboolean gvc_mixer_card_set_profile (GvcMixerCard *card, const char *profile); gboolean gvc_mixer_card_set_profiles (GvcMixerCard *card, GList *profiles); G_END_DECLS #endif /* __GVC_MIXER_CARD_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-control.c0000664000175000017500000022445512625665665027004 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006-2008 Lennart Poettering * Copyright (C) 2008 Sjoerd Simons * 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 "gvc-mixer-control.h" #include "gvc-mixer-sink.h" #include "gvc-mixer-source.h" #include "gvc-mixer-sink-input.h" #include "gvc-mixer-source-output.h" #include "gvc-mixer-event-role.h" #include "gvc-mixer-card.h" #include "gvc-mixer-card-private.h" #include "gvc-channel-map-private.h" #include "gvc-mixer-control-private.h" #define GVC_MIXER_CONTROL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlPrivate)) #define RECONNECT_DELAY 5 enum { PROP_0, PROP_NAME }; struct GvcMixerControlPrivate { pa_glib_mainloop *pa_mainloop; pa_mainloop_api *pa_api; pa_context *pa_context; int n_outstanding; guint reconnect_id; char *name; gboolean default_sink_is_set; guint default_sink_id; char *default_sink_name; gboolean default_source_is_set; guint default_source_id; char *default_source_name; gboolean event_sink_input_is_set; guint event_sink_input_id; GHashTable *all_streams; GHashTable *sinks; /* fixed outputs */ GHashTable *sources; /* fixed inputs */ GHashTable *sink_inputs; /* routable output streams */ GHashTable *source_outputs; /* routable input streams */ GHashTable *clients; GHashTable *cards; GvcMixerStream *new_default_stream; /* new default stream, used in gvc_mixer_control_set_default_sink () */ GvcMixerControlState state; }; enum { STATE_CHANGED, STREAM_ADDED, STREAM_REMOVED, CARD_ADDED, CARD_REMOVED, DEFAULT_SINK_CHANGED, DEFAULT_SOURCE_CHANGED, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0, }; static void gvc_mixer_control_class_init (GvcMixerControlClass *klass); static void gvc_mixer_control_init (GvcMixerControl *mixer_control); static void gvc_mixer_control_finalize (GObject *object); G_DEFINE_TYPE (GvcMixerControl, gvc_mixer_control, G_TYPE_OBJECT) pa_context * gvc_mixer_control_get_pa_context (GvcMixerControl *control) { g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); return control->priv->pa_context; } /** * gvc_mixer_control_get_event_sink_input: * * @control: * * Returns: (transfer none): */ GvcMixerStream * gvc_mixer_control_get_event_sink_input (GvcMixerControl *control) { GvcMixerStream *stream; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); stream = g_hash_table_lookup (control->priv->all_streams, GUINT_TO_POINTER (control->priv->event_sink_input_id)); return stream; } static void gvc_mixer_control_stream_restore_cb (pa_context *c, const pa_ext_stream_restore_info *info, int eol, void *userdata) { pa_operation *o; GvcMixerControl *control = (GvcMixerControl *) userdata; pa_ext_stream_restore_info new_info; if (eol || control->priv->new_default_stream == NULL) return; new_info.name = info->name; new_info.channel_map = info->channel_map; new_info.volume = info->volume; new_info.mute = info->mute; new_info.device = gvc_mixer_stream_get_name (control->priv->new_default_stream); o = pa_ext_stream_restore_write (control->priv->pa_context, PA_UPDATE_REPLACE, &new_info, 1, TRUE, NULL, NULL); if (o == NULL) { g_warning ("pa_ext_stream_restore_write() failed: %s", pa_strerror (pa_context_errno (control->priv->pa_context))); return; } g_debug ("Changed default device for %s to %s", info->name, info->device); pa_operation_unref (o); } gboolean gvc_mixer_control_set_default_sink (GvcMixerControl *control, GvcMixerStream *stream) { pa_operation *o; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); o = pa_context_set_default_sink (control->priv->pa_context, gvc_mixer_stream_get_name (stream), NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_default_sink() failed: %s", pa_strerror (pa_context_errno (control->priv->pa_context))); return FALSE; } pa_operation_unref (o); control->priv->new_default_stream = stream; g_object_add_weak_pointer (G_OBJECT (stream), (gpointer *) &control->priv->new_default_stream); o = pa_ext_stream_restore_read (control->priv->pa_context, gvc_mixer_control_stream_restore_cb, control); if (o == NULL) { g_warning ("pa_ext_stream_restore_read() failed: %s", pa_strerror (pa_context_errno (control->priv->pa_context))); return FALSE; } pa_operation_unref (o); return TRUE; } gboolean gvc_mixer_control_set_default_source (GvcMixerControl *control, GvcMixerStream *stream) { pa_operation *o; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE); o = pa_context_set_default_source (control->priv->pa_context, gvc_mixer_stream_get_name (stream), NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_default_source() failed"); return FALSE; } pa_operation_unref (o); return TRUE; } /** * gvc_mixer_control_get_default_sink: * * @control: * * Returns: (transfer none): */ GvcMixerStream * gvc_mixer_control_get_default_sink (GvcMixerControl *control) { GvcMixerStream *stream; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); if (control->priv->default_sink_is_set) { stream = g_hash_table_lookup (control->priv->all_streams, GUINT_TO_POINTER (control->priv->default_sink_id)); } else { stream = NULL; } return stream; } /** * gvc_mixer_control_get_default_source: * * @control: * * Returns: (transfer none): */ GvcMixerStream * gvc_mixer_control_get_default_source (GvcMixerControl *control) { GvcMixerStream *stream; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); if (control->priv->default_source_is_set) { stream = g_hash_table_lookup (control->priv->all_streams, GUINT_TO_POINTER (control->priv->default_source_id)); } else { stream = NULL; } return stream; } static gpointer gvc_mixer_control_lookup_id (GHashTable *hash_table, guint id) { return g_hash_table_lookup (hash_table, GUINT_TO_POINTER (id)); } /** * gvc_mixer_control_lookup_stream_id: * * @control: * @id: * * Returns: (transfer none): */ GvcMixerStream * gvc_mixer_control_lookup_stream_id (GvcMixerControl *control, guint id) { g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); return gvc_mixer_control_lookup_id (control->priv->all_streams, id); } /** * gvc_mixer_control_lookup_card_id: * * @control: * @id: * * Returns: (transfer none): */ GvcMixerCard * gvc_mixer_control_lookup_card_id (GvcMixerControl *control, guint id) { g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); return gvc_mixer_control_lookup_id (control->priv->cards, id); } static void listify_hash_values_hfunc (gpointer key, gpointer value, gpointer user_data) { GSList **list = user_data; *list = g_slist_prepend (*list, value); } static int gvc_name_collate (const char *namea, const char *nameb) { if (nameb == NULL && namea == NULL) return 0; if (nameb == NULL) return 1; if (namea == NULL) return -1; return g_utf8_collate (namea, nameb); } static int gvc_card_collate (GvcMixerCard *a, GvcMixerCard *b) { const char *namea; const char *nameb; g_return_val_if_fail (a == NULL || GVC_IS_MIXER_CARD (a), 0); g_return_val_if_fail (b == NULL || GVC_IS_MIXER_CARD (b), 0); namea = gvc_mixer_card_get_name (a); nameb = gvc_mixer_card_get_name (b); return gvc_name_collate (namea, nameb); } /** * gvc_mixer_control_get_cards: * * @control: * * Returns: (transfer container) (element-type Gvc.MixerCard): */ GSList * gvc_mixer_control_get_cards (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->cards, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_card_collate); } static int gvc_stream_collate (GvcMixerStream *a, GvcMixerStream *b) { const char *namea; const char *nameb; g_return_val_if_fail (a == NULL || GVC_IS_MIXER_STREAM (a), 0); g_return_val_if_fail (b == NULL || GVC_IS_MIXER_STREAM (b), 0); namea = gvc_mixer_stream_get_name (a); nameb = gvc_mixer_stream_get_name (b); return gvc_name_collate (namea, nameb); } /** * gvc_mixer_control_get_streams: * * @control: * * Returns: (transfer container) (element-type Gvc.MixerStream): */ GSList * gvc_mixer_control_get_streams (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->all_streams, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); } /** * gvc_mixer_control_get_sinks: * * @control: * * Returns: (transfer container) (element-type Gvc.MixerSink): */ GSList * gvc_mixer_control_get_sinks (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->sinks, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); } /** * gvc_mixer_control_get_sources: * * @control: * * Returns: (transfer container) (element-type Gvc.MixerSource): */ GSList * gvc_mixer_control_get_sources (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->sources, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); } /** * gvc_mixer_control_get_sink_inputs: * * @control: * * Returns: (transfer container) (element-type Gvc.MixerSinkInput): */ GSList * gvc_mixer_control_get_sink_inputs (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->sink_inputs, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); } /** * gvc_mixer_control_get_source_outputs: * * @control: * * Returns: (transfer container) (element-type Gvc.MixerSourceOutput): */ GSList * gvc_mixer_control_get_source_outputs (GvcMixerControl *control) { GSList *retval; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL); retval = NULL; g_hash_table_foreach (control->priv->source_outputs, listify_hash_values_hfunc, &retval); return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate); } static void dec_outstanding (GvcMixerControl *control) { if (control->priv->n_outstanding <= 0) { return; } if (--control->priv->n_outstanding <= 0) { control->priv->state = GVC_STATE_READY; g_signal_emit (G_OBJECT (control), signals[STATE_CHANGED], 0, GVC_STATE_READY); } } GvcMixerControlState gvc_mixer_control_get_state (GvcMixerControl *control) { g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); return control->priv->state; } static void _set_default_source (GvcMixerControl *control, GvcMixerStream *stream) { guint new_id; if (stream == NULL) { control->priv->default_source_id = 0; control->priv->default_source_is_set = FALSE; g_signal_emit (control, signals[DEFAULT_SOURCE_CHANGED], 0, PA_INVALID_INDEX); return; } new_id = gvc_mixer_stream_get_id (stream); if (control->priv->default_source_id != new_id) { control->priv->default_source_id = new_id; control->priv->default_source_is_set = TRUE; g_signal_emit (control, signals[DEFAULT_SOURCE_CHANGED], 0, new_id); } } static void _set_default_sink (GvcMixerControl *control, GvcMixerStream *stream) { guint new_id; if (stream == NULL) { /* Don't tell front-ends about an unset default * sink if it's already unset */ if (control->priv->default_sink_is_set == FALSE) return; control->priv->default_sink_id = 0; control->priv->default_sink_is_set = FALSE; g_signal_emit (control, signals[DEFAULT_SINK_CHANGED], 0, PA_INVALID_INDEX); return; } new_id = gvc_mixer_stream_get_id (stream); if (control->priv->default_sink_id != new_id) { control->priv->default_sink_id = new_id; control->priv->default_sink_is_set = TRUE; g_signal_emit (control, signals[DEFAULT_SINK_CHANGED], 0, new_id); } } static gboolean _stream_has_name (gpointer key, GvcMixerStream *stream, const char *name) { const char *t_name; t_name = gvc_mixer_stream_get_name (stream); if (t_name != NULL && name != NULL && strcmp (t_name, name) == 0) { return TRUE; } return FALSE; } static GvcMixerStream * find_stream_for_name (GvcMixerControl *control, const char *name) { GvcMixerStream *stream; stream = g_hash_table_find (control->priv->all_streams, (GHRFunc)_stream_has_name, (char *)name); return stream; } static void update_default_source_from_name (GvcMixerControl *control, const char *name) { gboolean changed = FALSE; if ((control->priv->default_source_name == NULL && name != NULL) || (control->priv->default_source_name != NULL && name == NULL) || (name != NULL && strcmp (control->priv->default_source_name, name) != 0)) { changed = TRUE; } if (changed) { GvcMixerStream *stream; g_free (control->priv->default_source_name); control->priv->default_source_name = g_strdup (name); stream = find_stream_for_name (control, name); _set_default_source (control, stream); } } static void update_default_sink_from_name (GvcMixerControl *control, const char *name) { gboolean changed = FALSE; if ((control->priv->default_sink_name == NULL && name != NULL) || (control->priv->default_sink_name != NULL && name == NULL) || (name != NULL && strcmp (control->priv->default_sink_name, name) != 0)) { changed = TRUE; } if (changed) { GvcMixerStream *stream; g_free (control->priv->default_sink_name); control->priv->default_sink_name = g_strdup (name); stream = find_stream_for_name (control, name); _set_default_sink (control, stream); } } static void update_server (GvcMixerControl *control, const pa_server_info *info) { if (info->default_source_name != NULL) { update_default_source_from_name (control, info->default_source_name); } if (info->default_sink_name != NULL) { update_default_sink_from_name (control, info->default_sink_name); } } static void remove_stream (GvcMixerControl *control, GvcMixerStream *stream) { guint id; g_object_ref (stream); id = gvc_mixer_stream_get_id (stream); if (id == control->priv->default_sink_id) { _set_default_sink (control, NULL); } else if (id == control->priv->default_source_id) { _set_default_source (control, NULL); } g_hash_table_remove (control->priv->all_streams, GUINT_TO_POINTER (id)); g_signal_emit (G_OBJECT (control), signals[STREAM_REMOVED], 0, gvc_mixer_stream_get_id (stream)); g_object_unref (stream); } static void add_stream (GvcMixerControl *control, GvcMixerStream *stream) { g_hash_table_insert (control->priv->all_streams, GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)), stream); g_signal_emit (G_OBJECT (control), signals[STREAM_ADDED], 0, gvc_mixer_stream_get_id (stream)); } static void set_icon_name_from_proplist (GvcMixerStream *stream, pa_proplist *l, const char *default_icon_name) { const char *t; if ((t = pa_proplist_gets (l, PA_PROP_DEVICE_ICON_NAME))) { goto finish; } if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ICON_NAME))) { goto finish; } if ((t = pa_proplist_gets (l, PA_PROP_WINDOW_ICON_NAME))) { goto finish; } if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ICON_NAME))) { goto finish; } if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) { if (strcmp (t, "video") == 0 || strcmp (t, "phone") == 0) { goto finish; } if (strcmp (t, "music") == 0) { t = "audio"; goto finish; } if (strcmp (t, "game") == 0) { t = "applications-games"; goto finish; } if (strcmp (t, "event") == 0) { t = "dialog-information"; goto finish; } } t = default_icon_name; finish: gvc_mixer_stream_set_icon_name (stream, t); } static void update_sink (GvcMixerControl *control, const pa_sink_info *info) { GvcMixerStream *stream; gboolean is_new; pa_volume_t max_volume; GvcChannelMap *map; char map_buff[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_channel_map_snprint (map_buff, PA_CHANNEL_MAP_SNPRINT_MAX, &info->channel_map); #if 1 g_debug ("Updating sink: index=%u name='%s' description='%s' map='%s'", info->index, info->name, info->description, map_buff); #endif map = NULL; is_new = FALSE; stream = g_hash_table_lookup (control->priv->sinks, GUINT_TO_POINTER (info->index)); if (stream == NULL) { GList *list = NULL; guint i; map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); stream = gvc_mixer_sink_new (control->priv->pa_context, info->index, map); for (i = 0; i < info->n_ports; i++) { GvcMixerStreamPort *port; port = g_new0 (GvcMixerStreamPort, 1); port->port = g_strdup (info->ports[i]->name); port->human_port = g_strdup (info->ports[i]->description); port->priority = info->ports[i]->priority; list = g_list_prepend (list, port); } gvc_mixer_stream_set_ports (stream, list); g_object_unref (map); is_new = TRUE; } else if (gvc_mixer_stream_is_running (stream)) { /* Ignore events if volume changes are outstanding */ g_debug ("Ignoring event, volume changes are outstanding"); return; } max_volume = pa_cvolume_max (&info->volume); gvc_mixer_stream_set_name (stream, info->name); gvc_mixer_stream_set_card_index (stream, info->card); gvc_mixer_stream_set_description (stream, info->description); set_icon_name_from_proplist (stream, info->proplist, "audio-card"); gvc_mixer_stream_set_sysfs_path (stream, pa_proplist_gets (info->proplist, "sysfs.path")); gvc_mixer_stream_set_volume (stream, (guint)max_volume); gvc_mixer_stream_set_is_muted (stream, info->mute); gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SINK_DECIBEL_VOLUME)); gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume); if (info->active_port != NULL) gvc_mixer_stream_set_port (stream, info->active_port->name); if (is_new) { g_hash_table_insert (control->priv->sinks, GUINT_TO_POINTER (info->index), g_object_ref (stream)); add_stream (control, stream); } if (control->priv->default_sink_name != NULL && info->name != NULL && strcmp (control->priv->default_sink_name, info->name) == 0) { _set_default_sink (control, stream); } if (map == NULL) map = (GvcChannelMap *) gvc_mixer_stream_get_channel_map (stream); gvc_channel_map_volume_changed (map, &info->volume, FALSE); } static void update_source (GvcMixerControl *control, const pa_source_info *info) { GvcMixerStream *stream; gboolean is_new; pa_volume_t max_volume; #if 1 g_debug ("Updating source: index=%u name='%s' description='%s'", info->index, info->name, info->description); #endif /* completely ignore monitors, they're not real sources */ if (info->monitor_of_sink != PA_INVALID_INDEX) { return; } is_new = FALSE; stream = g_hash_table_lookup (control->priv->sources, GUINT_TO_POINTER (info->index)); if (stream == NULL) { GList *list = NULL; guint i; GvcChannelMap *map; map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); stream = gvc_mixer_source_new (control->priv->pa_context, info->index, map); for (i = 0; i < info->n_ports; i++) { GvcMixerStreamPort *port; port = g_new0 (GvcMixerStreamPort, 1); port->port = g_strdup (info->ports[i]->name); port->human_port = g_strdup (info->ports[i]->description); port->priority = info->ports[i]->priority; list = g_list_prepend (list, port); } gvc_mixer_stream_set_ports (stream, list); g_object_unref (map); is_new = TRUE; } else if (gvc_mixer_stream_is_running (stream)) { /* Ignore events if volume changes are outstanding */ g_debug ("Ignoring event, volume changes are outstanding"); return; } max_volume = pa_cvolume_max (&info->volume); gvc_mixer_stream_set_name (stream, info->name); gvc_mixer_stream_set_card_index (stream, info->card); gvc_mixer_stream_set_description (stream, info->description); set_icon_name_from_proplist (stream, info->proplist, "audio-input-microphone"); gvc_mixer_stream_set_volume (stream, (guint)max_volume); gvc_mixer_stream_set_is_muted (stream, info->mute); gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SOURCE_DECIBEL_VOLUME)); gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume); if (info->active_port != NULL) gvc_mixer_stream_set_port (stream, info->active_port->name); if (is_new) { g_hash_table_insert (control->priv->sources, GUINT_TO_POINTER (info->index), g_object_ref (stream)); add_stream (control, stream); } if (control->priv->default_source_name != NULL && info->name != NULL && strcmp (control->priv->default_source_name, info->name) == 0) { _set_default_source (control, stream); } } static void set_is_event_stream_from_proplist (GvcMixerStream *stream, pa_proplist *l) { const char *t; gboolean is_event_stream; is_event_stream = FALSE; if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) { if (g_str_equal (t, "event")) is_event_stream = TRUE; } gvc_mixer_stream_set_is_event_stream (stream, is_event_stream); } static void set_application_id_from_proplist (GvcMixerStream *stream, pa_proplist *l) { const char *t; if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ID))) { gvc_mixer_stream_set_application_id (stream, t); } } static void update_sink_input (GvcMixerControl *control, const pa_sink_input_info *info) { GvcMixerStream *stream; gboolean is_new; pa_volume_t max_volume; const char *name; #if 0 g_debug ("Updating sink input: index=%u name='%s' client=%u sink=%u", info->index, info->name, info->client, info->sink); #endif is_new = FALSE; stream = g_hash_table_lookup (control->priv->sink_inputs, GUINT_TO_POINTER (info->index)); if (stream == NULL) { GvcChannelMap *map; map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); stream = gvc_mixer_sink_input_new (control->priv->pa_context, info->index, map); g_object_unref (map); is_new = TRUE; } else if (gvc_mixer_stream_is_running (stream)) { /* Ignore events if volume changes are outstanding */ g_debug ("Ignoring event, volume changes are outstanding"); return; } max_volume = pa_cvolume_max (&info->volume); name = (const char *)g_hash_table_lookup (control->priv->clients, GUINT_TO_POINTER (info->client)); gvc_mixer_stream_set_name (stream, name); gvc_mixer_stream_set_description (stream, info->name); set_application_id_from_proplist (stream, info->proplist); set_is_event_stream_from_proplist (stream, info->proplist); set_icon_name_from_proplist (stream, info->proplist, "applications-multimedia"); gvc_mixer_stream_set_volume (stream, (guint)max_volume); gvc_mixer_stream_set_is_muted (stream, info->mute); gvc_mixer_stream_set_is_virtual (stream, info->client == PA_INVALID_INDEX); if (is_new) { g_hash_table_insert (control->priv->sink_inputs, GUINT_TO_POINTER (info->index), g_object_ref (stream)); add_stream (control, stream); } } static void update_source_output (GvcMixerControl *control, const pa_source_output_info *info) { GvcMixerStream *stream; gboolean is_new; const char *name; #if 1 g_debug ("Updating source output: index=%u name='%s' client=%u source=%u", info->index, info->name, info->client, info->source); #endif is_new = FALSE; stream = g_hash_table_lookup (control->priv->source_outputs, GUINT_TO_POINTER (info->index)); if (stream == NULL) { GvcChannelMap *map; map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map); stream = gvc_mixer_source_output_new (control->priv->pa_context, info->index, map); g_object_unref (map); is_new = TRUE; } name = (const char *)g_hash_table_lookup (control->priv->clients, GUINT_TO_POINTER (info->client)); gvc_mixer_stream_set_name (stream, name); gvc_mixer_stream_set_description (stream, info->name); set_application_id_from_proplist (stream, info->proplist); set_is_event_stream_from_proplist (stream, info->proplist); set_icon_name_from_proplist (stream, info->proplist, "audio-input-microphone"); if (is_new) { g_hash_table_insert (control->priv->source_outputs, GUINT_TO_POINTER (info->index), g_object_ref (stream)); add_stream (control, stream); } } static void update_client (GvcMixerControl *control, const pa_client_info *info) { #if 1 g_debug ("Updating client: index=%u name='%s'", info->index, info->name); #endif g_hash_table_insert (control->priv->clients, GUINT_TO_POINTER (info->index), g_strdup (info->name)); } static char * card_num_streams_to_status (guint sinks, guint sources) { char *sinks_str; char *sources_str; char *ret; if (sinks == 0 && sources == 0) { /* translators: * The device has been disabled */ return g_strdup (_("Disabled")); } if (sinks == 0) { sinks_str = NULL; } else { /* translators: * The number of sound outputs on a particular device */ sinks_str = g_strdup_printf (ngettext ("%u Output", "%u Outputs", sinks), sinks); } if (sources == 0) { sources_str = NULL; } else { /* translators: * The number of sound inputs on a particular device */ sources_str = g_strdup_printf (ngettext ("%u Input", "%u Inputs", sources), sources); } if (sources_str == NULL) return sinks_str; if (sinks_str == NULL) return sources_str; ret = g_strdup_printf ("%s / %s", sinks_str, sources_str); g_free (sinks_str); g_free (sources_str); return ret; } static void update_card (GvcMixerControl *control, const pa_card_info *info) { GvcMixerCard *card; gboolean is_new = FALSE; #if 1 guint i; const char *key; void *state; g_debug ("Udpating card %s (index: %u driver: %s):", info->name, info->index, info->driver); for (i = 0; i < info->n_profiles; i++) { struct pa_card_profile_info pi = info->profiles[i]; gboolean is_default; is_default = (g_strcmp0 (pi.name, info->active_profile->name) == 0); g_debug ("\tProfile '%s': %d sources %d sinks%s", pi.name, pi.n_sources, pi.n_sinks, is_default ? " (Current)" : ""); } state = NULL; key = pa_proplist_iterate (info->proplist, &state); while (key != NULL) { g_debug ("\tProperty: '%s' = '%s'", key, pa_proplist_gets (info->proplist, key)); key = pa_proplist_iterate (info->proplist, &state); } #endif card = g_hash_table_lookup (control->priv->cards, GUINT_TO_POINTER (info->index)); if (card == NULL) { GList *list = NULL; for (i = 0; i < info->n_profiles; i++) { struct pa_card_profile_info pi = info->profiles[i]; GvcMixerCardProfile *profile; profile = g_new0 (GvcMixerCardProfile, 1); profile->profile = g_strdup (pi.name); profile->human_profile = g_strdup (pi.description); profile->status = card_num_streams_to_status (pi.n_sinks, pi.n_sources); profile->n_sinks = pi.n_sinks; profile->n_sources = pi.n_sources; profile->priority = pi.priority; list = g_list_prepend (list, profile); } card = gvc_mixer_card_new (control->priv->pa_context, info->index); gvc_mixer_card_set_profiles (card, list); is_new = TRUE; } gvc_mixer_card_set_name (card, pa_proplist_gets (info->proplist, "device.description")); gvc_mixer_card_set_icon_name (card, pa_proplist_gets (info->proplist, "device.icon_name")); gvc_mixer_card_set_profile (card, info->active_profile->name); if (is_new) { g_hash_table_insert (control->priv->cards, GUINT_TO_POINTER (info->index), g_object_ref (card)); } g_signal_emit (G_OBJECT (control), signals[CARD_ADDED], 0, info->index); } static void _pa_context_get_sink_info_cb (pa_context *context, const pa_sink_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) { return; } g_warning ("Sink callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_sink (control, i); } static void _pa_context_get_source_info_cb (pa_context *context, const pa_source_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) { return; } g_warning ("Source callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_source (control, i); } static void _pa_context_get_sink_input_info_cb (pa_context *context, const pa_sink_input_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) { return; } g_warning ("Sink input callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_sink_input (control, i); } static void _pa_context_get_source_output_info_cb (pa_context *context, const pa_source_output_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) { return; } g_warning ("Source output callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_source_output (control, i); } static void _pa_context_get_client_info_cb (pa_context *context, const pa_client_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) { return; } g_warning ("Client callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_client (control, i); } static void _pa_context_get_card_info_by_index_cb (pa_context *context, const pa_card_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { if (pa_context_errno (context) == PA_ERR_NOENTITY) return; g_warning ("Card callback failure"); return; } if (eol > 0) { dec_outstanding (control); return; } update_card (control, i); } static void _pa_context_get_server_info_cb (pa_context *context, const pa_server_info *i, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (i == NULL) { g_warning ("Server info callback failure"); return; } update_server (control, i); dec_outstanding (control); } static void remove_event_role_stream (GvcMixerControl *control) { g_debug ("Removing event role"); } static void update_event_role_stream (GvcMixerControl *control, const pa_ext_stream_restore_info *info) { GvcMixerStream *stream; gboolean is_new; pa_volume_t max_volume; if (strcmp (info->name, "sink-input-by-media-role:event") != 0) { return; } #if 0 g_debug ("Updating event role: name='%s' device='%s'", info->name, info->device); #endif is_new = FALSE; if (!control->priv->event_sink_input_is_set) { pa_channel_map pa_map; GvcChannelMap *map; pa_map.channels = 1; pa_map.map[0] = PA_CHANNEL_POSITION_MONO; map = gvc_channel_map_new_from_pa_channel_map (&pa_map); stream = gvc_mixer_event_role_new (control->priv->pa_context, info->device, map); control->priv->event_sink_input_id = gvc_mixer_stream_get_id (stream); control->priv->event_sink_input_is_set = TRUE; is_new = TRUE; } else { stream = g_hash_table_lookup (control->priv->all_streams, GUINT_TO_POINTER (control->priv->event_sink_input_id)); } max_volume = pa_cvolume_max (&info->volume); gvc_mixer_stream_set_name (stream, _("System Sounds")); gvc_mixer_stream_set_icon_name (stream, "multimedia-volume-control"); gvc_mixer_stream_set_volume (stream, (guint)max_volume); gvc_mixer_stream_set_is_muted (stream, info->mute); if (is_new) { add_stream (control, stream); } } static void _pa_ext_stream_restore_read_cb (pa_context *context, const pa_ext_stream_restore_info *i, int eol, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); if (eol < 0) { g_debug ("Failed to initialized stream_restore extension: %s", pa_strerror (pa_context_errno (context))); remove_event_role_stream (control); return; } if (eol > 0) { dec_outstanding (control); /* If we don't have an event stream to restore, then * set one up with a default 100% volume */ if (!control->priv->event_sink_input_is_set) { pa_ext_stream_restore_info info; memset (&info, 0, sizeof(info)); info.name = "sink-input-by-media-role:event"; info.volume.channels = 1; info.volume.values[0] = PA_VOLUME_NORM; update_event_role_stream (control, &info); } return; } update_event_role_stream (control, i); } static void _pa_ext_stream_restore_subscribe_cb (pa_context *context, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); pa_operation *o; o = pa_ext_stream_restore_read (context, _pa_ext_stream_restore_read_cb, control); if (o == NULL) { g_warning ("pa_ext_stream_restore_read() failed"); return; } pa_operation_unref (o); } static void req_update_server_info (GvcMixerControl *control, int index) { pa_operation *o; o = pa_context_get_server_info (control->priv->pa_context, _pa_context_get_server_info_cb, control); if (o == NULL) { g_warning ("pa_context_get_server_info() failed"); return; } pa_operation_unref (o); } static void req_update_client_info (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_client_info_list (control->priv->pa_context, _pa_context_get_client_info_cb, control); } else { o = pa_context_get_client_info (control->priv->pa_context, index, _pa_context_get_client_info_cb, control); } if (o == NULL) { g_warning ("pa_context_client_info_list() failed"); return; } pa_operation_unref (o); } static void req_update_card (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_card_info_list (control->priv->pa_context, _pa_context_get_card_info_by_index_cb, control); } else { o = pa_context_get_card_info_by_index (control->priv->pa_context, index, _pa_context_get_card_info_by_index_cb, control); } if (o == NULL) { g_warning ("pa_context_get_card_info_by_index() failed"); return; } pa_operation_unref (o); } static void req_update_sink_info (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_sink_info_list (control->priv->pa_context, _pa_context_get_sink_info_cb, control); } else { o = pa_context_get_sink_info_by_index (control->priv->pa_context, index, _pa_context_get_sink_info_cb, control); } if (o == NULL) { g_warning ("pa_context_get_sink_info_list() failed"); return; } pa_operation_unref (o); } static void req_update_source_info (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_source_info_list (control->priv->pa_context, _pa_context_get_source_info_cb, control); } else { o = pa_context_get_source_info_by_index(control->priv->pa_context, index, _pa_context_get_source_info_cb, control); } if (o == NULL) { g_warning ("pa_context_get_source_info_list() failed"); return; } pa_operation_unref (o); } static void req_update_sink_input_info (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_sink_input_info_list (control->priv->pa_context, _pa_context_get_sink_input_info_cb, control); } else { o = pa_context_get_sink_input_info (control->priv->pa_context, index, _pa_context_get_sink_input_info_cb, control); } if (o == NULL) { g_warning ("pa_context_get_sink_input_info_list() failed"); return; } pa_operation_unref (o); } static void req_update_source_output_info (GvcMixerControl *control, int index) { pa_operation *o; if (index < 0) { o = pa_context_get_source_output_info_list (control->priv->pa_context, _pa_context_get_source_output_info_cb, control); } else { o = pa_context_get_source_output_info (control->priv->pa_context, index, _pa_context_get_source_output_info_cb, control); } if (o == NULL) { g_warning ("pa_context_get_source_output_info_list() failed"); return; } pa_operation_unref (o); } static void remove_client (GvcMixerControl *control, guint index) { g_hash_table_remove (control->priv->clients, GUINT_TO_POINTER (index)); } static void remove_card (GvcMixerControl *control, guint index) { g_hash_table_remove (control->priv->cards, GUINT_TO_POINTER (index)); g_signal_emit (G_OBJECT (control), signals[CARD_REMOVED], 0, index); } static void remove_sink (GvcMixerControl *control, guint index) { GvcMixerStream *stream; #if 0 g_debug ("Removing sink: index=%u", index); #endif stream = g_hash_table_lookup (control->priv->sinks, GUINT_TO_POINTER (index)); if (stream == NULL) { return; } g_hash_table_remove (control->priv->sinks, GUINT_TO_POINTER (index)); remove_stream (control, stream); } static void remove_source (GvcMixerControl *control, guint index) { GvcMixerStream *stream; #if 0 g_debug ("Removing source: index=%u", index); #endif stream = g_hash_table_lookup (control->priv->sources, GUINT_TO_POINTER (index)); if (stream == NULL) { return; } g_hash_table_remove (control->priv->sources, GUINT_TO_POINTER (index)); remove_stream (control, stream); } static void remove_sink_input (GvcMixerControl *control, guint index) { GvcMixerStream *stream; #if 0 g_debug ("Removing sink input: index=%u", index); #endif stream = g_hash_table_lookup (control->priv->sink_inputs, GUINT_TO_POINTER (index)); if (stream == NULL) { return; } g_hash_table_remove (control->priv->sink_inputs, GUINT_TO_POINTER (index)); remove_stream (control, stream); } static void remove_source_output (GvcMixerControl *control, guint index) { GvcMixerStream *stream; #if 0 g_debug ("Removing source output: index=%u", index); #endif stream = g_hash_table_lookup (control->priv->source_outputs, GUINT_TO_POINTER (index)); if (stream == NULL) { return; } g_hash_table_remove (control->priv->source_outputs, GUINT_TO_POINTER (index)); remove_stream (control, stream); } static void _pa_context_subscribe_cb (pa_context *context, pa_subscription_event_type_t t, uint32_t index, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { case PA_SUBSCRIPTION_EVENT_SINK: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_sink (control, index); } else { req_update_sink_info (control, index); } break; case PA_SUBSCRIPTION_EVENT_SOURCE: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_source (control, index); } else { req_update_source_info (control, index); } break; case PA_SUBSCRIPTION_EVENT_SINK_INPUT: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_sink_input (control, index); } else { req_update_sink_input_info (control, index); } break; case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_source_output (control, index); } else { req_update_source_output_info (control, index); } break; case PA_SUBSCRIPTION_EVENT_CLIENT: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_client (control, index); } else { req_update_client_info (control, index); } break; case PA_SUBSCRIPTION_EVENT_SERVER: req_update_server_info (control, index); break; case PA_SUBSCRIPTION_EVENT_CARD: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) { remove_card (control, index); } else { req_update_card (control, index); } break; } } static void gvc_mixer_control_ready (GvcMixerControl *control) { pa_operation *o; pa_context_set_subscribe_callback (control->priv->pa_context, _pa_context_subscribe_cb, control); o = pa_context_subscribe (control->priv->pa_context, (pa_subscription_mask_t) (PA_SUBSCRIPTION_MASK_SINK| PA_SUBSCRIPTION_MASK_SOURCE| PA_SUBSCRIPTION_MASK_SINK_INPUT| PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT| PA_SUBSCRIPTION_MASK_CLIENT| PA_SUBSCRIPTION_MASK_SERVER| PA_SUBSCRIPTION_MASK_CARD), NULL, NULL); if (o == NULL) { g_warning ("pa_context_subscribe() failed"); return; } pa_operation_unref (o); req_update_server_info (control, -1); req_update_client_info (control, -1); req_update_sink_info (control, -1); req_update_source_info (control, -1); req_update_sink_input_info (control, -1); req_update_source_output_info (control, -1); req_update_card (control, -1); control->priv->n_outstanding = 6; /* This call is not always supported */ o = pa_ext_stream_restore_read (control->priv->pa_context, _pa_ext_stream_restore_read_cb, control); if (o != NULL) { pa_operation_unref (o); control->priv->n_outstanding++; pa_ext_stream_restore_set_subscribe_cb (control->priv->pa_context, _pa_ext_stream_restore_subscribe_cb, control); o = pa_ext_stream_restore_subscribe (control->priv->pa_context, 1, NULL, NULL); if (o != NULL) { pa_operation_unref (o); } } else { g_debug ("Failed to initialized stream_restore extension: %s", pa_strerror (pa_context_errno (control->priv->pa_context))); } } static void gvc_mixer_new_pa_context (GvcMixerControl *self) { pa_proplist *proplist; g_return_if_fail (self); g_return_if_fail (!self->priv->pa_context); proplist = pa_proplist_new (); pa_proplist_sets (proplist, PA_PROP_APPLICATION_NAME, self->priv->name); pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "org.gnome.VolumeControl"); pa_proplist_sets (proplist, PA_PROP_APPLICATION_ICON_NAME, "multimedia-volume-control"); pa_proplist_sets (proplist, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION); self->priv->pa_context = pa_context_new_with_proplist (self->priv->pa_api, NULL, proplist); pa_proplist_free (proplist); g_assert (self->priv->pa_context); } static void remove_all_streams (GvcMixerControl *control, GHashTable *hash_table) { GHashTableIter iter; gpointer key, value; g_hash_table_iter_init (&iter, hash_table); while (g_hash_table_iter_next (&iter, &key, &value)) { remove_stream (control, value); g_hash_table_iter_remove (&iter); } } static gboolean idle_reconnect (gpointer data) { GvcMixerControl *control = GVC_MIXER_CONTROL (data); GHashTableIter iter; gpointer key, value; g_return_val_if_fail (control, FALSE); if (control->priv->pa_context) { pa_context_unref (control->priv->pa_context); control->priv->pa_context = NULL; gvc_mixer_new_pa_context (control); } remove_all_streams (control, control->priv->sinks); remove_all_streams (control, control->priv->sources); remove_all_streams (control, control->priv->sink_inputs); remove_all_streams (control, control->priv->source_outputs); g_hash_table_iter_init (&iter, control->priv->clients); while (g_hash_table_iter_next (&iter, &key, &value)) g_hash_table_iter_remove (&iter); gvc_mixer_control_open (control); /* cannot fail */ control->priv->reconnect_id = 0; return FALSE; } static void _pa_context_state_cb (pa_context *context, void *userdata) { GvcMixerControl *control = GVC_MIXER_CONTROL (userdata); switch (pa_context_get_state (context)) { case PA_CONTEXT_UNCONNECTED: case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; case PA_CONTEXT_READY: gvc_mixer_control_ready (control); break; case PA_CONTEXT_FAILED: control->priv->state = GVC_STATE_FAILED; g_signal_emit (control, signals[STATE_CHANGED], 0, GVC_STATE_FAILED); if (control->priv->reconnect_id == 0) control->priv->reconnect_id = g_timeout_add_seconds (RECONNECT_DELAY, idle_reconnect, control); break; case PA_CONTEXT_TERMINATED: default: /* FIXME: */ break; } } gboolean gvc_mixer_control_open (GvcMixerControl *control) { int res; g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); g_return_val_if_fail (control->priv->pa_context != NULL, FALSE); g_return_val_if_fail (pa_context_get_state (control->priv->pa_context) == PA_CONTEXT_UNCONNECTED, FALSE); pa_context_set_state_callback (control->priv->pa_context, _pa_context_state_cb, control); control->priv->state = GVC_STATE_CONNECTING; g_signal_emit (G_OBJECT (control), signals[STATE_CHANGED], 0, GVC_STATE_CONNECTING); res = pa_context_connect (control->priv->pa_context, NULL, (pa_context_flags_t) PA_CONTEXT_NOFAIL, NULL); if (res < 0) { g_warning ("Failed to connect context: %s", pa_strerror (pa_context_errno (control->priv->pa_context))); } return res; } gboolean gvc_mixer_control_close (GvcMixerControl *control) { g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE); g_return_val_if_fail (control->priv->pa_context != NULL, FALSE); pa_context_disconnect (control->priv->pa_context); control->priv->state = GVC_STATE_CLOSED; g_signal_emit (G_OBJECT (control), signals[STATE_CHANGED], 0, GVC_STATE_CLOSED); return TRUE; } static void gvc_mixer_control_dispose (GObject *object) { GvcMixerControl *control = GVC_MIXER_CONTROL (object); if (control->priv->reconnect_id != 0) { g_source_remove (control->priv->reconnect_id); control->priv->reconnect_id = 0; } if (control->priv->pa_context != NULL) { pa_context_unref (control->priv->pa_context); control->priv->pa_context = NULL; } if (control->priv->default_source_name != NULL) { g_free (control->priv->default_source_name); control->priv->default_source_name = NULL; } if (control->priv->default_sink_name != NULL) { g_free (control->priv->default_sink_name); control->priv->default_sink_name = NULL; } if (control->priv->pa_mainloop != NULL) { pa_glib_mainloop_free (control->priv->pa_mainloop); control->priv->pa_mainloop = NULL; } if (control->priv->all_streams != NULL) { g_hash_table_destroy (control->priv->all_streams); control->priv->all_streams = NULL; } if (control->priv->sinks != NULL) { g_hash_table_destroy (control->priv->sinks); control->priv->sinks = NULL; } if (control->priv->sources != NULL) { g_hash_table_destroy (control->priv->sources); control->priv->sources = NULL; } if (control->priv->sink_inputs != NULL) { g_hash_table_destroy (control->priv->sink_inputs); control->priv->sink_inputs = NULL; } if (control->priv->source_outputs != NULL) { g_hash_table_destroy (control->priv->source_outputs); control->priv->source_outputs = NULL; } if (control->priv->clients != NULL) { g_hash_table_destroy (control->priv->clients); control->priv->clients = NULL; } if (control->priv->cards != NULL) { g_hash_table_destroy (control->priv->cards); control->priv->cards = NULL; } G_OBJECT_CLASS (gvc_mixer_control_parent_class)->dispose (object); } static void gvc_mixer_control_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcMixerControl *self = GVC_MIXER_CONTROL (object); switch (prop_id) { case PROP_NAME: g_free (self->priv->name); self->priv->name = g_value_dup_string (value); g_object_notify (G_OBJECT (self), "name"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_mixer_control_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcMixerControl *self = GVC_MIXER_CONTROL (object); switch (prop_id) { case PROP_NAME: g_value_set_string (value, self->priv->name); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * gvc_mixer_control_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerControl *self; object = G_OBJECT_CLASS (gvc_mixer_control_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_CONTROL (object); gvc_mixer_new_pa_context (self); return object; } static void gvc_mixer_control_class_init (GvcMixerControlClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = gvc_mixer_control_constructor; object_class->dispose = gvc_mixer_control_dispose; object_class->finalize = gvc_mixer_control_finalize; object_class->set_property = gvc_mixer_control_set_property; object_class->get_property = gvc_mixer_control_get_property; g_object_class_install_property (object_class, PROP_NAME, g_param_spec_string ("name", "Name", "Name to display for this mixer control", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); signals [STATE_CHANGED] = g_signal_new ("state-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, state_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [STREAM_ADDED] = g_signal_new ("stream-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, stream_added), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [STREAM_REMOVED] = g_signal_new ("stream-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, stream_removed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [CARD_ADDED] = g_signal_new ("card-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, card_added), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [CARD_REMOVED] = g_signal_new ("card-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, card_removed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [DEFAULT_SINK_CHANGED] = g_signal_new ("default-sink-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, default_sink_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [DEFAULT_SOURCE_CHANGED] = g_signal_new ("default-source-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcMixerControlClass, default_source_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); g_type_class_add_private (klass, sizeof (GvcMixerControlPrivate)); } static void gvc_mixer_control_init (GvcMixerControl *control) { control->priv = GVC_MIXER_CONTROL_GET_PRIVATE (control); control->priv->pa_mainloop = pa_glib_mainloop_new (g_main_context_default ()); g_assert (control->priv->pa_mainloop); control->priv->pa_api = pa_glib_mainloop_get_api (control->priv->pa_mainloop); g_assert (control->priv->pa_api); control->priv->all_streams = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->sinks = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->sources = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->sink_inputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->source_outputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->cards = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref); control->priv->clients = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_free); control->priv->state = GVC_STATE_CLOSED; } static void gvc_mixer_control_finalize (GObject *object) { GvcMixerControl *mixer_control; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_CONTROL (object)); mixer_control = GVC_MIXER_CONTROL (object); g_free (mixer_control->priv->name); mixer_control->priv->name = NULL; g_return_if_fail (mixer_control->priv != NULL); G_OBJECT_CLASS (gvc_mixer_control_parent_class)->finalize (object); } GvcMixerControl * gvc_mixer_control_new (const char *name) { GObject *control; control = g_object_new (GVC_TYPE_MIXER_CONTROL, "name", name, NULL); return GVC_MIXER_CONTROL (control); } /* FIXME: Remove when PA 0.9.23 is used */ #ifndef PA_VOLUME_UI_MAX #define PA_VOLUME_UI_MAX pa_sw_volume_from_dB(+11.0) #endif gdouble gvc_mixer_control_get_vol_max_norm (GvcMixerControl *control) { return (gdouble) PA_VOLUME_NORM; } gdouble gvc_mixer_control_get_vol_max_amplified (GvcMixerControl *control) { return (gdouble) PA_VOLUME_UI_MAX; } cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-sink.c0000664000175000017500000001334612625665665026263 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 "gvc-mixer-sink.h" #include "gvc-mixer-stream-private.h" #include "gvc-channel-map-private.h" #define GVC_MIXER_SINK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK, GvcMixerSinkPrivate)) struct GvcMixerSinkPrivate { gpointer dummy; }; static void gvc_mixer_sink_class_init (GvcMixerSinkClass *klass); static void gvc_mixer_sink_init (GvcMixerSink *mixer_sink); static void gvc_mixer_sink_finalize (GObject *object); G_DEFINE_TYPE (GvcMixerSink, gvc_mixer_sink, GVC_TYPE_MIXER_STREAM) static gboolean gvc_mixer_sink_push_volume (GvcMixerStream *stream, gpointer *op) { pa_operation *o; guint index; const GvcChannelMap *map; pa_context *context; const pa_cvolume *cv; index = gvc_mixer_stream_get_index (stream); map = gvc_mixer_stream_get_channel_map (stream); /* set the volume */ cv = gvc_channel_map_get_cvolume(map); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_sink_volume_by_index (context, index, cv, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_sink_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } *op = o; return TRUE; } static gboolean gvc_mixer_sink_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { pa_operation *o; guint index; pa_context *context; index = gvc_mixer_stream_get_index (stream); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_sink_mute_by_index (context, index, is_muted, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_sink_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } pa_operation_unref(o); return TRUE; } static gboolean gvc_mixer_sink_change_port (GvcMixerStream *stream, const char *port) { pa_operation *o; guint index; pa_context *context; index = gvc_mixer_stream_get_index (stream); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_sink_port_by_index (context, index, port, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_sink_port_by_index() failed: %s", pa_strerror(pa_context_errno(context))); return FALSE; } pa_operation_unref(o); return TRUE; } static void gvc_mixer_sink_class_init (GvcMixerSinkClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass); object_class->finalize = gvc_mixer_sink_finalize; stream_class->push_volume = gvc_mixer_sink_push_volume; stream_class->change_port = gvc_mixer_sink_change_port; stream_class->change_is_muted = gvc_mixer_sink_change_is_muted; g_type_class_add_private (klass, sizeof (GvcMixerSinkPrivate)); } static void gvc_mixer_sink_init (GvcMixerSink *sink) { sink->priv = GVC_MIXER_SINK_GET_PRIVATE (sink); } static void gvc_mixer_sink_finalize (GObject *object) { GvcMixerSink *mixer_sink; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_SINK (object)); mixer_sink = GVC_MIXER_SINK (object); g_return_if_fail (mixer_sink->priv != NULL); G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->finalize (object); } /** * gvc_mixer_sink_new: (skip) * * @context: * @index: * @channel_map: * * Returns: */ GvcMixerStream * gvc_mixer_sink_new (pa_context *context, guint index, GvcChannelMap *channel_map) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_SINK, "pa-context", context, "index", index, "channel-map", channel_map, NULL); return GVC_MIXER_STREAM (object); } cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-channel-map.h0000664000175000017500000000557312625665665026370 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. * */ #ifndef __GVC_CHANNEL_MAP_H #define __GVC_CHANNEL_MAP_H #include #include G_BEGIN_DECLS #define GVC_TYPE_CHANNEL_MAP (gvc_channel_map_get_type ()) #define GVC_CHANNEL_MAP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMap)) #define GVC_CHANNEL_MAP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_CHANNEL_MAP, GvcChannelMapClass)) #define GVC_IS_CHANNEL_MAP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_CHANNEL_MAP)) #define GVC_IS_CHANNEL_MAP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_CHANNEL_MAP)) #define GVC_CHANNEL_MAP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapClass)) typedef struct GvcChannelMapPrivate GvcChannelMapPrivate; typedef struct { GObject parent; GvcChannelMapPrivate *priv; } GvcChannelMap; typedef struct { GObjectClass parent_class; void (*volume_changed) (GvcChannelMap *channel_map, gboolean set); } GvcChannelMapClass; enum { VOLUME, BALANCE, FADE, LFE, NUM_TYPES }; GType gvc_channel_map_get_type (void); GvcChannelMap * gvc_channel_map_new (void); guint gvc_channel_map_get_num_channels (const GvcChannelMap *map); const gdouble * gvc_channel_map_get_volume (GvcChannelMap *map); gboolean gvc_channel_map_can_balance (const GvcChannelMap *map); gboolean gvc_channel_map_can_fade (const GvcChannelMap *map); gboolean gvc_channel_map_has_position (const GvcChannelMap *map, pa_channel_position_t position); #define gvc_channel_map_has_lfe(x) gvc_channel_map_has_position (x, PA_CHANNEL_POSITION_LFE) const char * gvc_channel_map_get_mapping (const GvcChannelMap *map); G_END_DECLS #endif /* __GVC_CHANNEL_MAP_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-channel-map.c0000664000175000017500000001662212625665665026360 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 "gvc-channel-map.h" #include "gvc-channel-map-private.h" #define GVC_CHANNEL_MAP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapPrivate)) struct GvcChannelMapPrivate { pa_channel_map pa_map; gboolean pa_volume_is_set; pa_cvolume pa_volume; gdouble extern_volume[NUM_TYPES]; /* volume, balance, fade, lfe */ gboolean can_balance; gboolean can_fade; }; enum { VOLUME_CHANGED, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0, }; static void gvc_channel_map_class_init (GvcChannelMapClass *klass); static void gvc_channel_map_init (GvcChannelMap *channel_map); static void gvc_channel_map_finalize (GObject *object); G_DEFINE_TYPE (GvcChannelMap, gvc_channel_map, G_TYPE_OBJECT) guint gvc_channel_map_get_num_channels (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), 0); if (!pa_channel_map_valid(&map->priv->pa_map)) return 0; return map->priv->pa_map.channels; } const gdouble * gvc_channel_map_get_volume (GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL); if (!pa_channel_map_valid(&map->priv->pa_map)) return NULL; map->priv->extern_volume[VOLUME] = (gdouble) pa_cvolume_max (&map->priv->pa_volume); if (gvc_channel_map_can_balance (map)) map->priv->extern_volume[BALANCE] = (gdouble) pa_cvolume_get_balance (&map->priv->pa_volume, &map->priv->pa_map); else map->priv->extern_volume[BALANCE] = 0; if (gvc_channel_map_can_fade (map)) map->priv->extern_volume[FADE] = (gdouble) pa_cvolume_get_fade (&map->priv->pa_volume, &map->priv->pa_map); else map->priv->extern_volume[FADE] = 0; if (gvc_channel_map_has_lfe (map)) map->priv->extern_volume[LFE] = (gdouble) pa_cvolume_get_position (&map->priv->pa_volume, &map->priv->pa_map, PA_CHANNEL_POSITION_LFE); else map->priv->extern_volume[LFE] = 0; return map->priv->extern_volume; } gboolean gvc_channel_map_can_balance (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE); return map->priv->can_balance; } gboolean gvc_channel_map_can_fade (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE); return map->priv->can_fade; } const char * gvc_channel_map_get_mapping (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL); if (!pa_channel_map_valid(&map->priv->pa_map)) return NULL; return pa_channel_map_to_pretty_name (&map->priv->pa_map); } /** * gvc_channel_map_has_position: (skip) * * @map: * @position: * * Returns: */ gboolean gvc_channel_map_has_position (const GvcChannelMap *map, pa_channel_position_t position) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE); return pa_channel_map_has_position (&(map->priv->pa_map), position); } const pa_channel_map * gvc_channel_map_get_pa_channel_map (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL); if (!pa_channel_map_valid(&map->priv->pa_map)) return NULL; return &map->priv->pa_map; } const pa_cvolume * gvc_channel_map_get_cvolume (const GvcChannelMap *map) { g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL); if (!pa_channel_map_valid(&map->priv->pa_map)) return NULL; return &map->priv->pa_volume; } static void gvc_channel_map_class_init (GvcChannelMapClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gvc_channel_map_finalize; signals [VOLUME_CHANGED] = g_signal_new ("volume-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GvcChannelMapClass, volume_changed), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); g_type_class_add_private (klass, sizeof (GvcChannelMapPrivate)); } void gvc_channel_map_volume_changed (GvcChannelMap *map, const pa_cvolume *cv, gboolean set) { g_return_if_fail (GVC_IS_CHANNEL_MAP (map)); g_return_if_fail (cv != NULL); g_return_if_fail (pa_cvolume_compatible_with_channel_map(cv, &map->priv->pa_map)); if (pa_cvolume_equal(cv, &map->priv->pa_volume)) return; map->priv->pa_volume = *cv; if (map->priv->pa_volume_is_set == FALSE) { map->priv->pa_volume_is_set = TRUE; return; } g_signal_emit (map, signals[VOLUME_CHANGED], 0, set); } static void gvc_channel_map_init (GvcChannelMap *map) { map->priv = GVC_CHANNEL_MAP_GET_PRIVATE (map); map->priv->pa_volume_is_set = FALSE; } static void gvc_channel_map_finalize (GObject *object) { GvcChannelMap *channel_map; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_CHANNEL_MAP (object)); channel_map = GVC_CHANNEL_MAP (object); g_return_if_fail (channel_map->priv != NULL); G_OBJECT_CLASS (gvc_channel_map_parent_class)->finalize (object); } GvcChannelMap * gvc_channel_map_new (void) { GObject *map; map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL); return GVC_CHANNEL_MAP (map); } static void set_from_pa_map (GvcChannelMap *map, const pa_channel_map *pa_map) { g_assert (pa_channel_map_valid(pa_map)); map->priv->can_balance = pa_channel_map_can_balance (pa_map); map->priv->can_fade = pa_channel_map_can_fade (pa_map); map->priv->pa_map = *pa_map; pa_cvolume_set(&map->priv->pa_volume, pa_map->channels, PA_VOLUME_NORM); } GvcChannelMap * gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *pa_map) { GObject *map; map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL); set_from_pa_map (GVC_CHANNEL_MAP (map), pa_map); return GVC_CHANNEL_MAP (map); } cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.h0000664000175000017500000000445212625665665030160 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. * */ #ifndef __GVC_MIXER_SOURCE_OUTPUT_H #define __GVC_MIXER_SOURCE_OUTPUT_H #include #include "gvc-mixer-stream.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_SOURCE_OUTPUT (gvc_mixer_source_output_get_type ()) #define GVC_MIXER_SOURCE_OUTPUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutput)) #define GVC_MIXER_SOURCE_OUTPUT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputClass)) #define GVC_IS_MIXER_SOURCE_OUTPUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT)) #define GVC_IS_MIXER_SOURCE_OUTPUT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SOURCE_OUTPUT)) #define GVC_MIXER_SOURCE_OUTPUT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputClass)) typedef struct GvcMixerSourceOutputPrivate GvcMixerSourceOutputPrivate; typedef struct { GvcMixerStream parent; GvcMixerSourceOutputPrivate *priv; } GvcMixerSourceOutput; typedef struct { GvcMixerStreamClass parent_class; } GvcMixerSourceOutputClass; GType gvc_mixer_source_output_get_type (void); GvcMixerStream * gvc_mixer_source_output_new (pa_context *context, guint index, GvcChannelMap *map); G_END_DECLS #endif /* __GVC_MIXER_SOURCE_OUTPUT_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-card.c0000664000175000017500000004215712625665665026232 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * Copyright (C) 2009 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 "gvc-mixer-card.h" #include "gvc-mixer-card-private.h" #define GVC_MIXER_CARD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardPrivate)) static guint32 card_serial = 1; struct GvcMixerCardPrivate { pa_context *pa_context; guint id; guint index; char *name; char *icon_name; char *profile; char *target_profile; char *human_profile; GList *profiles; pa_operation *profile_op; }; enum { PROP_0, PROP_ID, PROP_PA_CONTEXT, PROP_INDEX, PROP_NAME, PROP_ICON_NAME, PROP_PROFILE, PROP_HUMAN_PROFILE, }; static void gvc_mixer_card_class_init (GvcMixerCardClass *klass); static void gvc_mixer_card_init (GvcMixerCard *mixer_card); static void gvc_mixer_card_finalize (GObject *object); G_DEFINE_TYPE (GvcMixerCard, gvc_mixer_card, G_TYPE_OBJECT) static guint32 get_next_card_serial (void) { guint32 serial; serial = card_serial++; if ((gint32)card_serial < 0) { card_serial = 1; } return serial; } pa_context * gvc_mixer_card_get_pa_context (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0); return card->priv->pa_context; } guint gvc_mixer_card_get_index (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0); return card->priv->index; } guint gvc_mixer_card_get_id (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0); return card->priv->id; } const char * gvc_mixer_card_get_name (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL); return card->priv->name; } gboolean gvc_mixer_card_set_name (GvcMixerCard *card, const char *name) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE); g_free (card->priv->name); card->priv->name = g_strdup (name); g_object_notify (G_OBJECT (card), "name"); return TRUE; } const char * gvc_mixer_card_get_icon_name (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL); return card->priv->icon_name; } gboolean gvc_mixer_card_set_icon_name (GvcMixerCard *card, const char *icon_name) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE); g_free (card->priv->icon_name); card->priv->icon_name = g_strdup (icon_name); g_object_notify (G_OBJECT (card), "icon-name"); return TRUE; } /** * gvc_mixer_card_get_profile: (skip) * * @card: * * Returns: */ GvcMixerCardProfile * gvc_mixer_card_get_profile (GvcMixerCard *card) { GList *l; g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL); g_return_val_if_fail (card->priv->profiles != NULL, NULL); for (l = card->priv->profiles; l != NULL; l = l->next) { GvcMixerCardProfile *p = l->data; if (g_str_equal (card->priv->profile, p->profile)) { return p; } } g_assert_not_reached (); return NULL; } gboolean gvc_mixer_card_set_profile (GvcMixerCard *card, const char *profile) { GList *l; g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE); g_return_val_if_fail (card->priv->profiles != NULL, FALSE); g_free (card->priv->profile); card->priv->profile = g_strdup (profile); g_free (card->priv->human_profile); card->priv->human_profile = NULL; for (l = card->priv->profiles; l != NULL; l = l->next) { GvcMixerCardProfile *p = l->data; if (g_str_equal (card->priv->profile, p->profile)) { card->priv->human_profile = g_strdup (p->human_profile); break; } } g_object_notify (G_OBJECT (card), "profile"); return TRUE; } static void _pa_context_set_card_profile_by_index_cb (pa_context *context, int success, void *userdata) { GvcMixerCard *card = GVC_MIXER_CARD (userdata); g_assert (card->priv->target_profile); if (success > 0) { gvc_mixer_card_set_profile (card, card->priv->target_profile); } else { g_debug ("Failed to switch profile on '%s' from '%s' to '%s'", card->priv->name, card->priv->profile, card->priv->target_profile); } g_free (card->priv->target_profile); card->priv->target_profile = NULL; pa_operation_unref (card->priv->profile_op); card->priv->profile_op = NULL; } gboolean gvc_mixer_card_change_profile (GvcMixerCard *card, const char *profile) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE); g_return_val_if_fail (card->priv->profiles != NULL, FALSE); /* Same profile, or already requested? */ if (g_strcmp0 (card->priv->profile, profile) == 0) return TRUE; if (g_strcmp0 (profile, card->priv->target_profile) == 0) return TRUE; if (card->priv->profile_op != NULL) { pa_operation_cancel (card->priv->profile_op); pa_operation_unref (card->priv->profile_op); card->priv->profile_op = NULL; } if (card->priv->profile != NULL) { g_free (card->priv->target_profile); card->priv->target_profile = g_strdup (profile); card->priv->profile_op = pa_context_set_card_profile_by_index (card->priv->pa_context, card->priv->index, card->priv->target_profile, _pa_context_set_card_profile_by_index_cb, card); if (card->priv->profile_op == NULL) { g_warning ("pa_context_set_card_profile_by_index() failed"); return FALSE; } } else { g_assert (card->priv->human_profile == NULL); card->priv->profile = g_strdup (profile); } return TRUE; } /** * gvc_mixer_card_get_profiles: * * Return value: (transfer none) (element-type GvcMixerCardProfile): */ const GList * gvc_mixer_card_get_profiles (GvcMixerCard *card) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL); return card->priv->profiles; } static int sort_profiles (GvcMixerCardProfile *a, GvcMixerCardProfile *b) { if (a->priority == b->priority) return 0; if (a->priority > b->priority) return 1; return -1; } /** * gvc_mixer_card_set_profiles: * @profiles: (transfer full) (element-type GvcMixerCardProfile): */ gboolean gvc_mixer_card_set_profiles (GvcMixerCard *card, GList *profiles) { g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE); g_return_val_if_fail (card->priv->profiles == NULL, FALSE); card->priv->profiles = g_list_sort (profiles, (GCompareFunc) sort_profiles); return TRUE; } static void gvc_mixer_card_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GvcMixerCard *self = GVC_MIXER_CARD (object); switch (prop_id) { case PROP_PA_CONTEXT: self->priv->pa_context = g_value_get_pointer (value); break; case PROP_INDEX: self->priv->index = g_value_get_ulong (value); break; case PROP_ID: self->priv->id = g_value_get_ulong (value); break; case PROP_NAME: gvc_mixer_card_set_name (self, g_value_get_string (value)); break; case PROP_ICON_NAME: gvc_mixer_card_set_icon_name (self, g_value_get_string (value)); break; case PROP_PROFILE: gvc_mixer_card_set_profile (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gvc_mixer_card_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GvcMixerCard *self = GVC_MIXER_CARD (object); switch (prop_id) { case PROP_PA_CONTEXT: g_value_set_pointer (value, self->priv->pa_context); break; case PROP_INDEX: g_value_set_ulong (value, self->priv->index); break; case PROP_ID: g_value_set_ulong (value, self->priv->id); break; case PROP_NAME: g_value_set_string (value, self->priv->name); break; case PROP_ICON_NAME: g_value_set_string (value, self->priv->icon_name); break; case PROP_PROFILE: g_value_set_string (value, self->priv->profile); break; case PROP_HUMAN_PROFILE: g_value_set_string (value, self->priv->human_profile); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * gvc_mixer_card_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; GvcMixerCard *self; object = G_OBJECT_CLASS (gvc_mixer_card_parent_class)->constructor (type, n_construct_properties, construct_params); self = GVC_MIXER_CARD (object); self->priv->id = get_next_card_serial (); return object; } static void gvc_mixer_card_class_init (GvcMixerCardClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->constructor = gvc_mixer_card_constructor; gobject_class->finalize = gvc_mixer_card_finalize; gobject_class->set_property = gvc_mixer_card_set_property; gobject_class->get_property = gvc_mixer_card_get_property; g_object_class_install_property (gobject_class, PROP_INDEX, g_param_spec_ulong ("index", "Index", "The index for this card", 0, G_MAXULONG, 0, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_ID, g_param_spec_ulong ("id", "id", "The id for this card", 0, G_MAXULONG, 0, G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_PA_CONTEXT, g_param_spec_pointer ("pa-context", "PulseAudio context", "The PulseAudio context for this card", G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (gobject_class, PROP_NAME, g_param_spec_string ("name", "Name", "Name to display for this card", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_ICON_NAME, g_param_spec_string ("icon-name", "Icon Name", "Name of icon to display for this card", NULL, G_PARAM_READWRITE|G_PARAM_CONSTRUCT)); g_object_class_install_property (gobject_class, PROP_PROFILE, g_param_spec_string ("profile", "Profile", "Name of current profile for this card", NULL, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_HUMAN_PROFILE, g_param_spec_string ("human-profile", "Profile (Human readable)", "Name of current profile for this card in human readable form", NULL, G_PARAM_READABLE)); g_type_class_add_private (klass, sizeof (GvcMixerCardPrivate)); } static void gvc_mixer_card_init (GvcMixerCard *card) { card->priv = GVC_MIXER_CARD_GET_PRIVATE (card); } GvcMixerCard * gvc_mixer_card_new (pa_context *context, guint index) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_CARD, "index", index, "pa-context", context, NULL); return GVC_MIXER_CARD (object); } static void free_profile (GvcMixerCardProfile *p) { g_free (p->profile); g_free (p->human_profile); g_free (p->status); g_free (p); } static void gvc_mixer_card_finalize (GObject *object) { GvcMixerCard *mixer_card; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_CARD (object)); mixer_card = GVC_MIXER_CARD (object); g_return_if_fail (mixer_card->priv != NULL); g_free (mixer_card->priv->name); mixer_card->priv->name = NULL; g_free (mixer_card->priv->icon_name); mixer_card->priv->icon_name = NULL; g_free (mixer_card->priv->target_profile); mixer_card->priv->target_profile = NULL; g_free (mixer_card->priv->profile); mixer_card->priv->profile = NULL; g_free (mixer_card->priv->human_profile); mixer_card->priv->human_profile = NULL; g_list_foreach (mixer_card->priv->profiles, (GFunc) free_profile, NULL); g_list_free (mixer_card->priv->profiles); mixer_card->priv->profiles = NULL; G_OBJECT_CLASS (gvc_mixer_card_parent_class)->finalize (object); } cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.h0000664000175000017500000000433712625665665027404 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. * */ #ifndef __GVC_MIXER_EVENT_ROLE_H #define __GVC_MIXER_EVENT_ROLE_H #include #include "gvc-mixer-stream.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_EVENT_ROLE (gvc_mixer_event_role_get_type ()) #define GVC_MIXER_EVENT_ROLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRole)) #define GVC_MIXER_EVENT_ROLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRoleClass)) #define GVC_IS_MIXER_EVENT_ROLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_EVENT_ROLE)) #define GVC_IS_MIXER_EVENT_ROLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_EVENT_ROLE)) #define GVC_MIXER_EVENT_ROLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRoleClass)) typedef struct GvcMixerEventRolePrivate GvcMixerEventRolePrivate; typedef struct { GvcMixerStream parent; GvcMixerEventRolePrivate *priv; } GvcMixerEventRole; typedef struct { GvcMixerStreamClass parent_class; } GvcMixerEventRoleClass; GType gvc_mixer_event_role_get_type (void); GvcMixerStream * gvc_mixer_event_role_new (pa_context *context, const char *device, GvcChannelMap *channel_map); G_END_DECLS #endif /* __GVC_MIXER_EVENT_ROLE_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-source.h0000664000175000017500000000417712625665665026626 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. * */ #ifndef __GVC_MIXER_SOURCE_H #define __GVC_MIXER_SOURCE_H #include #include "gvc-mixer-stream.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_SOURCE (gvc_mixer_source_get_type ()) #define GVC_MIXER_SOURCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSource)) #define GVC_MIXER_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SOURCE, GvcMixerSourceClass)) #define GVC_IS_MIXER_SOURCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SOURCE)) #define GVC_IS_MIXER_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SOURCE)) #define GVC_MIXER_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSourceClass)) typedef struct GvcMixerSourcePrivate GvcMixerSourcePrivate; typedef struct { GvcMixerStream parent; GvcMixerSourcePrivate *priv; } GvcMixerSource; typedef struct { GvcMixerStreamClass parent_class; } GvcMixerSourceClass; GType gvc_mixer_source_get_type (void); GvcMixerStream * gvc_mixer_source_new (pa_context *context, guint index, GvcChannelMap *map); G_END_DECLS #endif /* __GVC_MIXER_SOURCE_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/Makefile.am0000664000175000017500000000156412625665665025307 0ustar fabiofabioNULL = noinst_LTLIBRARIES = libgvc.la INCLUDES = \ $(WARN_CFLAGS) \ $(MEDIA_KEYS_CFLAGS) \ $(NULL) libgvc_la_LIBADD = \ $(MEDIA_KEYS_LIBS) \ $(NULL) libgvc_la_SOURCES = \ gvc-mixer-stream.h \ gvc-mixer-stream.c \ gvc-mixer-stream-private.h \ gvc-channel-map.h \ gvc-channel-map.c \ gvc-channel-map-private.h \ gvc-mixer-card.c \ gvc-mixer-card.h \ gvc-mixer-card-private.h \ gvc-mixer-sink.h \ gvc-mixer-sink.c \ gvc-mixer-source.h \ gvc-mixer-source.c \ gvc-mixer-sink-input.h \ gvc-mixer-sink-input.c \ gvc-mixer-source-output.h \ gvc-mixer-source-output.c \ gvc-mixer-event-role.h \ gvc-mixer-event-role.c \ gvc-mixer-control.h \ gvc-mixer-control.c \ gvc-mixer-control-private.h \ gvc-pulseaudio-fake.h \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.c0000664000175000017500000001171012625665665027411 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 "gvc-mixer-sink-input.h" #include "gvc-mixer-stream-private.h" #include "gvc-channel-map-private.h" #define GVC_MIXER_SINK_INPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputPrivate)) struct GvcMixerSinkInputPrivate { gpointer dummy; }; static void gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass); static void gvc_mixer_sink_input_init (GvcMixerSinkInput *mixer_sink_input); static void gvc_mixer_sink_input_finalize (GObject *object); G_DEFINE_TYPE (GvcMixerSinkInput, gvc_mixer_sink_input, GVC_TYPE_MIXER_STREAM) static gboolean gvc_mixer_sink_input_push_volume (GvcMixerStream *stream, gpointer *op) { pa_operation *o; guint index; const GvcChannelMap *map; pa_context *context; const pa_cvolume *cv; index = gvc_mixer_stream_get_index (stream); map = gvc_mixer_stream_get_channel_map (stream); cv = gvc_channel_map_get_cvolume(map); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_sink_input_volume (context, index, cv, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_sink_input_volume() failed"); return FALSE; } *op = o; return TRUE; } static gboolean gvc_mixer_sink_input_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { pa_operation *o; guint index; pa_context *context; index = gvc_mixer_stream_get_index (stream); context = gvc_mixer_stream_get_pa_context (stream); o = pa_context_set_sink_input_mute (context, index, is_muted, NULL, NULL); if (o == NULL) { g_warning ("pa_context_set_sink_input_mute_by_index() failed"); return FALSE; } pa_operation_unref(o); return TRUE; } static void gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass); object_class->finalize = gvc_mixer_sink_input_finalize; stream_class->push_volume = gvc_mixer_sink_input_push_volume; stream_class->change_is_muted = gvc_mixer_sink_input_change_is_muted; g_type_class_add_private (klass, sizeof (GvcMixerSinkInputPrivate)); } static void gvc_mixer_sink_input_init (GvcMixerSinkInput *sink_input) { sink_input->priv = GVC_MIXER_SINK_INPUT_GET_PRIVATE (sink_input); } static void gvc_mixer_sink_input_finalize (GObject *object) { GvcMixerSinkInput *mixer_sink_input; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_SINK_INPUT (object)); mixer_sink_input = GVC_MIXER_SINK_INPUT (object); g_return_if_fail (mixer_sink_input->priv != NULL); G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->finalize (object); } /** * gvc_mixer_sink_input_new: (skip) * * @context: * @index: * @channel_map: * * Returns: */ GvcMixerStream * gvc_mixer_sink_input_new (pa_context *context, guint index, GvcChannelMap *channel_map) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_SINK_INPUT, "pa-context", context, "index", index, "channel-map", channel_map, NULL); return GVC_MIXER_STREAM (object); } cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-control-private.h0000664000175000017500000000224712625665665030452 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. * */ #ifndef __GVC_MIXER_CONTROL_PRIVATE_H #define __GVC_MIXER_CONTROL_PRIVATE_H #include #include #include "gvc-mixer-stream.h" #include "gvc-mixer-card.h" G_BEGIN_DECLS pa_context * gvc_mixer_control_get_pa_context (GvcMixerControl *control); G_END_DECLS #endif /* __GVC_MIXER_CONTROL_PRIVATE_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-sink.h0000664000175000017500000000411712625665665026264 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. * */ #ifndef __GVC_MIXER_SINK_H #define __GVC_MIXER_SINK_H #include #include "gvc-mixer-stream.h" G_BEGIN_DECLS #define GVC_TYPE_MIXER_SINK (gvc_mixer_sink_get_type ()) #define GVC_MIXER_SINK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SINK, GvcMixerSink)) #define GVC_MIXER_SINK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SINK, GvcMixerSinkClass)) #define GVC_IS_MIXER_SINK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SINK)) #define GVC_IS_MIXER_SINK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SINK)) #define GVC_MIXER_SINK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SINK, GvcMixerSinkClass)) typedef struct GvcMixerSinkPrivate GvcMixerSinkPrivate; typedef struct { GvcMixerStream parent; GvcMixerSinkPrivate *priv; } GvcMixerSink; typedef struct { GvcMixerStreamClass parent_class; } GvcMixerSinkClass; GType gvc_mixer_sink_get_type (void); GvcMixerStream * gvc_mixer_sink_new (pa_context *context, guint index, GvcChannelMap *map); G_END_DECLS #endif /* __GVC_MIXER_SINK_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.c0000664000175000017500000000720212625665665030147 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 "gvc-mixer-source-output.h" #define GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputPrivate)) struct GvcMixerSourceOutputPrivate { gpointer dummy; }; static void gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass); static void gvc_mixer_source_output_init (GvcMixerSourceOutput *mixer_source_output); static void gvc_mixer_source_output_finalize (GObject *object); G_DEFINE_TYPE (GvcMixerSourceOutput, gvc_mixer_source_output, GVC_TYPE_MIXER_STREAM) static gboolean gvc_mixer_source_output_push_volume (GvcMixerStream *stream, gpointer *op) { /* FIXME: */ *op = NULL; return TRUE; } static gboolean gvc_mixer_source_output_change_is_muted (GvcMixerStream *stream, gboolean is_muted) { /* FIXME: */ return TRUE; } static void gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass); object_class->finalize = gvc_mixer_source_output_finalize; stream_class->push_volume = gvc_mixer_source_output_push_volume; stream_class->change_is_muted = gvc_mixer_source_output_change_is_muted; g_type_class_add_private (klass, sizeof (GvcMixerSourceOutputPrivate)); } static void gvc_mixer_source_output_init (GvcMixerSourceOutput *source_output) { source_output->priv = GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE (source_output); } static void gvc_mixer_source_output_finalize (GObject *object) { GvcMixerSourceOutput *mixer_source_output; g_return_if_fail (object != NULL); g_return_if_fail (GVC_IS_MIXER_SOURCE_OUTPUT (object)); mixer_source_output = GVC_MIXER_SOURCE_OUTPUT (object); g_return_if_fail (mixer_source_output->priv != NULL); G_OBJECT_CLASS (gvc_mixer_source_output_parent_class)->finalize (object); } /** * gvc_mixer_source_output_new: (skip) * * @context: * @index: * @channel_map: * * Returns: */ GvcMixerStream * gvc_mixer_source_output_new (pa_context *context, guint index, GvcChannelMap *channel_map) { GObject *object; object = g_object_new (GVC_TYPE_MIXER_SOURCE_OUTPUT, "pa-context", context, "index", index, "channel-map", channel_map, NULL); return GVC_MIXER_STREAM (object); } cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-control.h0000664000175000017500000001165112625665665027001 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. * */ #ifndef __GVC_MIXER_CONTROL_H #define __GVC_MIXER_CONTROL_H #include #include "gvc-mixer-stream.h" #include "gvc-mixer-card.h" G_BEGIN_DECLS typedef enum { GVC_STATE_CLOSED, GVC_STATE_READY, GVC_STATE_CONNECTING, GVC_STATE_FAILED } GvcMixerControlState; #define GVC_TYPE_MIXER_CONTROL (gvc_mixer_control_get_type ()) #define GVC_MIXER_CONTROL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControl)) #define GVC_MIXER_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_CONTROL, GvcMixerControlClass)) #define GVC_IS_MIXER_CONTROL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_CONTROL)) #define GVC_IS_MIXER_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_CONTROL)) #define GVC_MIXER_CONTROL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlClass)) typedef struct GvcMixerControlPrivate GvcMixerControlPrivate; typedef struct { GObject parent; GvcMixerControlPrivate *priv; } GvcMixerControl; typedef struct { GObjectClass parent_class; void (*state_changed) (GvcMixerControl *control, GvcMixerControlState new_state); void (*stream_added) (GvcMixerControl *control, guint id); void (*stream_removed) (GvcMixerControl *control, guint id); void (*card_added) (GvcMixerControl *control, guint id); void (*card_removed) (GvcMixerControl *control, guint id); void (*default_sink_changed) (GvcMixerControl *control, guint id); void (*default_source_changed) (GvcMixerControl *control, guint id); } GvcMixerControlClass; GType gvc_mixer_control_get_type (void); GvcMixerControl * gvc_mixer_control_new (const char *name); gboolean gvc_mixer_control_open (GvcMixerControl *control); gboolean gvc_mixer_control_close (GvcMixerControl *control); GSList * gvc_mixer_control_get_cards (GvcMixerControl *control); GSList * gvc_mixer_control_get_streams (GvcMixerControl *control); GSList * gvc_mixer_control_get_sinks (GvcMixerControl *control); GSList * gvc_mixer_control_get_sources (GvcMixerControl *control); GSList * gvc_mixer_control_get_sink_inputs (GvcMixerControl *control); GSList * gvc_mixer_control_get_source_outputs (GvcMixerControl *control); GvcMixerStream * gvc_mixer_control_lookup_stream_id (GvcMixerControl *control, guint id); GvcMixerCard * gvc_mixer_control_lookup_card_id (GvcMixerControl *control, guint id); GvcMixerStream * gvc_mixer_control_get_default_sink (GvcMixerControl *control); GvcMixerStream * gvc_mixer_control_get_default_source (GvcMixerControl *control); GvcMixerStream * gvc_mixer_control_get_event_sink_input (GvcMixerControl *control); gboolean gvc_mixer_control_set_default_sink (GvcMixerControl *control, GvcMixerStream *stream); gboolean gvc_mixer_control_set_default_source (GvcMixerControl *control, GvcMixerStream *stream); gdouble gvc_mixer_control_get_vol_max_norm (GvcMixerControl *control); gdouble gvc_mixer_control_get_vol_max_amplified (GvcMixerControl *control); GvcMixerControlState gvc_mixer_control_get_state (GvcMixerControl *control); G_END_DECLS #endif /* __GVC_MIXER_CONTROL_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/cut-n-paste/gvc-mixer-card-private.h0000664000175000017500000000240012625665665027672 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008-2009 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 __GVC_MIXER_CARD_PRIVATE_H #define __GVC_MIXER_CARD_PRIVATE_H #include #include "gvc-mixer-card.h" G_BEGIN_DECLS GvcMixerCard * gvc_mixer_card_new (pa_context *context, guint index); pa_context * gvc_mixer_card_get_pa_context (GvcMixerCard *card); G_END_DECLS #endif /* __GVC_MIXER_CARD_PRIVATE_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/bus-watch-namespace.h0000664000175000017500000000261212625665665025106 0ustar fabiofabio/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Lars Uebernickel */ #ifndef __BUS_WATCH_NAMESPACE_H__ #define __BUS_WATCH_NAMESPACE_H__ #include guint bus_watch_namespace (GBusType bus_type, const gchar *name_space, GBusNameAppearedCallback appeared_handler, GBusNameVanishedCallback vanished_handler, gpointer user_data, GDestroyNotify user_data_destroy); void bus_unwatch_namespace (guint id); #endif cinnamon-settings-daemon-2.8.3/plugins/media-keys/csd-media-keys-plugin.h0000664000175000017500000000437312625665665025360 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. * */ #ifndef __CSD_MEDIA_KEYS_PLUGIN_H__ #define __CSD_MEDIA_KEYS_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_MEDIA_KEYS_PLUGIN (csd_media_keys_plugin_get_type ()) #define CSD_MEDIA_KEYS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_MEDIA_KEYS_PLUGIN, CsdMediaKeysPlugin)) #define CSD_MEDIA_KEYS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_MEDIA_KEYS_PLUGIN, CsdMediaKeysPluginClass)) #define CSD_IS_MEDIA_KEYS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_MEDIA_KEYS_PLUGIN)) #define CSD_IS_MEDIA_KEYS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_MEDIA_KEYS_PLUGIN)) #define CSD_MEDIA_KEYS_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_MEDIA_KEYS_PLUGIN, CsdMediaKeysPluginClass)) typedef struct CsdMediaKeysPluginPrivate CsdMediaKeysPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdMediaKeysPluginPrivate *priv; } CsdMediaKeysPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdMediaKeysPluginClass; GType csd_media_keys_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_MEDIA_KEYS_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/csd-media-keys-manager.h0000664000175000017500000000522712625665665025473 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_MEDIA_KEYS_MANAGER_H #define __CSD_MEDIA_KEYS_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_MEDIA_KEYS_MANAGER (csd_media_keys_manager_get_type ()) #define CSD_MEDIA_KEYS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_MEDIA_KEYS_MANAGER, CsdMediaKeysManager)) #define CSD_MEDIA_KEYS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_MEDIA_KEYS_MANAGER, CsdMediaKeysManagerClass)) #define CSD_IS_MEDIA_KEYS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_MEDIA_KEYS_MANAGER)) #define CSD_IS_MEDIA_KEYS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_MEDIA_KEYS_MANAGER)) #define CSD_MEDIA_KEYS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_MEDIA_KEYS_MANAGER, CsdMediaKeysManagerClass)) typedef struct CsdMediaKeysManagerPrivate CsdMediaKeysManagerPrivate; typedef struct { GObject parent; CsdMediaKeysManagerPrivate *priv; } CsdMediaKeysManager; typedef struct { GObjectClass parent_class; void (* media_player_key_pressed) (CsdMediaKeysManager *manager, const char *application, const char *key); } CsdMediaKeysManagerClass; GType csd_media_keys_manager_get_type (void); CsdMediaKeysManager * csd_media_keys_manager_new (void); gboolean csd_media_keys_manager_start (CsdMediaKeysManager *manager, GError **error); void csd_media_keys_manager_stop (CsdMediaKeysManager *manager); G_END_DECLS #endif /* __CSD_MEDIA_KEYS_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/README.media-keys-API0000664000175000017500000000347112625665665024430 0ustar fabiofabioThis is very simple documentation to cinnamon-settings-daemon's D-Bus API for media players. cinnamon-settings-daemon will send key press events from multimedia keys to applications that register their interest in those events. This allows the play/pause button to control an audio player that's not focused for example. The D-Bus API is described in csd-media-keys-manager.c (look for introspection_xml), but a small explanation follows here. 1. Create yourself a proxy object for the remote interface: Object path: /org/gnome/SettingsDaemon/MediaKeys D-Bus name: org.gnome.SettingsDaemon.MediaKeys Interface name: org.gnome.SettingsDaemon.MediaKeys 2. Register your application with cinnamon-settings-daemon GrabMediaPlayerKeys ("my-application", 0) with the second argument being the current time (usually 0, or the time passed to you from an event, such as a mouse click) 3. Listen to the MediaPlayerKeyPressed() signal 4. When receiving a MediaPlayerKeyPressed() signal, check whether the first argument (application) matches the value you passed to GrabMediaPlayerKeys() and apply the action depending on the key (2nd argument) Possible values of key are: - Play - Pause - Stop - Previous - Next - Rewind - FastForward - Repeat - Shuffle 5. Every time your application is focused, you should call GrabMediaPlayerKeys() again, so that cinnamon-settings-daemon knows which one was last used. This allows switching between a movie player and a music player, for example, and have the buttons control the last used application. 6. When your application wants to stop using the functionality it can call ReleaseMediaPlayerKeys(). If your application does not call ReleaseMediaPlayerKeys() and releases its D-Bus connection then the application will be automatically removed from the list of applications held by cinnamon-settings-daemon. cinnamon-settings-daemon-2.8.3/plugins/media-keys/csd-marshal.list0000664000175000017500000000002312625665665024173 0ustar fabiofabioVOID:STRING,STRING cinnamon-settings-daemon-2.8.3/plugins/media-keys/media-keys.cinnamon-settings-plugin.in0000664000175000017500000000022212625665665030414 0ustar fabiofabio[Cinnamon Settings Plugin] Module=media-keys IAge=0 _Name=Media keys _Description=Media keys plugin Authors= Copyright=Copyright © 2007 Website= cinnamon-settings-daemon-2.8.3/plugins/media-keys/csd-marshal.h0000664000175000017500000000130012625665665023446 0ustar fabiofabio #ifndef __csd_marshal_MARSHAL_H__ #define __csd_marshal_MARSHAL_H__ #include G_BEGIN_DECLS /* VOID:STRING,STRING (csd-marshal.list:1) */ G_GNUC_INTERNAL void csd_marshal_VOID__STRING_STRING (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); G_END_DECLS #endif /* __csd_marshal_MARSHAL_H__ */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/test-media-keys.c0000664000175000017500000000033512625665665024257 0ustar fabiofabio#define NEW csd_media_keys_manager_new #define START csd_media_keys_manager_start #define STOP csd_media_keys_manager_stop #define MANAGER CsdMediaKeysManager #include "csd-media-keys-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/media-keys/mpris-controller.h0000664000175000017500000000365312625665665024600 0ustar fabiofabio/* * Copyright © 2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope 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 Lesser General Public License * along with this program; if not, see * * Author: Michael Wood */ #ifndef __MPRIS_CONTROLLER_H__ #define __MPRIS_CONTROLLER_H__ #include G_BEGIN_DECLS #define MPRIS_TYPE_CONTROLLER mpris_controller_get_type() #define MPRIS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MPRIS_TYPE_CONTROLLER, MprisController)) #define MPRIS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MPRIS_TYPE_CONTROLLER, MprisControllerClass)) #define MPRIS_IS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MPRIS_TYPE_CONTROLLER)) #define MPRIS_IS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MPRIS_TYPE_CONTROLLER)) #define MPRIS_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MPRIS_TYPE_CONTROLLER, MprisControllerClass)) typedef struct _MprisController MprisController; typedef struct _MprisControllerClass MprisControllerClass; typedef struct _MprisControllerPrivate MprisControllerPrivate; struct _MprisController { GObject parent; MprisControllerPrivate *priv; }; struct _MprisControllerClass { GObjectClass parent_class; }; GType mpris_controller_get_type (void) G_GNUC_CONST; MprisController *mpris_controller_new (void); gboolean mpris_controller_key (MprisController *self, const gchar *key); G_END_DECLS #endif /* __MPRIS_CONTROLLER_H__ */ cinnamon-settings-daemon-2.8.3/plugins/media-keys/bus-watch-namespace.c0000664000175000017500000002545012625665665025106 0ustar fabiofabio/* * Copyright 2013 Canonical Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Lars Uebernickel */ #include "config.h" #include #include #include "bus-watch-namespace.h" typedef struct { guint id; gchar *name_space; GBusNameAppearedCallback appeared_handler; GBusNameVanishedCallback vanished_handler; gpointer user_data; GDestroyNotify user_data_destroy; GDBusConnection *connection; GCancellable *cancellable; GHashTable *names; guint subscription_id; } NamespaceWatcher; typedef struct { NamespaceWatcher *watcher; gchar *name; } GetNameOwnerData; static guint namespace_watcher_next_id; static GHashTable *namespace_watcher_watchers; static void namespace_watcher_stop (gpointer data) { NamespaceWatcher *watcher = data; g_cancellable_cancel (watcher->cancellable); g_object_unref (watcher->cancellable); if (watcher->subscription_id) g_dbus_connection_signal_unsubscribe (watcher->connection, watcher->subscription_id); if (watcher->vanished_handler) { GHashTableIter it; const gchar *name; g_hash_table_iter_init (&it, watcher->names); while (g_hash_table_iter_next (&it, (gpointer *) &name, NULL)) watcher->vanished_handler (watcher->connection, name, watcher->user_data); } if (watcher->user_data_destroy) watcher->user_data_destroy (watcher->user_data); if (watcher->connection) { g_signal_handlers_disconnect_by_func (watcher->connection, namespace_watcher_stop, watcher); g_object_unref (watcher->connection); } g_hash_table_unref (watcher->names); g_hash_table_remove (namespace_watcher_watchers, GUINT_TO_POINTER (watcher->id)); if (g_hash_table_size (namespace_watcher_watchers) == 0) g_clear_pointer (&namespace_watcher_watchers, g_hash_table_destroy); g_free (watcher); } static void namespace_watcher_name_appeared (NamespaceWatcher *watcher, const gchar *name, const gchar *owner) { /* There's a race between NameOwnerChanged signals arriving and the * ListNames/GetNameOwner sequence returning, so this function might * be called more than once for the same name. To ensure that * appeared_handler is only called once for each name, it is only * called when inserting the name into watcher->names (each name is * only inserted once there). */ if (g_hash_table_contains (watcher->names, name)) return; g_hash_table_add (watcher->names, g_strdup (name)); if (watcher->appeared_handler) watcher->appeared_handler (watcher->connection, name, owner, watcher->user_data); } static void namespace_watcher_name_vanished (NamespaceWatcher *watcher, const gchar *name) { if (g_hash_table_remove (watcher->names, name) && watcher->vanished_handler) watcher->vanished_handler (watcher->connection, name, watcher->user_data); } static gboolean dbus_name_has_namespace (const gchar *name, const gchar *name_space) { gint len_name; gint len_namespace; len_name = strlen (name); len_namespace = strlen (name_space); if (len_name < len_namespace) return FALSE; if (memcmp (name_space, name, len_namespace) != 0) return FALSE; return len_namespace == len_name || name[len_namespace] == '.'; } static void name_owner_changed (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { NamespaceWatcher *watcher = user_data; const gchar *name; const gchar *old_owner; const gchar *new_owner; g_variant_get (parameters, "(&s&s&s)", &name, &old_owner, &new_owner); if (old_owner[0] != '\0') namespace_watcher_name_vanished (watcher, name); if (new_owner[0] != '\0') namespace_watcher_name_appeared (watcher, name, new_owner); } static void got_name_owner (GObject *object, GAsyncResult *result, gpointer user_data) { GetNameOwnerData *data = user_data; GError *error = NULL; GVariant *reply; const gchar *owner; reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error_free (error); goto out; } if (reply == NULL) { if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER)) g_warning ("bus_watch_namespace: error calling org.freedesktop.DBus.GetNameOwner: %s", error->message); g_error_free (error); goto out; } g_variant_get (reply, "(&s)", &owner); namespace_watcher_name_appeared (data->watcher, data->name, owner); g_variant_unref (reply); out: g_free (data->name); g_slice_free (GetNameOwnerData, data); } static void names_listed (GObject *object, GAsyncResult *result, gpointer user_data) { NamespaceWatcher *watcher; GError *error = NULL; GVariant *reply; GVariantIter *iter; const gchar *name; reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error_free (error); return; } watcher = user_data; if (reply == NULL) { g_warning ("bus_watch_namespace: error calling org.freedesktop.DBus.ListNames: %s", error->message); g_error_free (error); return; } g_variant_get (reply, "(as)", &iter); while (g_variant_iter_next (iter, "&s", &name)) { if (dbus_name_has_namespace (name, watcher->name_space)) { GetNameOwnerData *data = g_slice_new (GetNameOwnerData); data->watcher = watcher; data->name = g_strdup (name); g_dbus_connection_call (watcher->connection, "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetNameOwner", g_variant_new ("(s)", name), G_VARIANT_TYPE ("(s)"), G_DBUS_CALL_FLAGS_NONE, -1, watcher->cancellable, got_name_owner, data); } } g_variant_iter_free (iter); g_variant_unref (reply); } static void connection_closed (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data) { NamespaceWatcher *watcher = user_data; namespace_watcher_stop (watcher); } static void got_bus (GObject *object, GAsyncResult *result, gpointer user_data) { GDBusConnection *connection; NamespaceWatcher *watcher; GError *error = NULL; connection = g_bus_get_finish (result, &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error_free (error); return; } watcher = user_data; if (connection == NULL) { namespace_watcher_stop (watcher); return; } watcher->connection = connection; g_signal_connect (watcher->connection, "closed", G_CALLBACK (connection_closed), watcher); #ifdef HAVE_NEW_GLIB // G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE is only available since Glib 2.38, LMDE uses 2.36 so we test the version of Glib here. watcher->subscription_id = g_dbus_connection_signal_subscribe (watcher->connection, "org.freedesktop.DBus", "org.freedesktop.DBus", "NameOwnerChanged", "/org/freedesktop/DBus", watcher->name_space, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, name_owner_changed, watcher, NULL); #endif /* HAVE_NEW_GLIB */ g_dbus_connection_call (watcher->connection, "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames", NULL, G_VARIANT_TYPE ("(as)"), G_DBUS_CALL_FLAGS_NONE, -1, watcher->cancellable, names_listed, watcher); } guint bus_watch_namespace (GBusType bus_type, const gchar *name_space, GBusNameAppearedCallback appeared_handler, GBusNameVanishedCallback vanished_handler, gpointer user_data, GDestroyNotify user_data_destroy) { NamespaceWatcher *watcher; /* same rules for interfaces and well-known names */ g_return_val_if_fail (name_space != NULL && g_dbus_is_interface_name (name_space), 0); g_return_val_if_fail (appeared_handler || vanished_handler, 0); watcher = g_new0 (NamespaceWatcher, 1); watcher->id = namespace_watcher_next_id++; watcher->name_space = g_strdup (name_space); watcher->appeared_handler = appeared_handler; watcher->vanished_handler = vanished_handler; watcher->user_data = user_data; watcher->user_data_destroy = user_data_destroy; watcher->cancellable = g_cancellable_new ();; watcher->names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); if (namespace_watcher_watchers == NULL) namespace_watcher_watchers = g_hash_table_new (g_direct_hash, g_direct_equal); g_hash_table_insert (namespace_watcher_watchers, GUINT_TO_POINTER (watcher->id), watcher); g_bus_get (bus_type, watcher->cancellable, got_bus, watcher); return watcher->id; } void bus_unwatch_namespace (guint id) { /* namespace_watcher_stop() might have already removed the watcher * with @id in the case of a connection error. Thus, this function * doesn't warn when @id is absent from the hash table. */ if (namespace_watcher_watchers) { NamespaceWatcher *watcher; watcher = g_hash_table_lookup (namespace_watcher_watchers, GUINT_TO_POINTER (id)); if (watcher) { /* make sure vanished() is not called as a result of this function */ g_hash_table_remove_all (watcher->names); namespace_watcher_stop (watcher); } } } cinnamon-settings-daemon-2.8.3/plugins/media-keys/mpris-controller.c0000664000175000017500000001416512625665665024573 0ustar fabiofabio/* * Copyright © 2013 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU Lesser General Public License, * version 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope 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 Lesser General Public License * along with this program; if not, see * * Author: Michael Wood */ #include "mpris-controller.h" #include "bus-watch-namespace.h" #include G_DEFINE_TYPE (MprisController, mpris_controller, G_TYPE_OBJECT) #define CONTROLLER_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), MPRIS_TYPE_CONTROLLER, MprisControllerPrivate)) struct _MprisControllerPrivate { GCancellable *cancellable; GDBusProxy *mpris_client_proxy; guint namespace_watcher_id; GSList *other_players; gboolean connecting; }; static void mpris_controller_dispose (GObject *object) { MprisControllerPrivate *priv = MPRIS_CONTROLLER (object)->priv; g_clear_object (&priv->cancellable); g_clear_object (&priv->mpris_client_proxy); if (priv->namespace_watcher_id) { bus_unwatch_namespace (priv->namespace_watcher_id); priv->namespace_watcher_id = 0; } if (priv->other_players) { g_slist_free_full (priv->other_players, g_free); priv->other_players = NULL; } G_OBJECT_CLASS (mpris_controller_parent_class)->dispose (object); } static void mpris_proxy_call_done (GObject *object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; GVariant *ret; if (!(ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (object), res, &error))) { g_warning ("Error calling method %s", error->message); g_clear_error (&error); return; } g_variant_unref (ret); } gboolean mpris_controller_key (MprisController *self, const gchar *key) { MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv; if (!priv->mpris_client_proxy) return FALSE; if (g_strcmp0 (key, "Play") == 0) key = "PlayPause"; g_debug ("calling %s over dbus to mpris client %s", key, g_dbus_proxy_get_name (priv->mpris_client_proxy)); g_dbus_proxy_call (priv->mpris_client_proxy, key, NULL, 0, -1, priv->cancellable, mpris_proxy_call_done, NULL); return TRUE; } static void mpris_proxy_ready_cb (GObject *object, GAsyncResult *res, gpointer user_data) { MprisControllerPrivate *priv = MPRIS_CONTROLLER (user_data)->priv; GError *error = NULL; priv->mpris_client_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (!priv->mpris_client_proxy) g_warning ("Error connecting to mpris interface %s", error->message); priv->connecting = FALSE; g_clear_error (&error); } static void start_mpris_proxy (MprisController *self, const gchar *name) { MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv; g_debug ("Creating proxy for for %s", name); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, 0, NULL, name, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", priv->cancellable, mpris_proxy_ready_cb, self); priv->connecting = TRUE; } static void mpris_player_appeared (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) { MprisController *self = user_data; MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv; if (priv->mpris_client_proxy == NULL && !priv->connecting) start_mpris_proxy (self, name); else self->priv->other_players = g_slist_prepend (self->priv->other_players, g_strdup (name)); } static void mpris_player_vanished (GDBusConnection *connection, const gchar *name, gpointer user_data) { MprisController *self = user_data; MprisControllerPrivate *priv = MPRIS_CONTROLLER (self)->priv; if (priv->mpris_client_proxy && g_strcmp0 (name, g_dbus_proxy_get_name (priv->mpris_client_proxy)) == 0) { g_clear_object (&priv->mpris_client_proxy); /* take the next one if there's one */ if (self->priv->other_players && !priv->connecting) { GSList *first; gchar *name; first = self->priv->other_players; name = first->data; start_mpris_proxy (self, name); self->priv->other_players = self->priv->other_players->next; g_free (name); g_slist_free_1 (first); } } } static void mpris_controller_constructed (GObject *object) { MprisControllerPrivate *priv = MPRIS_CONTROLLER (object)->priv; priv->namespace_watcher_id = bus_watch_namespace (G_BUS_TYPE_SESSION, "org.mpris.MediaPlayer2", mpris_player_appeared, mpris_player_vanished, MPRIS_CONTROLLER (object), NULL); } static void mpris_controller_class_init (MprisControllerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (MprisControllerPrivate)); object_class->constructed = mpris_controller_constructed; object_class->dispose = mpris_controller_dispose; } static void mpris_controller_init (MprisController *self) { self->priv = CONTROLLER_PRIVATE (self); } MprisController * mpris_controller_new (void) { return g_object_new (MPRIS_TYPE_CONTROLLER, NULL); } cinnamon-settings-daemon-2.8.3/plugins/media-keys/csd-media-keys-plugin.c0000664000175000017500000000631512625665665025351 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 "cinnamon-settings-plugin.h" #include "csd-media-keys-plugin.h" #include "csd-media-keys-manager.h" struct CsdMediaKeysPluginPrivate { CsdMediaKeysManager *manager; }; #define CSD_MEDIA_KEYS_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_MEDIA_KEYS_PLUGIN, CsdMediaKeysPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdMediaKeysPlugin, csd_media_keys_plugin) static void csd_media_keys_plugin_init (CsdMediaKeysPlugin *plugin) { plugin->priv = CSD_MEDIA_KEYS_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdMediaKeysPlugin initializing"); plugin->priv->manager = csd_media_keys_manager_new (); } static void csd_media_keys_plugin_finalize (GObject *object) { CsdMediaKeysPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_MEDIA_KEYS_PLUGIN (object)); g_debug ("CsdMediaKeysPlugin finalizing"); plugin = CSD_MEDIA_KEYS_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_media_keys_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating media_keys plugin"); error = NULL; res = csd_media_keys_manager_start (CSD_MEDIA_KEYS_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start media_keys manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating media_keys plugin"); csd_media_keys_manager_stop (CSD_MEDIA_KEYS_PLUGIN (plugin)->priv->manager); } static void csd_media_keys_plugin_class_init (CsdMediaKeysPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_media_keys_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdMediaKeysPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/media-keys/Makefile.am0000664000175000017500000000555212625665665023150 0ustar fabiofabioicondir = $(datadir)/icons/hicolor context = actions plugin_name = media-keys NULL = SUBDIRS = cut-n-paste plugin_LTLIBRARIES = libmedia-keys.la BUILT_SOURCES = \ csd-marshal.h \ csd-marshal.c \ $(NULL) csd-marshal.c: csd-marshal.list $(AM_V_GEN) $(GLIB_GENMARSHAL) --prefix=csd_marshal $< --header --body --internal > $@ csd-marshal.h: csd-marshal.list $(AM_V_GEN) $(GLIB_GENMARSHAL) --prefix=csd_marshal $< --header --internal > $@ libmedia_keys_la_SOURCES = \ csd-media-keys-plugin.h \ csd-media-keys-plugin.c \ csd-media-keys-manager.h \ csd-media-keys-manager.c \ bus-watch-namespace.c \ bus-watch-namespace.h \ mpris-controller.c \ mpris-controller.h \ $(BUILT_SOURCES) \ $(NULL) libmedia_keys_la_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -I$(top_srcdir)/plugins/media-keys/cut-n-paste \ -DBINDIR=\"$(bindir)\" \ -DPIXMAPDIR=\""$(pkgdatadir)"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libmedia_keys_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(MEDIA_KEYS_CFLAGS) \ $(AM_CFLAGS) libmedia_keys_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) libmedia_keys_la_LIBADD = \ $(top_builddir)/plugins/common/libcommon.la \ $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la \ $(MEDIA_KEYS_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ -lm plugin_in_files = \ media-keys.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) libexec_PROGRAMS = csd-test-media-keys csd_test_media_keys_SOURCES = \ csd-media-keys-manager.c \ csd-media-keys-manager.h \ bus-watch-namespace.c \ bus-watch-namespace.h \ mpris-controller.c \ mpris-controller.h \ test-media-keys.c \ $(BUILT_SOURCES) \ $(NULL) csd_test_media_keys_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -I$(top_srcdir)/plugins/media-keys/cut-n-paste \ -DBINDIR=\"$(bindir)\" \ -DPIXMAPDIR=\""$(pkgdatadir)"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_test_media_keys_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(MEDIA_KEYS_CFLAGS) \ $(AM_CFLAGS) csd_test_media_keys_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(MEDIA_KEYS_LIBS) \ -lm EXTRA_DIST = \ csd-marshal.list \ README.media-keys-API \ $(plugin_in_files) CLEANFILES = \ $(BUILT_SOURCES) \ $(plugin_DATA) DISTCLEANFILES = \ $(plugin_DATA) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/media-keys/csd-media-keys-manager.c0000664000175000017500000023302212625665665025462 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 * * 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 #ifdef HAVE_GUDEV #include #endif #include "mpris-controller.h" #include "cinnamon-settings-profile.h" #include "csd-marshal.h" #include "csd-media-keys-manager.h" #include "csd-power-helper.h" #include "csd-input-helper.h" #include "csd-enums.h" #include #include #include "gvc-mixer-control.h" #include #include /* For media keys, we need to keep using org.gnome because that's what apps are looking for */ #define GNOME_DBUS_PATH "/org/gnome/SettingsDaemon" #define GNOME_DBUS_NAME "org.gnome.SettingsDaemon" #define CSD_MEDIA_KEYS_DBUS_PATH GNOME_DBUS_PATH "/MediaKeys" #define CSD_MEDIA_KEYS_DBUS_NAME GNOME_DBUS_NAME ".MediaKeys" #define CINNAMON_DBUS_PATH "/org/cinnamon/SettingsDaemon" #define CINNAMON_DBUS_NAME "org.cinnamon.SettingsDaemon" #define CINNAMON_SHELL_DBUS_PATH "/org/Cinnamon" #define CINNAMON_SHELL_DBUS_NAME "org.Cinnamon" #define CINNAMON_KEYBINDINGS_PATH CINNAMON_DBUS_PATH "/KeybindingHandler" #define CINNAMON_KEYBINDINGS_NAME CINNAMON_DBUS_NAME ".KeybindingHandler" #define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager" #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager" #define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager" #define GNOME_KEYRING_DBUS_NAME "org.gnome.keyring" #define GNOME_KEYRING_DBUS_PATH "/org/gnome/keyring/daemon" #define GNOME_KEYRING_DBUS_INTERFACE "org.gnome.keyring.Daemon" static const gchar introspection_xml[] = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; static const gchar kb_introspection_xml[] = "" " " " " " " " " " " " " ""; #define SETTINGS_INTERFACE_DIR "org.cinnamon.desktop.interface" #define SETTINGS_POWER_DIR "org.cinnamon.settings-daemon.plugins.power" #define SETTINGS_XSETTINGS_DIR "org.cinnamon.settings-daemon.plugins.xsettings" #define SETTINGS_TOUCHPAD_DIR "org.cinnamon.settings-daemon.peripherals.touchpad" #define TOUCHPAD_ENABLED_KEY "touchpad-enabled" #define HIGH_CONTRAST "HighContrast" #define VOLUME_STEP 5 /* percents for one volume button press */ #define MAX_VOLUME 65536.0 #define LOGIND_DBUS_NAME "org.freedesktop.login1" #define LOGIND_DBUS_PATH "/org/freedesktop/login1" #define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager" #define CSD_MEDIA_KEYS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_MEDIA_KEYS_MANAGER, CsdMediaKeysManagerPrivate)) typedef struct { char *application; char *name; guint32 time; guint watch_id; } MediaPlayer; struct CsdMediaKeysManagerPrivate { /* Volume bits */ GvcMixerControl *volume; GvcMixerStream *stream; GvcMixerStream *source_stream; /* Microphone */ ca_context *ca; #ifdef HAVE_GUDEV GHashTable *streams; /* key = X device ID, value = stream id */ GUdevClient *udev_client; #endif /* HAVE_GUDEV */ GtkWidget *dialog; /* HighContrast theme settings */ GSettings *interface_settings; char *icon_theme; char *gtk_theme; /* Power stuff */ GSettings *power_settings; GDBusProxy *upower_proxy; GDBusProxy *power_screen_proxy; GDBusProxy *power_keyboard_proxy; /* OSD stuff */ GDBusProxy *osd_proxy; GCancellable *osd_cancellable; /* logind stuff */ GDBusProxy *logind_proxy; gint inhibit_keys_fd; GSettings *session_settings; gboolean use_logind; /* Multihead stuff */ GdkScreen *current_screen; GSList *screens; int opcode; GList *media_players; GDBusNodeInfo *introspection_data; GDBusNodeInfo *kb_introspection_data; GDBusConnection *connection; GCancellable *bus_cancellable; GDBusProxy *xrandr_proxy; GCancellable *cancellable; guint start_idle_id; MprisController *mpris_controller; /* Ubuntu notifications */ NotifyNotification *volume_notification; NotifyNotification *brightness_notification; NotifyNotification *kb_backlight_notification; }; static void csd_media_keys_manager_class_init (CsdMediaKeysManagerClass *klass); static void csd_media_keys_manager_init (CsdMediaKeysManager *media_keys_manager); static void csd_media_keys_manager_finalize (GObject *object); static void register_manager (CsdMediaKeysManager *manager); static gboolean do_action (CsdMediaKeysManager *manager, guint deviceid, CDesktopMediaKeyType type, gint64 timestamp); G_DEFINE_TYPE (CsdMediaKeysManager, csd_media_keys_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; #define NOTIFY_CAP_PRIVATE_SYNCHRONOUS "x-canonical-private-synchronous" #define NOTIFY_CAP_PRIVATE_ICON_ONLY "x-canonical-private-icon-only" #define NOTIFY_HINT_TRUE "true" typedef struct { CsdMediaKeysManager *manager; CDesktopMediaKeyType type; guint old_percentage; } CsdBrightnessActionData; static void init_screens (CsdMediaKeysManager *manager) { GdkDisplay *display; int i; display = gdk_display_get_default (); for (i = 0; i < gdk_display_get_n_screens (display); i++) { GdkScreen *screen; screen = gdk_display_get_screen (display, i); if (screen == NULL) { continue; } manager->priv->screens = g_slist_append (manager->priv->screens, screen); } manager->priv->current_screen = manager->priv->screens->data; } static char * get_term_command (CsdMediaKeysManager *manager) { char *cmd_term, *cmd_args;; char *cmd = NULL; GSettings *settings; settings = g_settings_new ("org.cinnamon.desktop.default-applications.terminal"); cmd_term = g_settings_get_string (settings, "exec"); if (cmd_term[0] == '\0') cmd_term = g_strdup ("gnome-terminal"); cmd_args = g_settings_get_string (settings, "exec-arg"); if (strcmp (cmd_term, "") != 0) { cmd = g_strdup_printf ("%s %s -e", cmd_term, cmd_args); } else { cmd = g_strdup_printf ("%s -e", cmd_term); } g_free (cmd_args); g_free (cmd_term); g_object_unref (settings); return cmd; } static char ** get_keyring_env (CsdMediaKeysManager *manager) { GError *error = NULL; GVariant *variant, *item; GVariantIter *iter; char **envp; variant = g_dbus_connection_call_sync (manager->priv->connection, GNOME_KEYRING_DBUS_NAME, GNOME_KEYRING_DBUS_PATH, GNOME_KEYRING_DBUS_INTERFACE, "GetEnvironment", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (variant == NULL) { g_warning ("Failed to call GetEnvironment on keyring daemon: %s", error->message); g_error_free (error); return NULL; } envp = g_get_environ (); g_variant_get (variant, "(a{ss})", &iter); while ((item = g_variant_iter_next_value (iter))) { char *key; char *value; g_variant_get (item, "{ss}", &key, &value); envp = g_environ_setenv (envp, key, value, TRUE); g_variant_unref (item); g_free (key); g_free (value); } g_variant_iter_free (iter); g_variant_unref (variant); return envp; } static void execute (CsdMediaKeysManager *manager, char *cmd, gboolean need_term) { gboolean retval; char **argv; int argc; char *exec; char *term = NULL; GError *error = NULL; retval = FALSE; if (need_term) term = get_term_command (manager); if (term) { exec = g_strdup_printf ("%s %s", term, cmd); g_free (term); } else { exec = g_strdup (cmd); } if (g_shell_parse_argv (exec, &argc, &argv, NULL)) { char **envp; envp = get_keyring_env (manager); retval = g_spawn_async (g_get_home_dir (), argv, envp, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error); g_strfreev (argv); g_strfreev (envp); } if (retval == FALSE && error != NULL) { g_warning ("Couldn't execute command: %s: %s", exec, error->message); g_error_free (error); } g_free (exec); } static void ensure_cancellable (GCancellable **cancellable) { if (*cancellable == NULL) { *cancellable = g_cancellable_new (); g_object_add_weak_pointer (G_OBJECT (*cancellable), (gpointer *)cancellable); } else { g_object_ref (*cancellable); } } static void show_osd_complete (GObject *source, GAsyncResult *result, gpointer data) { CsdMediaKeysManager *manager = data; g_object_unref (manager->priv->osd_cancellable); } static void show_osd (CsdMediaKeysManager *manager, const char *icon, int level) { GVariantBuilder builder; if (manager->priv->connection == NULL || manager->priv->osd_proxy == NULL) { g_warning ("No existing D-Bus connection trying to handle osd"); return; } g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); g_variant_builder_open (&builder, G_VARIANT_TYPE_VARDICT); if (icon) g_variant_builder_add (&builder, "{sv}", "icon", g_variant_new_string (icon)); if (level >= 0) g_variant_builder_add (&builder, "{sv}", "level", g_variant_new_int32 (level)); g_variant_builder_close (&builder); ensure_cancellable (&manager->priv->osd_cancellable); g_dbus_proxy_call (manager->priv->osd_proxy, "ShowOSD", g_variant_builder_end (&builder), G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, manager->priv->osd_cancellable, show_osd_complete, manager); } static const char * get_icon_name_for_volume (gboolean muted, int volume) { static const char *icon_names[] = { "audio-volume-muted-symbolic", "audio-volume-low-symbolic", "audio-volume-medium-symbolic", "audio-volume-high-symbolic", NULL }; int n; if (muted) { n = 0; } else { n = 3 * volume / 100 + 1; if (n < 1) { n = 1; } else if (n > 3) { n = 3; } } return icon_names[n]; } static void launch_app (GAppInfo *app_info, gint64 timestamp) { GError *error = NULL; GdkAppLaunchContext *launch_context; /* setup the launch context so the startup notification is correct */ launch_context = gdk_display_get_app_launch_context (gdk_display_get_default ()); gdk_app_launch_context_set_timestamp (launch_context, timestamp); if (!g_app_info_launch (app_info, NULL, G_APP_LAUNCH_CONTEXT (launch_context), &error)) { g_warning ("Could not launch '%s': %s", g_app_info_get_commandline (app_info), error->message); g_error_free (error); } g_object_unref (launch_context); } static void do_url_action (CsdMediaKeysManager *manager, const char *scheme, gint64 timestamp) { GAppInfo *app_info; app_info = g_app_info_get_default_for_uri_scheme (scheme); if (app_info != NULL) { launch_app (app_info, timestamp); g_object_unref (app_info); } else { g_warning ("Could not find default application for '%s' scheme", scheme); } } static void do_media_action (CsdMediaKeysManager *manager, gint64 timestamp) { GAppInfo *app_info; app_info = g_app_info_get_default_for_type ("audio/x-vorbis+ogg", FALSE); if (app_info != NULL) { launch_app (app_info, timestamp); g_object_unref (app_info); } else { g_warning ("Could not find default application for '%s' mime-type", "audio/x-vorbis+ogg"); } } static void do_terminal_action (CsdMediaKeysManager *manager) { GSettings *settings; char *term; settings = g_settings_new ("org.cinnamon.desktop.default-applications.terminal"); term = g_settings_get_string (settings, "exec"); if (term) execute (manager, term, FALSE); g_free (term); g_object_unref (settings); } static void cinnamon_session_shutdown (CsdMediaKeysManager *manager) { GError *error = NULL; GVariant *variant; /* Shouldn't happen, but you never know */ if (manager->priv->connection == NULL) { execute (manager, "cinnamon-session-quit --logout", FALSE); return; } variant = g_dbus_connection_call_sync (manager->priv->connection, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_PATH, GNOME_SESSION_DBUS_INTERFACE, "Shutdown", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (variant == NULL) { g_warning ("Failed to call Shutdown on session manager: %s", error->message); g_error_free (error); return; } g_variant_unref (variant); } static void do_logout_action (CsdMediaKeysManager *manager) { execute (manager, "cinnamon-session-quit --logout", FALSE); } static void do_eject_action_cb (GDrive *drive, GAsyncResult *res, CsdMediaKeysManager *manager) { g_drive_eject_with_operation_finish (drive, res, NULL); } #define NO_SCORE 0 #define SCORE_CAN_EJECT 50 #define SCORE_HAS_MEDIA 100 static void do_eject_action (CsdMediaKeysManager *manager) { GList *drives, *l; GDrive *fav_drive; guint score; GVolumeMonitor *volume_monitor; volume_monitor = g_volume_monitor_get (); /* Find the best drive to eject */ fav_drive = NULL; score = NO_SCORE; drives = g_volume_monitor_get_connected_drives (volume_monitor); for (l = drives; l != NULL; l = l->next) { GDrive *drive = l->data; if (g_drive_can_eject (drive) == FALSE) continue; if (g_drive_is_media_removable (drive) == FALSE) continue; if (score < SCORE_CAN_EJECT) { fav_drive = drive; score = SCORE_CAN_EJECT; } if (g_drive_has_media (drive) == FALSE) continue; if (score < SCORE_HAS_MEDIA) { fav_drive = drive; score = SCORE_HAS_MEDIA; break; } } /* Show the dialogue */ show_osd (manager, "media-eject-symbolic", -1); /* Clean up the drive selection and exit if no suitable * drives are found */ if (fav_drive != NULL) fav_drive = g_object_ref (fav_drive); g_list_foreach (drives, (GFunc) g_object_unref, NULL); if (fav_drive == NULL) return; /* Eject! */ g_drive_eject_with_operation (fav_drive, G_MOUNT_UNMOUNT_FORCE, NULL, NULL, (GAsyncReadyCallback) do_eject_action_cb, manager); g_object_unref (fav_drive); g_object_unref (volume_monitor); } static void do_home_key_action (CsdMediaKeysManager *manager, gint64 timestamp) { GFile *file; GError *error = NULL; char *uri; file = g_file_new_for_path (g_get_home_dir ()); uri = g_file_get_uri (file); g_object_unref (file); if (gtk_show_uri (NULL, uri, timestamp, &error) == FALSE) { g_warning ("Failed to launch '%s': %s", uri, error->message); g_error_free (error); } g_free (uri); } static void do_execute_desktop (CsdMediaKeysManager *manager, const char *desktop, gint64 timestamp) { GDesktopAppInfo *app_info; app_info = g_desktop_app_info_new (desktop); if (app_info != NULL) { launch_app (G_APP_INFO (app_info), timestamp); g_object_unref (app_info); } else { g_warning ("Could not find application '%s'", desktop); } } static void do_touchpad_osd_action (CsdMediaKeysManager *manager, gboolean state) { show_osd (manager, state ? "input-touchpad-symbolic" : "touchpad-disabled-symbolic", -1); } static void do_touchpad_action (CsdMediaKeysManager *manager) { GSettings *settings; gboolean state; if (touchpad_is_present () == FALSE) { do_touchpad_osd_action (manager, FALSE); return; } settings = g_settings_new (SETTINGS_TOUCHPAD_DIR); state = g_settings_get_boolean (settings, TOUCHPAD_ENABLED_KEY); do_touchpad_osd_action (manager, !state); g_settings_set_boolean (settings, TOUCHPAD_ENABLED_KEY, !state); g_object_unref (settings); } static void update_dialog (CsdMediaKeysManager *manager, GvcMixerStream *stream, gint vol, gboolean muted, gboolean sound_changed, gboolean quiet) { const char *icon; vol = CLAMP (vol, 0, 100); icon = get_icon_name_for_volume (muted, vol); show_osd (manager, icon, vol); if (quiet == FALSE && sound_changed != FALSE && muted == FALSE) { GSettings *settings = g_settings_new ("org.cinnamon.desktop.sound"); gboolean enabled = g_settings_get_boolean (settings, "volume-sound-enabled"); char *sound = g_settings_get_string (settings, "volume-sound-file"); if (enabled) { ca_context_change_device (manager->priv->ca, gvc_mixer_stream_get_name (stream)); ca_context_play (manager->priv->ca, 1, CA_PROP_MEDIA_FILENAME, sound, NULL); } g_free(sound); g_object_unref (settings); } } #ifdef HAVE_GUDEV /* PulseAudio gives us /devices/... paths, when udev * expects /sys/devices/... paths. */ static GUdevDevice * get_udev_device_for_sysfs_path (CsdMediaKeysManager *manager, const char *sysfs_path) { char *path; GUdevDevice *dev; path = g_strdup_printf ("/sys%s", sysfs_path); dev = g_udev_client_query_by_sysfs_path (manager->priv->udev_client, path); g_free (path); return dev; } static GvcMixerStream * get_stream_for_device_id (CsdMediaKeysManager *manager, guint deviceid, gboolean is_source_stream) { char *devnode; gpointer id_ptr; GvcMixerStream *res; GUdevDevice *dev, *parent; GSList *streams, *l; id_ptr = g_hash_table_lookup (manager->priv->streams, GUINT_TO_POINTER (deviceid)); if (id_ptr != NULL) { if (GPOINTER_TO_UINT (id_ptr) == (guint) -1) return NULL; else return gvc_mixer_control_lookup_stream_id (manager->priv->volume, GPOINTER_TO_UINT (id_ptr)); } devnode = xdevice_get_device_node (deviceid); if (devnode == NULL) { g_debug ("Could not find device node for XInput device %d", deviceid); return NULL; } dev = g_udev_client_query_by_device_file (manager->priv->udev_client, devnode); if (dev == NULL) { g_debug ("Could not find udev device for device path '%s'", devnode); g_free (devnode); return NULL; } g_free (devnode); if (g_strcmp0 (g_udev_device_get_property (dev, "ID_BUS"), "usb") != 0) { g_debug ("Not handling XInput device %d, not USB", deviceid); g_hash_table_insert (manager->priv->streams, GUINT_TO_POINTER (deviceid), GUINT_TO_POINTER ((guint) -1)); g_object_unref (dev); return NULL; } parent = g_udev_device_get_parent_with_subsystem (dev, "usb", "usb_device"); if (parent == NULL) { g_warning ("No USB device parent for XInput device %d even though it's USB", deviceid); g_object_unref (dev); return NULL; } res = NULL; if (is_source_stream) { streams = gvc_mixer_control_get_sinks (manager->priv->volume); } else { streams = gvc_mixer_control_get_sources (manager->priv->volume); } for (l = streams; l; l = l->next) { GvcMixerStream *stream = l->data; const char *sysfs_path; GUdevDevice *stream_dev, *stream_parent; sysfs_path = gvc_mixer_stream_get_sysfs_path (stream); stream_dev = get_udev_device_for_sysfs_path (manager, sysfs_path); if (stream_dev == NULL) continue; stream_parent = g_udev_device_get_parent_with_subsystem (stream_dev, "usb", "usb_device"); g_object_unref (stream_dev); if (stream_parent == NULL) continue; if (g_strcmp0 (g_udev_device_get_sysfs_path (stream_parent), g_udev_device_get_sysfs_path (parent)) == 0) { res = stream; } g_object_unref (stream_parent); if (res != NULL) break; } if (res) g_hash_table_insert (manager->priv->streams, GUINT_TO_POINTER (deviceid), GUINT_TO_POINTER (gvc_mixer_stream_get_id (res))); else g_hash_table_insert (manager->priv->streams, GUINT_TO_POINTER (deviceid), GUINT_TO_POINTER ((guint) -1)); return res; } #endif /* HAVE_GUDEV */ static void do_sound_action (CsdMediaKeysManager *manager, guint deviceid, int type, gboolean quiet) { GvcMixerStream *stream; gboolean old_muted, new_muted; guint old_vol, new_vol, norm_vol_step, osd_vol; gboolean sound_changed; /* Find the stream that corresponds to the device, if any */ gboolean is_source_stream = type == C_DESKTOP_MEDIA_KEY_MIC_MUTE ? TRUE : FALSE; #ifdef HAVE_GUDEV stream = get_stream_for_device_id (manager, deviceid, is_source_stream); if (stream == NULL) #endif /* HAVE_GUDEV */ { if (is_source_stream) { stream = manager->priv->source_stream; } else { stream = manager->priv->stream; } } if (stream == NULL) return; norm_vol_step = PA_VOLUME_NORM * VOLUME_STEP / 100; /* FIXME: this is racy */ new_vol = old_vol = gvc_mixer_stream_get_volume (stream); new_muted = old_muted = gvc_mixer_stream_get_is_muted (stream); sound_changed = FALSE; switch (type) { case C_DESKTOP_MEDIA_KEY_MUTE: case C_DESKTOP_MEDIA_KEY_MIC_MUTE: new_muted = !old_muted; break; case C_DESKTOP_MEDIA_KEY_VOLUME_DOWN: if (old_vol <= norm_vol_step) { new_vol = 0; new_muted = TRUE; } else { new_vol = old_vol - norm_vol_step; } break; case C_DESKTOP_MEDIA_KEY_VOLUME_UP: new_muted = FALSE; /* When coming out of mute only increase the volume if it was 0 */ if (!old_muted || old_vol == 0) new_vol = MIN (old_vol + norm_vol_step, MAX_VOLUME); break; } if (old_muted != new_muted) { gvc_mixer_stream_change_is_muted (stream, new_muted); sound_changed = TRUE; } if (old_vol != new_vol) { if (gvc_mixer_stream_set_volume (stream, new_vol) != FALSE) { gvc_mixer_stream_push_volume (stream); sound_changed = TRUE; } } if (type == C_DESKTOP_MEDIA_KEY_VOLUME_DOWN && old_vol == 0 && old_muted) osd_vol = -1; else if (type == C_DESKTOP_MEDIA_KEY_VOLUME_UP && old_vol == PA_VOLUME_NORM && !old_muted) osd_vol = 101; else if (!new_muted) osd_vol = (int) (100 * (double) new_vol / PA_VOLUME_NORM); else osd_vol = 0; update_dialog (manager, stream, osd_vol, new_muted, sound_changed, quiet); } static void update_default_sink (CsdMediaKeysManager *manager) { GvcMixerStream *stream; stream = gvc_mixer_control_get_default_sink (manager->priv->volume); if (stream == manager->priv->stream) return; if (manager->priv->stream != NULL) { g_object_unref (manager->priv->stream); manager->priv->stream = NULL; } if (stream != NULL) { manager->priv->stream = g_object_ref (stream); } else { g_warning ("Unable to get default sink"); } } static void update_default_source (CsdMediaKeysManager *manager) { GvcMixerStream *stream; stream = gvc_mixer_control_get_default_source (manager->priv->volume); if (stream == manager->priv->source_stream) return; if (manager->priv->source_stream != NULL) { g_object_unref (manager->priv->source_stream); manager->priv->source_stream = NULL; } if (stream != NULL) { manager->priv->source_stream = g_object_ref (stream); } else { g_warning ("Unable to get default source"); } } static void on_control_state_changed (GvcMixerControl *control, GvcMixerControlState new_state, CsdMediaKeysManager *manager) { update_default_sink (manager); update_default_source (manager); } static void on_control_default_sink_changed (GvcMixerControl *control, guint id, CsdMediaKeysManager *manager) { update_default_sink (manager); } static void on_control_default_source_changed (GvcMixerControl *control, guint id, CsdMediaKeysManager *manager) { update_default_source (manager); } #ifdef HAVE_GUDEV static gboolean remove_stream (gpointer key, gpointer value, gpointer id) { if (GPOINTER_TO_UINT (value) == GPOINTER_TO_UINT (id)) return TRUE; return FALSE; } #endif /* HAVE_GUDEV */ static void on_control_stream_removed (GvcMixerControl *control, guint id, CsdMediaKeysManager *manager) { if (manager->priv->stream != NULL) { if (gvc_mixer_stream_get_id (manager->priv->stream) == id) { g_object_unref (manager->priv->stream); manager->priv->stream = NULL; } } if (manager->priv->source_stream != NULL) { if (gvc_mixer_stream_get_id (manager->priv->source_stream) == id) { g_object_unref (manager->priv->source_stream); manager->priv->source_stream = NULL; } } #ifdef HAVE_GUDEV g_hash_table_foreach_remove (manager->priv->streams, (GHRFunc) remove_stream, GUINT_TO_POINTER (id)); #endif } static void free_media_player (MediaPlayer *player) { if (player->watch_id > 0) { g_bus_unwatch_name (player->watch_id); player->watch_id = 0; } g_free (player->application); g_free (player->name); g_free (player); } static gint find_by_application (gconstpointer a, gconstpointer b) { return strcmp (((MediaPlayer *)a)->application, b); } static gint find_by_name (gconstpointer a, gconstpointer b) { return strcmp (((MediaPlayer *)a)->name, b); } static gint find_by_time (gconstpointer a, gconstpointer b) { return ((MediaPlayer *)a)->time < ((MediaPlayer *)b)->time; } static void name_vanished_handler (GDBusConnection *connection, const gchar *name, CsdMediaKeysManager *manager) { GList *iter; iter = g_list_find_custom (manager->priv->media_players, name, find_by_name); if (iter != NULL) { MediaPlayer *player; player = iter->data; g_debug ("Deregistering vanished %s (name: %s)", player->application, player->name); free_media_player (player); manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter); } } /* * Register a new media player. Most applications will want to call * this with time = GDK_CURRENT_TIME. This way, the last registered * player will receive media events. In some cases, applications * may want to register with a lower priority (usually 1), to grab * events only nobody is interested. */ static void csd_media_keys_manager_grab_media_player_keys (CsdMediaKeysManager *manager, const char *application, const char *name, guint32 time) { GList *iter; MediaPlayer *media_player; guint watch_id; if (time == GDK_CURRENT_TIME) { GTimeVal tv; g_get_current_time (&tv); time = tv.tv_sec * 1000 + tv.tv_usec / 1000; } iter = g_list_find_custom (manager->priv->media_players, application, find_by_application); if (iter != NULL) { if (((MediaPlayer *)iter->data)->time < time) { MediaPlayer *player = iter->data; free_media_player (player); manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter); } else { return; } } watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, name, G_BUS_NAME_WATCHER_FLAGS_NONE, NULL, (GBusNameVanishedCallback) name_vanished_handler, manager, NULL); g_debug ("Registering %s at %u", application, time); media_player = g_new0 (MediaPlayer, 1); media_player->application = g_strdup (application); media_player->name = g_strdup (name); media_player->time = time; media_player->watch_id = watch_id; manager->priv->media_players = g_list_insert_sorted (manager->priv->media_players, media_player, find_by_time); } static void csd_media_keys_manager_release_media_player_keys (CsdMediaKeysManager *manager, const char *application, const char *name) { GList *iter = NULL; g_return_if_fail (application != NULL || name != NULL); if (application != NULL) { iter = g_list_find_custom (manager->priv->media_players, application, find_by_application); } if (iter == NULL && name != NULL) { iter = g_list_find_custom (manager->priv->media_players, name, find_by_name); } if (iter != NULL) { MediaPlayer *player; player = iter->data; g_debug ("Deregistering %s (name: %s)", application, player->name); free_media_player (player); manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter); } } static gboolean csd_media_player_key_pressed (CsdMediaKeysManager *manager, const char *key) { const char *application; gboolean have_listeners; GError *error = NULL; MediaPlayer *player; g_return_val_if_fail (key != NULL, FALSE); g_debug ("Media key '%s' pressed", key); have_listeners = (manager->priv->media_players != NULL); if (!have_listeners) { if (!mpris_controller_key (manager->priv->mpris_controller, key)) { /* Popup a dialog with an (/) icon */ show_osd (manager, "action-unavailable-symbolic", -1); } return TRUE; } player = manager->priv->media_players->data; application = player->application; if (g_dbus_connection_emit_signal (manager->priv->connection, player->name, CSD_MEDIA_KEYS_DBUS_PATH, CSD_MEDIA_KEYS_DBUS_NAME, "MediaPlayerKeyPressed", g_variant_new ("(ss)", application ? application : "", key), &error) == FALSE) { g_debug ("Error emitting signal: %s", error->message); g_error_free (error); } return !have_listeners; } static void csd_media_keys_manager_handle_cinnamon_keybinding (CsdMediaKeysManager *manager, guint deviceid, CDesktopMediaKeyType type, gint64 timestamp) { do_action (manager, deviceid, type, timestamp); } 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) { CsdMediaKeysManager *manager = (CsdMediaKeysManager *) user_data; g_debug ("Calling method '%s' for media-keys", method_name); if (g_strcmp0 (method_name, "ReleaseMediaPlayerKeys") == 0) { const char *app_name; g_variant_get (parameters, "(&s)", &app_name); csd_media_keys_manager_release_media_player_keys (manager, app_name, sender); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "GrabMediaPlayerKeys") == 0) { const char *app_name; guint32 time; g_variant_get (parameters, "(&su)", &app_name, &time); csd_media_keys_manager_grab_media_player_keys (manager, app_name, sender, time); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "HandleKeybinding") == 0) { CDesktopMediaKeyType action; g_variant_get (parameters, "(u)", &action); csd_media_keys_manager_handle_cinnamon_keybinding (manager, 0, action, CurrentTime); g_dbus_method_invocation_return_value (invocation, NULL); } } static const GDBusInterfaceVTable interface_vtable = { handle_method_call, NULL, /* Get Property */ NULL, /* Set Property */ }; static gboolean do_multimedia_player_action (CsdMediaKeysManager *manager, const char *icon, const char *key) { return csd_media_player_key_pressed (manager, key); } static void on_xrandr_action_call_finished (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GError *error = NULL; GVariant *variant; char *action; action = g_object_get_data (G_OBJECT (source_object), "csd-media-keys-manager-xrandr-action"); variant = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); g_object_unref (manager->priv->cancellable); manager->priv->cancellable = NULL; if (error != NULL) { g_warning ("Unable to call '%s': %s", action, error->message); g_error_free (error); } else { g_variant_unref (variant); } g_free (action); } static void do_xrandr_action (CsdMediaKeysManager *manager, const char *action, gint64 timestamp) { CsdMediaKeysManagerPrivate *priv = manager->priv; if (priv->connection == NULL || 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; } priv->cancellable = g_cancellable_new (); g_object_set_data (G_OBJECT (priv->xrandr_proxy), "csd-media-keys-manager-xrandr-action", g_strdup (action)); g_dbus_proxy_call (priv->xrandr_proxy, action, g_variant_new ("(x)", timestamp), G_DBUS_CALL_FLAGS_NONE, -1, priv->cancellable, (GAsyncReadyCallback) on_xrandr_action_call_finished, manager); } static gboolean do_video_out_action (CsdMediaKeysManager *manager, gint64 timestamp) { do_xrandr_action (manager, "VideoModeSwitch", timestamp); return FALSE; } static gboolean do_video_rotate_action (CsdMediaKeysManager *manager, gint64 timestamp) { do_xrandr_action (manager, "Rotate", timestamp); return FALSE; } static void do_toggle_accessibility_key (const char *key) { GSettings *settings; gboolean state; settings = g_settings_new ("org.cinnamon.desktop.a11y.applications"); state = g_settings_get_boolean (settings, key); g_settings_set_boolean (settings, key, !state); g_object_unref (settings); } static void do_screenreader_action (CsdMediaKeysManager *manager) { do_toggle_accessibility_key ("screen-reader-enabled"); } static void do_on_screen_keyboard_action (CsdMediaKeysManager *manager) { do_toggle_accessibility_key ("screen-keyboard-enabled"); } static void do_text_size_action (CsdMediaKeysManager *manager, CDesktopMediaKeyType type) { gdouble factor, best, distance; guint i; /* Same values used in the Seeing tab of the Universal Access panel */ static gdouble factors[] = { 0.75, 1.0, 1.25, 1.5 }; /* Figure out the current DPI scaling factor */ factor = g_settings_get_double (manager->priv->interface_settings, "text-scaling-factor"); factor += (type == C_DESKTOP_MEDIA_KEY_INCREASE_TEXT ? 0.25 : -0.25); /* Try to find a matching value */ distance = 1e6; best = 1.0; for (i = 0; i < G_N_ELEMENTS(factors); i++) { gdouble d; d = fabs (factor - factors[i]); if (d < distance) { best = factors[i]; distance = d; } } if (best == 1.0) g_settings_reset (manager->priv->interface_settings, "text-scaling-factor"); else g_settings_set_double (manager->priv->interface_settings, "text-scaling-factor", best); } static void do_toggle_contrast_action (CsdMediaKeysManager *manager) { gboolean high_contrast; char *theme; /* Are we using HighContrast now? */ theme = g_settings_get_string (manager->priv->interface_settings, "gtk-theme"); high_contrast = g_str_equal (theme, HIGH_CONTRAST); g_free (theme); if (high_contrast != FALSE) { if (manager->priv->gtk_theme == NULL) g_settings_reset (manager->priv->interface_settings, "gtk-theme"); else g_settings_set (manager->priv->interface_settings, "gtk-theme", manager->priv->gtk_theme); g_settings_set (manager->priv->interface_settings, "icon-theme", manager->priv->icon_theme); } else { g_settings_set (manager->priv->interface_settings, "gtk-theme", HIGH_CONTRAST); g_settings_set (manager->priv->interface_settings, "icon-theme", HIGH_CONTRAST); } } static void do_config_power_action (CsdMediaKeysManager *manager, const gchar *config_key) { CsdPowerActionType action_type; action_type = g_settings_get_enum (manager->priv->power_settings, config_key); switch (action_type) { case CSD_POWER_ACTION_SUSPEND: csd_power_suspend (manager->priv->use_logind, manager->priv->upower_proxy); break; case CSD_POWER_ACTION_INTERACTIVE: cinnamon_session_shutdown (manager); break; case CSD_POWER_ACTION_SHUTDOWN: //FIXME: A wee bit cheating here... execute (manager, "dbus-send --dest=org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.RequestShutdown", FALSE); break; case CSD_POWER_ACTION_HIBERNATE: csd_power_hibernate (manager->priv->use_logind, manager->priv->upower_proxy); break; case CSD_POWER_ACTION_BLANK: execute (manager, "cinnamon-screensaver-command --lock", FALSE); break; case CSD_POWER_ACTION_NOTHING: /* these actions cannot be handled by media-keys and * are not used in this context */ break; } } static void update_screen_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; guint percentage; GVariant *new_percentage; CsdMediaKeysManager *manager = CSD_MEDIA_KEYS_MANAGER (user_data); new_percentage = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (new_percentage == NULL) { g_warning ("Failed to set new screen percentage: %s", error->message); g_error_free (error); return; } /* update the dialog with the new value */ g_variant_get (new_percentage, "(u)", &percentage); show_osd (manager, "display-brightness-symbolic", percentage); g_variant_unref (new_percentage); } static void do_screen_brightness_action_real (GObject *source_object, GAsyncResult *res, gpointer user_data) { CsdBrightnessActionData *data = (CsdBrightnessActionData *) user_data; CsdMediaKeysManager *manager = data->manager; GError *error = NULL; GVariant *old_percentage = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (old_percentage == NULL) { g_warning ("Failed to get old screen percentage: %s", error->message); g_error_free (error); g_free (data); return; } g_variant_get (old_percentage, "(u)", &data->old_percentage); /* call into the power plugin */ g_dbus_proxy_call (manager->priv->power_screen_proxy, data->type == C_DESKTOP_MEDIA_KEY_SCREEN_BRIGHTNESS_UP ? "StepUp" : "StepDown", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, update_screen_cb, manager); g_variant_unref (old_percentage); } static void do_screen_brightness_action (CsdMediaKeysManager *manager, CDesktopMediaKeyType type) { if (manager->priv->connection == NULL || manager->priv->power_screen_proxy == NULL) { g_warning ("No existing D-Bus connection trying to handle power keys"); return; } CsdBrightnessActionData *data = g_new0 (CsdBrightnessActionData, 1); data->manager = manager; data->type = type; g_dbus_proxy_call (manager->priv->power_screen_proxy, "GetPercentage", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, do_screen_brightness_action_real, data); } static void update_keyboard_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; guint percentage; GVariant *new_percentage; CsdMediaKeysManager *manager = CSD_MEDIA_KEYS_MANAGER (user_data); new_percentage = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); if (new_percentage == NULL) { g_warning ("Failed to set new keyboard percentage: %s", error->message); g_error_free (error); return; } /* update the dialog with the new value */ g_variant_get (new_percentage, "(u)", &percentage); show_osd (manager, "keyboard-brightness-symbolic", percentage); g_variant_unref (new_percentage); } static void do_keyboard_brightness_action (CsdMediaKeysManager *manager, CDesktopMediaKeyType type) { const char *cmd; if (manager->priv->connection == NULL || manager->priv->power_keyboard_proxy == NULL) { g_warning ("No existing D-Bus connection trying to handle power keys"); return; } switch (type) { case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_UP: cmd = "StepUp"; break; case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_DOWN: cmd = "StepDown"; break; case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_TOGGLE: cmd = "Toggle"; break; default: g_assert_not_reached (); } /* call into the power plugin */ g_dbus_proxy_call (manager->priv->power_keyboard_proxy, cmd, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, update_keyboard_cb, manager); } static gboolean do_action (CsdMediaKeysManager *manager, guint deviceid, CDesktopMediaKeyType type, gint64 timestamp) { char *cmd; g_debug ("Launching action for key type '%d' (on device id %d)", type, deviceid); switch (type) { case C_DESKTOP_MEDIA_KEY_TOUCHPAD: do_touchpad_action (manager); break; case C_DESKTOP_MEDIA_KEY_TOUCHPAD_ON: do_touchpad_osd_action (manager, TRUE); break; case C_DESKTOP_MEDIA_KEY_TOUCHPAD_OFF: do_touchpad_osd_action (manager, FALSE); break; case C_DESKTOP_MEDIA_KEY_MUTE: case C_DESKTOP_MEDIA_KEY_VOLUME_DOWN: case C_DESKTOP_MEDIA_KEY_VOLUME_UP: case C_DESKTOP_MEDIA_KEY_MIC_MUTE: do_sound_action (manager, deviceid, type, FALSE); break; case C_DESKTOP_MEDIA_KEY_MUTE_QUIET: do_sound_action (manager, deviceid, C_DESKTOP_MEDIA_KEY_MUTE, TRUE); break; case C_DESKTOP_MEDIA_KEY_VOLUME_DOWN_QUIET: do_sound_action (manager, deviceid, C_DESKTOP_MEDIA_KEY_VOLUME_DOWN, TRUE); break; case C_DESKTOP_MEDIA_KEY_VOLUME_UP_QUIET: do_sound_action (manager, deviceid, C_DESKTOP_MEDIA_KEY_VOLUME_UP, TRUE); break; case C_DESKTOP_MEDIA_KEY_LOGOUT: do_logout_action (manager); break; case C_DESKTOP_MEDIA_KEY_EJECT: do_eject_action (manager); break; case C_DESKTOP_MEDIA_KEY_HOME: do_home_key_action (manager, timestamp); break; case C_DESKTOP_MEDIA_KEY_SEARCH: cmd = NULL; if ((cmd = g_find_program_in_path ("tracker-search-tool"))) do_execute_desktop (manager, "tracker-needle.desktop", timestamp); else do_execute_desktop (manager, "gnome-search-tool.desktop", timestamp); g_free (cmd); break; case C_DESKTOP_MEDIA_KEY_EMAIL: do_url_action (manager, "mailto", timestamp); break; case C_DESKTOP_MEDIA_KEY_SCREENSAVER: execute (manager, "cinnamon-screensaver-command --lock", FALSE); break; case C_DESKTOP_MEDIA_KEY_HELP: do_url_action (manager, "ghelp", timestamp); break; case C_DESKTOP_MEDIA_KEY_SCREENSHOT: execute (manager, "gnome-screenshot", FALSE); break; case C_DESKTOP_MEDIA_KEY_WINDOW_SCREENSHOT: execute (manager, "gnome-screenshot --window", FALSE); break; case C_DESKTOP_MEDIA_KEY_AREA_SCREENSHOT: execute (manager, "gnome-screenshot --area", FALSE); break; case C_DESKTOP_MEDIA_KEY_SCREENSHOT_CLIP: execute (manager, "gnome-screenshot --clipboard", FALSE); break; case C_DESKTOP_MEDIA_KEY_WINDOW_SCREENSHOT_CLIP: execute (manager, "gnome-screenshot --window --clipboard", FALSE); break; case C_DESKTOP_MEDIA_KEY_AREA_SCREENSHOT_CLIP: execute (manager, "gnome-screenshot --area --clipboard", FALSE); break; case C_DESKTOP_MEDIA_KEY_TERMINAL: do_terminal_action (manager); break; case C_DESKTOP_MEDIA_KEY_WWW: do_url_action (manager, "http", timestamp); break; case C_DESKTOP_MEDIA_KEY_MEDIA: do_media_action (manager, timestamp); break; case C_DESKTOP_MEDIA_KEY_CALCULATOR: if ((cmd = g_find_program_in_path ("gnome-calculator"))) { execute (manager, "gnome-calculator", FALSE); } else if ((cmd = g_find_program_in_path ("galculator"))) { execute (manager, "galculator", FALSE); } else { execute (manager, "mate-calc", FALSE); } g_free (cmd); break; case C_DESKTOP_MEDIA_KEY_PLAY: return do_multimedia_player_action (manager, NULL, "Play"); case C_DESKTOP_MEDIA_KEY_PAUSE: return do_multimedia_player_action (manager, NULL, "Pause"); case C_DESKTOP_MEDIA_KEY_STOP: return do_multimedia_player_action (manager, NULL, "Stop"); case C_DESKTOP_MEDIA_KEY_PREVIOUS: return do_multimedia_player_action (manager, NULL, "Previous"); case C_DESKTOP_MEDIA_KEY_NEXT: return do_multimedia_player_action (manager, NULL, "Next"); case C_DESKTOP_MEDIA_KEY_REWIND: return do_multimedia_player_action (manager, NULL, "Rewind"); case C_DESKTOP_MEDIA_KEY_FORWARD: return do_multimedia_player_action (manager, NULL, "FastForward"); case C_DESKTOP_MEDIA_KEY_REPEAT: return do_multimedia_player_action (manager, NULL, "Repeat"); case C_DESKTOP_MEDIA_KEY_RANDOM: return do_multimedia_player_action (manager, NULL, "Shuffle"); case C_DESKTOP_MEDIA_KEY_VIDEO_OUT: do_video_out_action (manager, timestamp); break; case C_DESKTOP_MEDIA_KEY_ROTATE_VIDEO: do_video_rotate_action (manager, timestamp); break; case C_DESKTOP_MEDIA_KEY_SCREENREADER: do_screenreader_action (manager); break; case C_DESKTOP_MEDIA_KEY_ON_SCREEN_KEYBOARD: do_on_screen_keyboard_action (manager); break; case C_DESKTOP_MEDIA_KEY_INCREASE_TEXT: case C_DESKTOP_MEDIA_KEY_DECREASE_TEXT: do_text_size_action (manager, type); break; case C_DESKTOP_MEDIA_KEY_TOGGLE_CONTRAST: do_toggle_contrast_action (manager); break; case C_DESKTOP_MEDIA_KEY_SHUTDOWN: do_config_power_action (manager, "button-power"); break; case C_DESKTOP_MEDIA_KEY_SUSPEND: do_config_power_action (manager, "button-suspend"); break; case C_DESKTOP_MEDIA_KEY_HIBERNATE: do_config_power_action (manager, "button-hibernate"); break; case C_DESKTOP_MEDIA_KEY_SCREEN_BRIGHTNESS_UP: case C_DESKTOP_MEDIA_KEY_SCREEN_BRIGHTNESS_DOWN: do_screen_brightness_action (manager, type); break; case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_UP: case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_DOWN: case C_DESKTOP_MEDIA_KEY_KEYBOARD_BRIGHTNESS_TOGGLE: do_keyboard_brightness_action (manager, type); break; case C_DESKTOP_MEDIA_KEY_BATTERY: do_execute_desktop (manager, "gnome-power-statistics.desktop", timestamp); break; /* Note, no default so compiler catches missing keys */ case C_DESKTOP_MEDIA_KEY_SEPARATOR: g_assert_not_reached (); } return FALSE; } static void update_theme_settings (GSettings *settings, const char *key, CsdMediaKeysManager *manager) { char *theme; theme = g_settings_get_string (manager->priv->interface_settings, key); if (g_str_equal (theme, HIGH_CONTRAST)) { g_free (theme); } else { if (g_str_equal (key, "gtk-theme")) { g_free (manager->priv->gtk_theme); manager->priv->gtk_theme = theme; } else { g_free (manager->priv->icon_theme); manager->priv->icon_theme = theme; } } } static gboolean start_media_keys_idle_cb (CsdMediaKeysManager *manager) { g_debug ("Starting media_keys manager"); cinnamon_settings_profile_start (NULL); gvc_mixer_control_open (manager->priv->volume); /* 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.gnome.VolumeControl", NULL); manager->priv->session_settings = g_settings_new("org.cinnamon.desktop.session"); manager->priv->use_logind = g_settings_get_boolean (manager->priv->session_settings, "settings-daemon-uses-logind"); /* for the power plugin interface code */ manager->priv->power_settings = g_settings_new (SETTINGS_POWER_DIR); /* Logic from http://git.gnome.org/browse/gnome-shell/tree/js/ui/status/accessibility.js#n163 */ manager->priv->interface_settings = g_settings_new (SETTINGS_INTERFACE_DIR); g_signal_connect (G_OBJECT (manager->priv->interface_settings), "changed::gtk-theme", G_CALLBACK (update_theme_settings), manager); g_signal_connect (G_OBJECT (manager->priv->interface_settings), "changed::icon-theme", G_CALLBACK (update_theme_settings), manager); manager->priv->gtk_theme = g_settings_get_string (manager->priv->interface_settings, "gtk-theme"); if (g_str_equal (manager->priv->gtk_theme, HIGH_CONTRAST)) { g_free (manager->priv->gtk_theme); manager->priv->gtk_theme = NULL; } manager->priv->icon_theme = g_settings_get_string (manager->priv->interface_settings, "icon-theme"); init_screens (manager); g_debug ("Starting mpris controller"); manager->priv->mpris_controller = mpris_controller_new (); cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } gboolean csd_media_keys_manager_start (CsdMediaKeysManager *manager, GError **error) { const char * const subsystems[] = { "input", "usb", "sound", NULL }; cinnamon_settings_profile_start (NULL); #ifdef HAVE_GUDEV manager->priv->streams = g_hash_table_new (g_direct_hash, g_direct_equal); manager->priv->udev_client = g_udev_client_new (subsystems); #endif /* initialise Volume handler * * We do this one here to force checking gstreamer cache, etc. * The rest (grabbing and setting the keys) can happen in an * idle. */ cinnamon_settings_profile_start ("gvc_mixer_control_new"); manager->priv->volume = gvc_mixer_control_new ("Cinnamon Volume Control Media Keys"); g_signal_connect (manager->priv->volume, "state-changed", G_CALLBACK (on_control_state_changed), manager); g_signal_connect (manager->priv->volume, "default-sink-changed", G_CALLBACK (on_control_default_sink_changed), manager); g_signal_connect (manager->priv->volume, "default-source-changed", G_CALLBACK (on_control_default_source_changed), manager); g_signal_connect (manager->priv->volume, "stream-removed", G_CALLBACK (on_control_stream_removed), manager); cinnamon_settings_profile_end ("gvc_mixer_control_new"); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_media_keys_idle_cb, manager); register_manager (manager_object); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_media_keys_manager_stop (CsdMediaKeysManager *manager) { CsdMediaKeysManagerPrivate *priv = manager->priv; GList *l; g_debug ("Stopping media_keys manager"); if (priv->bus_cancellable != NULL) { g_cancellable_cancel (priv->bus_cancellable); g_object_unref (priv->bus_cancellable); priv->bus_cancellable = NULL; } if (manager->priv->ca) { ca_context_destroy (manager->priv->ca); manager->priv->ca = NULL; } #ifdef HAVE_GUDEV if (priv->streams) { g_hash_table_destroy (priv->streams); priv->streams = NULL; } if (priv->udev_client) { g_object_unref (priv->udev_client); priv->udev_client = NULL; } #endif /* HAVE_GUDEV */ if (priv->logind_proxy) { g_object_unref (priv->logind_proxy); priv->logind_proxy = NULL; } if (priv->power_settings) { g_object_unref (priv->power_settings); priv->power_settings = NULL; } if (priv->power_screen_proxy) { g_object_unref (priv->power_screen_proxy); priv->power_screen_proxy = NULL; } if (priv->power_keyboard_proxy) { g_object_unref (priv->power_keyboard_proxy); priv->power_keyboard_proxy = NULL; } if (priv->mpris_controller) { g_object_unref (priv->mpris_controller); priv->mpris_controller = NULL; } if (priv->upower_proxy) { g_object_unref (priv->upower_proxy); priv->upower_proxy = NULL; } if (priv->osd_proxy) { g_object_unref (priv->osd_proxy); priv->osd_proxy = NULL; } if (priv->cancellable != NULL) { g_cancellable_cancel (priv->cancellable); g_object_unref (priv->cancellable); priv->cancellable = NULL; } if (priv->introspection_data) { g_dbus_node_info_unref (priv->introspection_data); priv->introspection_data = NULL; } if (priv->kb_introspection_data) { g_dbus_node_info_unref (priv->kb_introspection_data); priv->kb_introspection_data = NULL; } if (priv->connection != NULL) { g_object_unref (priv->connection); priv->connection = NULL; } if (priv->volume_notification != NULL) { notify_notification_close (priv->volume_notification, NULL); g_object_unref (priv->volume_notification); priv->volume_notification = NULL; } if (priv->brightness_notification != NULL) { notify_notification_close (priv->brightness_notification, NULL); g_object_unref (priv->brightness_notification); priv->brightness_notification = NULL; } if (priv->kb_backlight_notification != NULL) { notify_notification_close (priv->kb_backlight_notification, NULL); g_object_unref (priv->kb_backlight_notification); priv->kb_backlight_notification = NULL; } if (priv->osd_cancellable != NULL) { g_cancellable_cancel (priv->osd_cancellable); g_object_unref (priv->osd_cancellable); priv->osd_cancellable = NULL; } if (priv->screens != NULL) { g_slist_free (priv->screens); priv->screens = NULL; } if (priv->stream) { g_object_unref (priv->stream); priv->stream = NULL; } if (priv->volume) { g_object_unref (priv->volume); priv->volume = NULL; } if (priv->dialog != NULL) { gtk_widget_destroy (priv->dialog); priv->dialog = NULL; } if (priv->media_players != NULL) { for (l = priv->media_players; l; l = l->next) { MediaPlayer *mp = l->data; g_free (mp->application); g_free (mp); } g_list_free (priv->media_players); priv->media_players = NULL; } } static GObject * csd_media_keys_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdMediaKeysManager *media_keys_manager; media_keys_manager = CSD_MEDIA_KEYS_MANAGER (G_OBJECT_CLASS (csd_media_keys_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (media_keys_manager); } static void csd_media_keys_manager_class_init (CsdMediaKeysManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_media_keys_manager_constructor; object_class->finalize = csd_media_keys_manager_finalize; g_type_class_add_private (klass, sizeof (CsdMediaKeysManagerPrivate)); } static void inhibit_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); CsdMediaKeysManager *manager = CSD_MEDIA_KEYS_MANAGER (user_data); GError *error = NULL; GVariant *res; GUnixFDList *fd_list = NULL; gint idx; res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error); if (res == NULL) { g_warning ("Unable to inhibit keypresses: %s", error->message); g_error_free (error); } else { g_variant_get (res, "(h)", &idx); manager->priv->inhibit_keys_fd = g_unix_fd_list_get (fd_list, idx, &error); if (manager->priv->inhibit_keys_fd == -1) { g_warning ("Failed to receive system inhibitor fd: %s", error->message); g_error_free (error); } g_debug ("System inhibitor fd is %d", manager->priv->inhibit_keys_fd); g_object_unref (fd_list); g_variant_unref (res); } } static void csd_media_keys_manager_init (CsdMediaKeysManager *manager) { GError *error; GDBusConnection *bus; error = NULL; manager->priv = CSD_MEDIA_KEYS_MANAGER_GET_PRIVATE (manager); bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (bus == NULL) { g_warning ("Failed to connect to system bus: %s", error->message); g_error_free (error); return; } manager->priv->logind_proxy = g_dbus_proxy_new_sync (bus, 0, NULL, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, NULL, &error); if (manager->priv->logind_proxy == NULL) { g_warning ("Failed to connect to logind: %s", error->message); g_error_free (error); } g_object_unref (bus); g_debug ("Adding system inhibitors for power keys"); manager->priv->inhibit_keys_fd = -1; g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy, "Inhibit", g_variant_new ("(ssss)", "handle-power-key:handle-suspend-key:handle-hibernate-key", g_get_user_name (), "Cinnamon handling keypresses", "block"), 0, G_MAXINT, NULL, NULL, inhibit_done, manager); } static void csd_media_keys_manager_finalize (GObject *object) { CsdMediaKeysManager *media_keys_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_MEDIA_KEYS_MANAGER (object)); media_keys_manager = CSD_MEDIA_KEYS_MANAGER (object); g_return_if_fail (media_keys_manager->priv != NULL); if (media_keys_manager->priv->start_idle_id != 0) { g_source_remove (media_keys_manager->priv->start_idle_id); media_keys_manager->priv->start_idle_id = 0; } if (media_keys_manager->priv->inhibit_keys_fd != -1) close (media_keys_manager->priv->inhibit_keys_fd); G_OBJECT_CLASS (csd_media_keys_manager_parent_class)->finalize (object); } static void xrandr_ready_cb (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { 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); } } static void upower_ready_cb (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GError *error = NULL; manager->priv->upower_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->upower_proxy == NULL) { g_warning ("Failed to get proxy for upower: %s", error->message); g_error_free (error); } } static void power_screen_ready_cb (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GError *error = NULL; manager->priv->power_screen_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->power_screen_proxy == NULL) { g_warning ("Failed to get proxy for power (screen): %s", error->message); g_error_free (error); } } static void power_keyboard_ready_cb (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GError *error = NULL; manager->priv->power_keyboard_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->power_keyboard_proxy == NULL) { g_warning ("Failed to get proxy for power (keyboard): %s", error->message); g_error_free (error); } } static void osd_ready_cb (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *manager) { GError *error = NULL; manager->priv->osd_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->osd_proxy == NULL) { g_warning ("Failed to get proxy for OSD operations: %s", error->message); g_error_free (error); } } static void on_bus_gotten (GObject *source_object, GAsyncResult *res, CsdMediaKeysManager *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, CSD_MEDIA_KEYS_DBUS_PATH, manager->priv->introspection_data->interfaces[0], &interface_vtable, manager, NULL, NULL); g_dbus_connection_register_object (connection, CINNAMON_KEYBINDINGS_PATH, manager->priv->kb_introspection_data->interfaces[0], &interface_vtable, manager, NULL, NULL); g_dbus_proxy_new (manager->priv->connection, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.cinnamon.SettingsDaemon", "/org/cinnamon/SettingsDaemon/XRANDR", "org.cinnamon.SettingsDaemon.XRANDR_2", NULL, (GAsyncReadyCallback) xrandr_ready_cb, manager); g_dbus_proxy_new (manager->priv->connection, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.cinnamon.SettingsDaemon", "/org/cinnamon/SettingsDaemon/Power", "org.cinnamon.SettingsDaemon.Power.Screen", NULL, (GAsyncReadyCallback) power_screen_ready_cb, manager); g_dbus_proxy_new (manager->priv->connection, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.cinnamon.SettingsDaemon", "/org/cinnamon/SettingsDaemon/Power", "org.cinnamon.SettingsDaemon.Power.Keyboard", NULL, (GAsyncReadyCallback) power_keyboard_ready_cb, manager); g_dbus_proxy_new (manager->priv->connection, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, "org.Cinnamon", "/org/Cinnamon", "org.Cinnamon", NULL, (GAsyncReadyCallback) osd_ready_cb, manager); } static void register_manager (CsdMediaKeysManager *manager) { manager->priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); manager->priv->kb_introspection_data = g_dbus_node_info_new_for_xml (kb_introspection_xml, NULL); manager->priv->bus_cancellable = g_cancellable_new (); g_assert (manager->priv->introspection_data != NULL); g_assert (manager->priv->kb_introspection_data != NULL); g_bus_get (G_BUS_TYPE_SESSION, manager->priv->bus_cancellable, (GAsyncReadyCallback) on_bus_gotten, manager); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.UPower", "/org/freedesktop/UPower", "org.freedesktop.UPower", NULL, (GAsyncReadyCallback) upower_ready_cb, manager); } CsdMediaKeysManager * csd_media_keys_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_MEDIA_KEYS_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_MEDIA_KEYS_MANAGER (manager_object); } cinnamon-settings-daemon-2.8.3/plugins/xsettings/0000775000175000017500000000000012625665665021105 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/xsettings/fontconfig-monitor.c0000664000175000017500000001145312625665665025076 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; g_type_init (); 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-2.8.3/plugins/xsettings/csd-xsettings-manager.c0000664000175000017500000012562312625665665025471 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 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 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 /* The minimum resolution at which we turn on a window-scale of 2 */ #define HIDPI_LIMIT (DPI_FALLBACK * 2) /* The minimum screen height at which we turn on a window-scale of 2; * below this there just isn't enough vertical real estate for GNOME * apps to work, and it's better to just be tiny */ #define HIDPI_MIN_HEIGHT 1500 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_class_init (CinnamonSettingsXSettingsManagerClass *klass); static void cinnamon_xsettings_manager_init (CinnamonSettingsXSettingsManager *xsettings_manager); 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 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-decoration-layout", "Gtk/DecorationLayout", 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.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; int window_scale; GdkRectangle rect; GdkDisplay *display; GdkScreen *screen; int width_mm, height_mm; int monitor_scale; double dpi_x, dpi_y; 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) { int primary; display = gdk_display_get_default (); screen = gdk_display_get_default_screen (display); primary = gdk_screen_get_primary_monitor (screen); gdk_screen_get_monitor_geometry (screen, primary, &rect); width_mm = gdk_screen_get_monitor_width_mm (screen, primary); height_mm = gdk_screen_get_monitor_height_mm (screen, primary); monitor_scale = gdk_screen_get_monitor_scale_factor (screen, primary); window_scale = 1; if (rect.height < HIDPI_MIN_HEIGHT) goto out; /* Some monitors/TV encode the aspect ratio (16/9 or 16/10) instead of the physical size */ if ((width_mm == 160 && height_mm == 90) || (width_mm == 160 && height_mm == 100) || (width_mm == 16 && height_mm == 9) || (width_mm == 16 && height_mm == 10)) goto out; if (width_mm > 0 && height_mm > 0) { dpi_x = (double)rect.width * monitor_scale / (width_mm / 25.4); dpi_y = (double)rect.height * monitor_scale / (height_mm / 25.4); /* We don't completely trust these values so both must be high, and never pick higher ratio than 2 automatically */ if (dpi_x > HIDPI_LIMIT && dpi_y > HIDPI_LIMIT) window_scale = 2; } } out: 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)) { 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, 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-2.8.3/plugins/xsettings/csd-xsettings-gtk.h0000664000175000017500000000414412625665665024643 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-2.8.3/plugins/xsettings/csd-xsettings-gtk.c0000664000175000017500000003016012625665665024633 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; } g_object_unref (info); } else { empty_cond_settings_list (gtk); } bail: 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-2.8.3/plugins/xsettings/xsettings-common.h0000664000175000017500000000442712625665665024603 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-2.8.3/plugins/xsettings/xsettings-manager.h0000664000175000017500000000524012625665665024717 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-2.8.3/plugins/xsettings/test-xsettings.c0000664000175000017500000000036512625665665024262 0ustar fabiofabio#define NEW cinnamon_xsettings_manager_new #define START cinnamon_xsettings_manager_start #define STOP cinnamon_xsettings_manager_stop #define MANAGER CinnamonSettingsXSettingsManager #include "csd-xsettings-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/xsettings/test-gtk-modules.c0000664000175000017500000000131612625665665024462 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; g_type_init (); 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-2.8.3/plugins/xsettings/xsettings-common.c0000664000175000017500000000561412625665665024575 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-2.8.3/plugins/xsettings/csd-xsettings-plugin.c0000664000175000017500000000661412625665665025353 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 "cinnamon-settings-plugin.h" #include "csd-xsettings-plugin.h" #include "csd-xsettings-manager.h" struct CinnamonSettingsXSettingsPluginPrivate { CinnamonSettingsXSettingsManager *manager; }; #define CINNAMON_XSETTINGS_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CINNAMON_TYPE_XSETTINGS_PLUGIN, CinnamonSettingsXSettingsPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CinnamonSettingsXSettingsPlugin, cinnamon_xsettings_plugin) static void cinnamon_xsettings_plugin_init (CinnamonSettingsXSettingsPlugin *plugin) { plugin->priv = CINNAMON_XSETTINGS_PLUGIN_GET_PRIVATE (plugin); g_debug ("CinnamonSettingsXSettingsPlugin initializing"); plugin->priv->manager = cinnamon_xsettings_manager_new (); } static void cinnamon_xsettings_plugin_finalize (GObject *object) { CinnamonSettingsXSettingsPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CINNAMON_IS_XSETTINGS_PLUGIN (object)); g_debug ("CinnamonSettingsXSettingsPlugin finalizing"); plugin = CINNAMON_XSETTINGS_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (cinnamon_xsettings_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating xsettings plugin"); error = NULL; res = cinnamon_xsettings_manager_start (CINNAMON_XSETTINGS_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start xsettings manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating xsettings plugin"); cinnamon_xsettings_manager_stop (CINNAMON_XSETTINGS_PLUGIN (plugin)->priv->manager); } static void cinnamon_xsettings_plugin_class_init (CinnamonSettingsXSettingsPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = cinnamon_xsettings_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CinnamonSettingsXSettingsPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/xsettings/csd-xsettings-manager.h0000664000175000017500000000514712625665665025474 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-2.8.3/plugins/xsettings/csd-xsettings-plugin.h0000664000175000017500000000465112625665665025357 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. * */ #ifndef __CINNAMON_XSETTINGS_PLUGIN_H__ #define __CINNAMON_XSETTINGS_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CINNAMON_TYPE_XSETTINGS_PLUGIN (cinnamon_xsettings_plugin_get_type ()) #define CINNAMON_XSETTINGS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CINNAMON_TYPE_XSETTINGS_PLUGIN, CinnamonSettingsXSettingsPlugin)) #define CINNAMON_XSETTINGS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CINNAMON_TYPE_XSETTINGS_PLUGIN, CinnamonSettingsXSettingsPluginClass)) #define CINNAMON_IS_XSETTINGS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CINNAMON_TYPE_XSETTINGS_PLUGIN)) #define CINNAMON_IS_XSETTINGS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CINNAMON_TYPE_XSETTINGS_PLUGIN)) #define CINNAMON_XSETTINGS_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CINNAMON_TYPE_XSETTINGS_PLUGIN, CinnamonSettingsXSettingsPluginClass)) typedef struct CinnamonSettingsXSettingsPluginPrivate CinnamonSettingsXSettingsPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CinnamonSettingsXSettingsPluginPrivate *priv; } CinnamonSettingsXSettingsPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CinnamonSettingsXSettingsPluginClass; GType cinnamon_xsettings_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CINNAMON_XSETTINGS_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/xsettings/Makefile.am0000664000175000017500000000473712625665665023154 0ustar fabiofabioNULL = plugin_name = xsettings noinst_PROGRAMS = test-gtk-modules test_gtk_modules_SOURCES = \ csd-xsettings-gtk.c \ csd-xsettings-gtk.h \ test-gtk-modules.c test_gtk_modules_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) test_gtk_modules_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(XSETTINGS_LIBS) \ $(SETTINGS_PLUGIN_LIBS) test_gtk_modules_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/data/ \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DGTK_MODULES_DIRECTORY=\""$(libdir)/cinnamon-settings-daemon-@CSD_API_VERSION@/gtk-modules/"\" \ $(AM_CPPFLAGS) libexec_PROGRAMS = csd-test-xsettings csd_test_xsettings_SOURCES = \ csd-xsettings-gtk.c \ csd-xsettings-gtk.h \ csd-xsettings-manager.c \ csd-xsettings-gtk.h \ xsettings-common.c \ xsettings-common.h \ xsettings-manager.c \ xsettings-manager.h \ fontconfig-monitor.c \ fontconfig-monitor.h \ test-xsettings.c csd_test_xsettings_CFLAGS = $(test_gtk_modules_CFLAGS) csd_test_xsettings_CPPFLAGS = $(test_gtk_modules_CPPFLAGS) -I$(top_srcdir)/plugins/common csd_test_xsettings_LDADD = $(test_gtk_modules_LDADD) plugin_LTLIBRARIES = \ libxsettings.la \ $(NULL) libxsettings_la_SOURCES = \ csd-xsettings-plugin.h \ csd-xsettings-plugin.c \ csd-xsettings-manager.h \ csd-xsettings-manager.c \ csd-xsettings-gtk.c \ csd-xsettings-gtk.h \ xsettings-common.h \ xsettings-common.c \ xsettings-manager.h \ xsettings-manager.c \ fontconfig-monitor.h \ fontconfig-monitor.c \ $(NULL) libxsettings_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/data/ \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DGTK_MODULES_DIRECTORY=\""$(libdir)/cinnamon-settings-daemon-@CSD_API_VERSION@/gtk-modules/"\" \ $(AM_CPPFLAGS) libxsettings_la_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(XSETTINGS_CFLAGS) \ $(AM_CFLAGS) libxsettings_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) \ $(NULL) libxsettings_la_LIBADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(SETTINGS_PLUGIN_LIBS) \ $(XSETTINGS_LIBS) \ $(NULL) plugin_in_files = \ xsettings.cinnamon-settings-plugin.in \ $(NULL) plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ README.xsettings \ $(plugin_in_files) \ $(NULL) CLEANFILES = \ $(plugin_DATA) \ $(NULL) DISTCLEANFILES = \ $(plugin_DATA) \ $(NULL) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/xsettings/README.xsettings0000664000175000017500000000260012625665665024012 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-2.8.3/plugins/xsettings/xsettings.cinnamon-settings-plugin.in0000664000175000017500000000026612625665665030424 0ustar fabiofabio[Cinnamon Settings Plugin] Module=xsettings IAge=0 _Name=X Settings _Description=Manage X Settings Authors=William Jon McCann Copyright=Copyright © 2007 William Jon McCann Website= cinnamon-settings-daemon-2.8.3/plugins/xsettings/xsettings-manager.c0000664000175000017500000002560712625665665024723 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-2.8.3/plugins/xsettings/fontconfig-monitor.h0000664000175000017500000000254412625665665025104 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-2.8.3/plugins/a11y-keyboard/0000775000175000017500000000000012625665665021426 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/a11y-keyboard/csd-a11y-keyboard-plugin.h0000664000175000017500000000450312625665665026215 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. * */ #ifndef __CSD_A11Y_KEYBOARD_PLUGIN_H__ #define __CSD_A11Y_KEYBOARD_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_A11Y_KEYBOARD_PLUGIN (csd_a11y_keyboard_plugin_get_type ()) #define CSD_A11Y_KEYBOARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_A11Y_KEYBOARD_PLUGIN, CsdA11yKeyboardPlugin)) #define CSD_A11Y_KEYBOARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_A11Y_KEYBOARD_PLUGIN, CsdA11yKeyboardPluginClass)) #define CSD_IS_A11Y_KEYBOARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_A11Y_KEYBOARD_PLUGIN)) #define CSD_IS_A11Y_KEYBOARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_A11Y_KEYBOARD_PLUGIN)) #define CSD_A11Y_KEYBOARD_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_A11Y_KEYBOARD_PLUGIN, CsdA11yKeyboardPluginClass)) typedef struct CsdA11yKeyboardPluginPrivate CsdA11yKeyboardPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdA11yKeyboardPluginPrivate *priv; } CsdA11yKeyboardPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdA11yKeyboardPluginClass; GType csd_a11y_keyboard_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_A11Y_KEYBOARD_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/a11y-keyboard/a11y-keyboard.cinnamon-settings-plugin.in0000664000175000017500000000030712625665665031262 0ustar fabiofabio[Cinnamon Settings Plugin] Module=a11y-keyboard IAge=0 _Name=Accessibility Keyboard _Description=Accessibility keyboard plugin Authors=Jody Goldberg Copyright=Copyright © 2001 Ximian, Inc. Website= cinnamon-settings-daemon-2.8.3/plugins/a11y-keyboard/test-a11y-keyboard.c0000664000175000017500000000035412625665665025122 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 #include "csd-a11y-keyboard-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/a11y-keyboard/csd-a11y-keyboard-manager.h0000664000175000017500000000475012625665665026335 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-2.8.3/plugins/a11y-keyboard/csd-a11y-preferences-dialog.c0000664000175000017500000004255412625665665026662 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_class_init (CsdA11yPreferencesDialogClass *klass); static void csd_a11y_preferences_dialog_init (CsdA11yPreferencesDialog *a11y_preferences_dialog); 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, "allow-shrink", FALSE, "allow-grow", 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-2.8.3/plugins/a11y-keyboard/csd-a11y-keyboard-plugin.c0000664000175000017500000000645312625665665026216 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 "cinnamon-settings-plugin.h" #include "csd-a11y-keyboard-plugin.h" #include "csd-a11y-keyboard-manager.h" struct CsdA11yKeyboardPluginPrivate { CsdA11yKeyboardManager *manager; }; #define CSD_A11Y_KEYBOARD_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_A11Y_KEYBOARD_PLUGIN, CsdA11yKeyboardPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdA11yKeyboardPlugin, csd_a11y_keyboard_plugin) static void csd_a11y_keyboard_plugin_init (CsdA11yKeyboardPlugin *plugin) { plugin->priv = CSD_A11Y_KEYBOARD_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdA11yKeyboardPlugin initializing"); plugin->priv->manager = csd_a11y_keyboard_manager_new (); } static void csd_a11y_keyboard_plugin_finalize (GObject *object) { CsdA11yKeyboardPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_A11Y_KEYBOARD_PLUGIN (object)); g_debug ("CsdA11yKeyboardPlugin finalizing"); plugin = CSD_A11Y_KEYBOARD_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_a11y_keyboard_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating a11y_keyboard plugin"); error = NULL; res = csd_a11y_keyboard_manager_start (CSD_A11Y_KEYBOARD_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start a11y_keyboard manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating a11y_keyboard plugin"); csd_a11y_keyboard_manager_stop (CSD_A11Y_KEYBOARD_PLUGIN (plugin)->priv->manager); } static void csd_a11y_keyboard_plugin_class_init (CsdA11yKeyboardPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_a11y_keyboard_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdA11yKeyboardPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/a11y-keyboard/test-a11y-preferences-dialog.c0000664000175000017500000000317512625665665027064 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-2.8.3/plugins/a11y-keyboard/csd-a11y-preferences-dialog.ui0000664000175000017500000002611712625665665027052 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-2.8.3/plugins/a11y-keyboard/Makefile.am0000664000175000017500000000532212625665665023464 0ustar fabiofabioNULL = plugin_name = a11y-keyboard gtkbuilderdir = $(pkgdatadir) gtkbuilder_DATA = \ csd-a11y-preferences-dialog.ui \ $(NULL) noinst_PROGRAMS = test-a11y-preferences-dialog libexec_PROGRAMS = csd-test-a11y-keyboard csd_test_a11y_keyboard_SOURCES = \ csd-a11y-keyboard-manager.h \ csd-a11y-keyboard-manager.c \ csd-a11y-preferences-dialog.c \ csd-a11y-preferences-dialog.h \ test-a11y-keyboard.c csd_test_a11y_keyboard_CFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ $(PLUGIN_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(APPINDICATOR_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_test_a11y_keyboard_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(LIBNOTIFY_LIBS) \ $(APPINDICATOR_LIBS) \ $(SETTINGS_PLUGIN_LIBS) test_a11y_preferences_dialog_SOURCES = \ csd-a11y-preferences-dialog.c \ csd-a11y-preferences-dialog.h \ test-a11y-preferences-dialog.c \ $(NULL) test_a11y_preferences_dialog_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DPIXMAPDIR=\""$(pkgdatadir)"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) test_a11y_preferences_dialog_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) test_a11y_preferences_dialog_LDADD = \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(NULL) plugin_LTLIBRARIES = \ liba11y-keyboard.la \ $(NULL) liba11y_keyboard_la_SOURCES = \ csd-a11y-keyboard-plugin.h \ csd-a11y-keyboard-plugin.c \ csd-a11y-keyboard-manager.h \ csd-a11y-keyboard-manager.c \ csd-a11y-preferences-dialog.h \ csd-a11y-preferences-dialog.c \ $(NULL) liba11y_keyboard_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DGTKBUILDERDIR=\""$(gtkbuilderdir)"\" \ $(AM_CPPFLAGS) liba11y_keyboard_la_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(LIBNOTIFY_CFLAGS) \ $(APPINDICATOR_CFLAGS) \ $(AM_CFLAGS) liba11y_keyboard_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) \ $(NULL) liba11y_keyboard_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(XF86MISC_LIBS) \ $(LIBNOTIFY_LIBS) \ $(APPINDICATOR_LIBS) \ $(NULL) plugin_in_files = \ a11y-keyboard.cinnamon-settings-plugin.in \ $(NULL) plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) \ $(gtkbuilder_DATA) \ $(NULL) CLEANFILES = \ $(plugin_DATA) \ $(NULL) DISTCLEANFILES = \ $(plugin_DATA) \ $(NULL) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/a11y-keyboard/csd-a11y-preferences-dialog.h0000664000175000017500000000441612625665665026662 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 */ cinnamon-settings-daemon-2.8.3/plugins/a11y-keyboard/csd-a11y-keyboard-manager.c0000664000175000017500000013365612625665665026340 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_class_init (CsdA11yKeyboardManagerClass *klass); static void csd_a11y_keyboard_manager_init (CsdA11yKeyboardManager *a11y_keyboard_manager); 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_error_trap_push (); 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_error_trap_pop_ignored (); 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); } /* toggle keys */ desc->ctrls->ax_options = set_clear (g_settings_get_boolean (settings, "togglekeys-enable"), desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_IndicatorFBMask); /* g_debug ("CHANGE to : 0x%x", desc->ctrls->enabled_ctrls); g_debug ("CHANGE to : 0x%x (2)", desc->ctrls->ax_options); */ gdk_error_trap_push (); 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_error_trap_pop_ignored (); 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); changed |= set_bool (settings, "togglekeys-enable", desc->ctrls->ax_options & XkbAX_IndicatorFBMask); 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-2.8.3/plugins/dummy/0000775000175000017500000000000012625665665020210 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/dummy/dummy.cinnamon-settings-plugin.in0000664000175000017500000000022012625665665026620 0ustar fabiofabio[Cinnamon Settings Plugin] Module=dummy IAge=0 _Name=Dummy _Description=Dummy plugin Authors=AUTHOR Copyright=Copyright © 2007 AUTHOR Website= cinnamon-settings-daemon-2.8.3/plugins/dummy/csd-dummy-manager.h0000664000175000017500000000437312625665665023702 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_DUMMY_MANAGER_H #define __CSD_DUMMY_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_DUMMY_MANAGER (csd_dummy_manager_get_type ()) #define CSD_DUMMY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_DUMMY_MANAGER, CsdDummyManager)) #define CSD_DUMMY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_DUMMY_MANAGER, CsdDummyManagerClass)) #define CSD_IS_DUMMY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_DUMMY_MANAGER)) #define CSD_IS_DUMMY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_DUMMY_MANAGER)) #define CSD_DUMMY_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_DUMMY_MANAGER, CsdDummyManagerClass)) typedef struct CsdDummyManagerPrivate CsdDummyManagerPrivate; typedef struct { GObject parent; CsdDummyManagerPrivate *priv; } CsdDummyManager; typedef struct { GObjectClass parent_class; } CsdDummyManagerClass; GType csd_dummy_manager_get_type (void); CsdDummyManager * csd_dummy_manager_new (void); gboolean csd_dummy_manager_start (CsdDummyManager *manager, GError **error); void csd_dummy_manager_stop (CsdDummyManager *manager); G_END_DECLS #endif /* __CSD_DUMMY_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/dummy/csd-dummy-plugin.h0000664000175000017500000000421312625665665023557 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. * */ #ifndef __CSD_DUMMY_PLUGIN_H__ #define __CSD_DUMMY_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_DUMMY_PLUGIN (csd_dummy_plugin_get_type ()) #define CSD_DUMMY_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_DUMMY_PLUGIN, CsdDummyPlugin)) #define CSD_DUMMY_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_DUMMY_PLUGIN, CsdDummyPluginClass)) #define CSD_IS_DUMMY_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_DUMMY_PLUGIN)) #define CSD_IS_DUMMY_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_DUMMY_PLUGIN)) #define CSD_DUMMY_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_DUMMY_PLUGIN, CsdDummyPluginClass)) typedef struct CsdDummyPluginPrivate CsdDummyPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdDummyPluginPrivate *priv; } CsdDummyPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdDummyPluginClass; GType csd_dummy_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_DUMMY_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/dummy/csd-dummy-manager.c0000664000175000017500000001222712625665665023672 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 #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-dummy-manager.h" #define CSD_DUMMY_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_DUMMY_MANAGER, CsdDummyManagerPrivate)) struct CsdDummyManagerPrivate { gboolean padding; }; enum { PROP_0, }; static void csd_dummy_manager_class_init (CsdDummyManagerClass *klass); static void csd_dummy_manager_init (CsdDummyManager *dummy_manager); static void csd_dummy_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdDummyManager, csd_dummy_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; gboolean csd_dummy_manager_start (CsdDummyManager *manager, GError **error) { g_debug ("Starting dummy manager"); cinnamon_settings_profile_start (NULL); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_dummy_manager_stop (CsdDummyManager *manager) { g_debug ("Stopping dummy manager"); } static void csd_dummy_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csd_dummy_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * csd_dummy_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdDummyManager *dummy_manager; dummy_manager = CSD_DUMMY_MANAGER (G_OBJECT_CLASS (csd_dummy_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (dummy_manager); } static void csd_dummy_manager_dispose (GObject *object) { G_OBJECT_CLASS (csd_dummy_manager_parent_class)->dispose (object); } static void csd_dummy_manager_class_init (CsdDummyManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = csd_dummy_manager_get_property; object_class->set_property = csd_dummy_manager_set_property; object_class->constructor = csd_dummy_manager_constructor; object_class->dispose = csd_dummy_manager_dispose; object_class->finalize = csd_dummy_manager_finalize; g_type_class_add_private (klass, sizeof (CsdDummyManagerPrivate)); } static void csd_dummy_manager_init (CsdDummyManager *manager) { manager->priv = CSD_DUMMY_MANAGER_GET_PRIVATE (manager); } static void csd_dummy_manager_finalize (GObject *object) { CsdDummyManager *dummy_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_DUMMY_MANAGER (object)); dummy_manager = CSD_DUMMY_MANAGER (object); g_return_if_fail (dummy_manager->priv != NULL); G_OBJECT_CLASS (csd_dummy_manager_parent_class)->finalize (object); } CsdDummyManager * csd_dummy_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_DUMMY_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_DUMMY_MANAGER (manager_object); } cinnamon-settings-daemon-2.8.3/plugins/dummy/Makefile.am0000664000175000017500000000162312625665665022246 0ustar fabiofabioplugin_name = dummy plugin_LTLIBRARIES = \ libdummy.la libdummy_la_SOURCES = \ csd-dummy-manager.c \ csd-dummy-manager.h \ csd-dummy-plugin.c \ csd-dummy-plugin.h libdummy_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libdummy_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) libdummy_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) libdummy_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) plugin_in_files = \ dummy.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) CLEANFILES = \ $(plugin_DATA) DISTCLEANFILES = \ $(plugin_DATA) @CSD_INTLTOOL_PLUGIN_RULE@ # override to _not_ install the test plugin # do not copy into your plugin install-pluginDATA: install-pluginLTLIBRARIES: cinnamon-settings-daemon-2.8.3/plugins/dummy/csd-dummy-plugin.c0000664000175000017500000000607412625665665023561 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 "cinnamon-settings-plugin.h" #include "csd-dummy-plugin.h" #include "csd-dummy-manager.h" struct CsdDummyPluginPrivate { CsdDummyManager *manager; }; #define CSD_DUMMY_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_DUMMY_PLUGIN, CsdDummyPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdDummyPlugin, csd_dummy_plugin) static void csd_dummy_plugin_init (CsdDummyPlugin *plugin) { plugin->priv = CSD_DUMMY_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdDummyPlugin initializing"); plugin->priv->manager = csd_dummy_manager_new (); } static void csd_dummy_plugin_finalize (GObject *object) { CsdDummyPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_DUMMY_PLUGIN (object)); g_debug ("CsdDummyPlugin finalizing"); plugin = CSD_DUMMY_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_dummy_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating dummy plugin"); error = NULL; res = csd_dummy_manager_start (CSD_DUMMY_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start dummy manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating dummy plugin"); csd_dummy_manager_stop (CSD_DUMMY_PLUGIN (plugin)->priv->manager); } static void csd_dummy_plugin_class_init (CsdDummyPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_dummy_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdDummyPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/sound/0000775000175000017500000000000012625665665020205 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/sound/csd-sound-manager.c0000664000175000017500000004646212625665665023674 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 #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; 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_class_init (CsdSoundManagerClass *klass); static void csd_sound_manager_init (CsdSoundManager *sound_manager); 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, 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, 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, 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"); 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); } 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 GObject * csd_sound_manager_constructor ( GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdSoundManager *m; m = CSD_SOUND_MANAGER (G_OBJECT_CLASS (csd_sound_manager_parent_class)->constructor ( type, n_construct_properties, construct_properties)); return G_OBJECT (m); } 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->constructor = csd_sound_manager_constructor; 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); 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-2.8.3/plugins/sound/csd-sound-manager.h0000664000175000017500000000412312625665665023665 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-2.8.3/plugins/sound/csd-sound-plugin.c0000664000175000017500000000576412625665665023560 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, 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 "cinnamon-settings-plugin.h" #include "csd-sound-plugin.h" #include "csd-sound-manager.h" struct CsdSoundPluginPrivate { CsdSoundManager *manager; }; #define CSD_SOUND_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_SOUND_PLUGIN, CsdSoundPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdSoundPlugin, csd_sound_plugin) static void csd_sound_plugin_init (CsdSoundPlugin *plugin) { plugin->priv = CSD_SOUND_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdSoundPlugin initializing"); plugin->priv->manager = csd_sound_manager_new (); } static void csd_sound_plugin_finalize (GObject *object) { CsdSoundPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_SOUND_PLUGIN (object)); g_debug ("CsdSoundPlugin finalizing"); plugin = CSD_SOUND_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) g_object_unref (plugin->priv->manager); G_OBJECT_CLASS (csd_sound_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { GError *error = NULL; g_debug ("Activating sound plugin"); if (!csd_sound_manager_start (CSD_SOUND_PLUGIN (plugin)->priv->manager, &error)) { g_warning ("Unable to start sound manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating sound plugin"); csd_sound_manager_stop (CSD_SOUND_PLUGIN (plugin)->priv->manager); } static void csd_sound_plugin_class_init (CsdSoundPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_sound_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdSoundPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/sound/sound.cinnamon-settings-plugin.in0000664000175000017500000000024212625665665026616 0ustar fabiofabio[Cinnamon Settings Plugin] Module=sound IAge=0 _Name=Sound _Description=Sound Sample Cache plugin Authors=Lennart Poettering Copyright=Copyright © 2008 Website= cinnamon-settings-daemon-2.8.3/plugins/sound/test-sound.c0000664000175000017500000000030512625665665022454 0ustar fabiofabio#define NEW csd_sound_manager_new #define START csd_sound_manager_start #define STOP csd_sound_manager_stop #define MANAGER CsdSoundManager #include "csd-sound-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/sound/csd-sound-plugin.h0000664000175000017500000000420412625665665023551 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, 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_PLUGIN_H__ #define __CSD_SOUND_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_SOUND_PLUGIN (csd_sound_plugin_get_type ()) #define CSD_SOUND_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_SOUND_PLUGIN, CsdSoundPlugin)) #define CSD_SOUND_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CSD_TYPE_SOUND_PLUGIN, CsdSoundPluginClass)) #define CSD_IS_SOUND_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_SOUND_PLUGIN)) #define CSD_IS_SOUND_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_SOUND_PLUGIN)) #define CSD_SOUND_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_SOUND_PLUGIN, CsdSoundPluginClass)) typedef struct CsdSoundPluginPrivate CsdSoundPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdSoundPluginPrivate *priv; } CsdSoundPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdSoundPluginClass; GType csd_sound_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_SOUND_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/sound/Makefile.am0000664000175000017500000000254512625665665022247 0ustar fabiofabioplugin_name = sound libexec_PROGRAMS = csd-test-sound csd_test_sound_SOURCES = \ csd-sound-manager.h \ csd-sound-manager.c \ test-sound.c csd_test_sound_CFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(SOUND_CFLAGS) \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_test_sound_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SOUND_LIBS) \ $(SETTINGS_PLUGIN_LIBS) plugin_LTLIBRARIES = \ libsound.la libsound_la_SOURCES = \ csd-sound-plugin.h \ csd-sound-plugin.c \ csd-sound-manager.h \ csd-sound-manager.c libsound_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libsound_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(SOUND_CFLAGS) \ $(AM_CFLAGS) libsound_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) libsound_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(SOUND_LIBS) plugin_in_files = \ sound.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) CLEANFILES = \ $(plugin_DATA) DISTCLEANFILES = \ $(plugin_DATA) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/clipboard/0000775000175000017500000000000012625665665021014 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/clipboard/csd-clipboard-plugin.c0000664000175000017500000000627012625665665025167 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 "cinnamon-settings-plugin.h" #include "csd-clipboard-plugin.h" #include "csd-clipboard-manager.h" struct CsdClipboardPluginPrivate { CsdClipboardManager *manager; }; #define CSD_CLIPBOARD_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_CLIPBOARD_PLUGIN, CsdClipboardPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdClipboardPlugin, csd_clipboard_plugin) static void csd_clipboard_plugin_init (CsdClipboardPlugin *plugin) { plugin->priv = CSD_CLIPBOARD_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdClipboardPlugin initializing"); plugin->priv->manager = csd_clipboard_manager_new (); } static void csd_clipboard_plugin_finalize (GObject *object) { CsdClipboardPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_CLIPBOARD_PLUGIN (object)); g_debug ("CsdClipboardPlugin finalizing"); plugin = CSD_CLIPBOARD_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_clipboard_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating clipboard plugin"); error = NULL; res = csd_clipboard_manager_start (CSD_CLIPBOARD_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start clipboard manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating clipboard plugin"); csd_clipboard_manager_stop (CSD_CLIPBOARD_PLUGIN (plugin)->priv->manager); } static void csd_clipboard_plugin_class_init (CsdClipboardPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_clipboard_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdClipboardPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/clipboard/xutils.h0000664000175000017500000000334012625665665022515 0ustar fabiofabio/* * Copyright © 2004 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: Matthias Clasen, Red Hat, Inc. */ #ifndef X_UTILS_H #define X_UTILS_H #include extern Atom XA_ATOM_PAIR; extern Atom XA_CLIPBOARD_MANAGER; extern Atom XA_CLIPBOARD; extern Atom XA_DELETE; extern Atom XA_INCR; extern Atom XA_INSERT_PROPERTY; extern Atom XA_INSERT_SELECTION; extern Atom XA_MANAGER; extern Atom XA_MULTIPLE; extern Atom XA_NULL; extern Atom XA_SAVE_TARGETS; extern Atom XA_TARGETS; extern Atom XA_TIMESTAMP; extern unsigned long SELECTION_MAX_SIZE; void init_atoms (Display *display); Time get_server_time (Display *display, Window window); #endif /* X_UTILS_H */ cinnamon-settings-daemon-2.8.3/plugins/clipboard/csd-clipboard-manager.h0000664000175000017500000000456312625665665025313 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_CLIPBOARD_MANAGER_H #define __CSD_CLIPBOARD_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_CLIPBOARD_MANAGER (csd_clipboard_manager_get_type ()) #define CSD_CLIPBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_CLIPBOARD_MANAGER, CsdClipboardManager)) #define CSD_CLIPBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_CLIPBOARD_MANAGER, CsdClipboardManagerClass)) #define CSD_IS_CLIPBOARD_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_CLIPBOARD_MANAGER)) #define CSD_IS_CLIPBOARD_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_CLIPBOARD_MANAGER)) #define CSD_CLIPBOARD_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_CLIPBOARD_MANAGER, CsdClipboardManagerClass)) typedef struct CsdClipboardManagerPrivate CsdClipboardManagerPrivate; typedef struct { GObject parent; CsdClipboardManagerPrivate *priv; } CsdClipboardManager; typedef struct { GObjectClass parent_class; } CsdClipboardManagerClass; GType csd_clipboard_manager_get_type (void); CsdClipboardManager * csd_clipboard_manager_new (void); gboolean csd_clipboard_manager_start (CsdClipboardManager *manager, GError **error); void csd_clipboard_manager_stop (CsdClipboardManager *manager); G_END_DECLS #endif /* __CSD_CLIPBOARD_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/clipboard/clipboard.cinnamon-settings-plugin.in0000664000175000017500000000025612625665665030241 0ustar fabiofabio[Cinnamon Settings Plugin] Module=clipboard IAge=0 _Name=Clipboard _Description=Clipboard plugin Authors=Matthias Clasen Copyright=Copyright © 2007 Matthias Clasen Website= cinnamon-settings-daemon-2.8.3/plugins/clipboard/list.h0000664000175000017500000000356612625665665022152 0ustar fabiofabio/* * Copyright © 2004 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: Matthias Clasen, Red Hat, Inc. */ #ifndef LIST_H #define LIST_H typedef struct _List List; typedef void (*Callback) (void *data, void *user_data); struct _List { void *data; List *next; }; typedef int (*ListFindFunc) (void *data, void *user_data); void list_foreach (List *list, Callback func, void *user_data); List *list_prepend (List *list, void *data); void list_free (List *list); List *list_find (List *list, ListFindFunc func, void *user_data); List *list_remove (List *list, void *data); int list_length (List *list); List *list_copy (List *list); #endif /* LIST_H */ cinnamon-settings-daemon-2.8.3/plugins/clipboard/list.c0000664000175000017500000000550412625665665022137 0ustar fabiofabio/* * Copyright © 2004 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: Matthias Clasen, Red Hat, Inc. */ #include #include void list_foreach (List *list, Callback func, void *user_data) { while (list) { func (list->data, user_data); list = list->next; } } List * list_prepend (List *list, void *data) { List *link; link = (List *) malloc (sizeof (List)); link->next = list; link->data = data; return link; } void list_free (List *list) { while (list) { List *next = list->next; free (list); list = next; } } List * list_find (List *list, ListFindFunc func, void *user_data) { List *tmp; for (tmp = list; tmp; tmp = tmp->next) { if ((*func) (tmp->data, user_data)) break; } return tmp; } List * list_remove (List *list, void *data) { List *tmp, *prev; prev = NULL; for (tmp = list; tmp; tmp = tmp->next) { if (tmp->data == data) { if (prev) prev->next = tmp->next; else list = tmp->next; free (tmp); break; } prev = tmp; } return list; } int list_length (List *list) { List *tmp; int length; length = 0; for (tmp = list; tmp; tmp = tmp->next) length++; return length; } List * list_copy (List *list) { List *new_list = NULL; if (list) { List *last; new_list = (List *) malloc (sizeof (List)); new_list->data = list->data; new_list->next = NULL; last = new_list; list = list->next; while (list) { last->next = (List *) malloc (sizeof (List)); last = last->next; last->data = list->data; list = list->next; } last->next = NULL; } return new_list; } cinnamon-settings-daemon-2.8.3/plugins/clipboard/xutils.c0000664000175000017500000000675612625665665022526 0ustar fabiofabio/* * Copyright © 2004 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: Matthias Clasen, Red Hat, Inc. */ #include #include "xutils.h" Atom XA_ATOM_PAIR; Atom XA_CLIPBOARD_MANAGER; Atom XA_CLIPBOARD; Atom XA_DELETE; Atom XA_INCR; Atom XA_INSERT_PROPERTY; Atom XA_INSERT_SELECTION; Atom XA_MANAGER; Atom XA_MULTIPLE; Atom XA_NULL; Atom XA_SAVE_TARGETS; Atom XA_TARGETS; Atom XA_TIMESTAMP; unsigned long SELECTION_MAX_SIZE = 0; void init_atoms (Display *display) { unsigned long max_request_size; if (SELECTION_MAX_SIZE > 0) return; XA_ATOM_PAIR = XInternAtom (display, "ATOM_PAIR", False); XA_CLIPBOARD_MANAGER = XInternAtom (display, "CLIPBOARD_MANAGER", False); XA_CLIPBOARD = XInternAtom (display, "CLIPBOARD", False); XA_DELETE = XInternAtom (display, "DELETE", False); XA_INCR = XInternAtom (display, "INCR", False); XA_INSERT_PROPERTY = XInternAtom (display, "INSERT_PROPERTY", False); XA_INSERT_SELECTION = XInternAtom (display, "INSERT_SELECTION", False); XA_MANAGER = XInternAtom (display, "MANAGER", False); XA_MULTIPLE = XInternAtom (display, "MULTIPLE", False); XA_NULL = XInternAtom (display, "NULL", False); XA_SAVE_TARGETS = XInternAtom (display, "SAVE_TARGETS", False); XA_TARGETS = XInternAtom (display, "TARGETS", False); XA_TIMESTAMP = XInternAtom (display, "TIMESTAMP", False); max_request_size = XExtendedMaxRequestSize (display); if (max_request_size == 0) max_request_size = XMaxRequestSize (display); SELECTION_MAX_SIZE = max_request_size - 100; if (SELECTION_MAX_SIZE > 262144) SELECTION_MAX_SIZE = 262144; } 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; } 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; } cinnamon-settings-daemon-2.8.3/plugins/clipboard/csd-clipboard-plugin.h0000664000175000017500000000435312625665665025174 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. * */ #ifndef __CSD_CLIPBOARD_PLUGIN_H__ #define __CSD_CLIPBOARD_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_CLIPBOARD_PLUGIN (csd_clipboard_plugin_get_type ()) #define CSD_CLIPBOARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_CLIPBOARD_PLUGIN, CsdClipboardPlugin)) #define CSD_CLIPBOARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_CLIPBOARD_PLUGIN, CsdClipboardPluginClass)) #define CSD_IS_CLIPBOARD_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_CLIPBOARD_PLUGIN)) #define CSD_IS_CLIPBOARD_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_CLIPBOARD_PLUGIN)) #define CSD_CLIPBOARD_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_CLIPBOARD_PLUGIN, CsdClipboardPluginClass)) typedef struct CsdClipboardPluginPrivate CsdClipboardPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdClipboardPluginPrivate *priv; } CsdClipboardPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdClipboardPluginClass; GType csd_clipboard_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_CLIPBOARD_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/clipboard/csd-clipboard-manager.c0000664000175000017500000011655012625665665025306 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Matthias Clasen * Copyright (C) 2007 Anders Carlsson * 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 #include "xutils.h" #include "list.h" #include "cinnamon-settings-profile.h" #include "csd-clipboard-manager.h" #define CSD_CLIPBOARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_CLIPBOARD_MANAGER, CsdClipboardManagerPrivate)) struct CsdClipboardManagerPrivate { guint start_idle_id; Display *display; Window window; Time timestamp; List *contents; List *conversions; Window requestor; Atom property; Time time; }; typedef struct { unsigned char *data; int length; Atom target; Atom type; int format; int refcount; } TargetData; typedef struct { Atom target; TargetData *data; Atom property; Window requestor; int offset; } IncrConversion; static void csd_clipboard_manager_class_init (CsdClipboardManagerClass *klass); static void csd_clipboard_manager_init (CsdClipboardManager *clipboard_manager); static void csd_clipboard_manager_finalize (GObject *object); static void clipboard_manager_watch_cb (CsdClipboardManager *manager, Window window, Bool is_start, long mask, void *cb_data); G_DEFINE_TYPE (CsdClipboardManager, csd_clipboard_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; /* We need to use reference counting for the target data, since we may * need to keep the data around after loosing the CLIPBOARD ownership * to complete incremental transfers. */ static TargetData * target_data_ref (TargetData *data) { data->refcount++; return data; } static void target_data_unref (TargetData *data) { data->refcount--; if (data->refcount == 0) { free (data->data); free (data); } } static void conversion_free (IncrConversion *rdata) { if (rdata->data) { target_data_unref (rdata->data); } free (rdata); } static void send_selection_notify (CsdClipboardManager *manager, Bool success) { XSelectionEvent notify; notify.type = SelectionNotify; notify.serial = 0; notify.send_event = True; notify.display = manager->priv->display; notify.requestor = manager->priv->requestor; notify.selection = XA_CLIPBOARD_MANAGER; notify.target = XA_SAVE_TARGETS; notify.property = success ? manager->priv->property : None; notify.time = manager->priv->time; gdk_error_trap_push (); XSendEvent (manager->priv->display, manager->priv->requestor, False, NoEventMask, (XEvent *)¬ify); XSync (manager->priv->display, False); gdk_error_trap_pop_ignored (); } static void finish_selection_request (CsdClipboardManager *manager, XEvent *xev, Bool success) { XSelectionEvent notify; notify.type = SelectionNotify; notify.serial = 0; notify.send_event = True; notify.display = xev->xselectionrequest.display; notify.requestor = xev->xselectionrequest.requestor; notify.selection = xev->xselectionrequest.selection; notify.target = xev->xselectionrequest.target; notify.property = success ? xev->xselectionrequest.property : None; notify.time = xev->xselectionrequest.time; gdk_error_trap_push (); XSendEvent (xev->xselectionrequest.display, xev->xselectionrequest.requestor, False, NoEventMask, (XEvent *) ¬ify); XSync (manager->priv->display, False); gdk_error_trap_pop_ignored (); } static int clipboard_bytes_per_item (int format) { switch (format) { case 8: return sizeof (char); case 16: return sizeof (short); case 32: return sizeof (long); default: ; } return 0; } static void save_targets (CsdClipboardManager *manager, Atom *save_targets, int nitems) { int nout, i; Atom *multiple; TargetData *tdata; multiple = (Atom *) malloc (2 * nitems * sizeof (Atom)); nout = 0; for (i = 0; i < nitems; i++) { if (save_targets[i] != XA_TARGETS && save_targets[i] != XA_MULTIPLE && save_targets[i] != XA_DELETE && save_targets[i] != XA_INSERT_PROPERTY && save_targets[i] != XA_INSERT_SELECTION && save_targets[i] != XA_PIXMAP) { tdata = (TargetData *) malloc (sizeof (TargetData)); tdata->data = NULL; tdata->length = 0; tdata->target = save_targets[i]; tdata->type = None; tdata->format = 0; tdata->refcount = 1; manager->priv->contents = list_prepend (manager->priv->contents, tdata); multiple[nout++] = save_targets[i]; multiple[nout++] = save_targets[i]; } } XFree (save_targets); XChangeProperty (manager->priv->display, manager->priv->window, XA_MULTIPLE, XA_ATOM_PAIR, 32, PropModeReplace, (const unsigned char *) multiple, nout); free (multiple); XConvertSelection (manager->priv->display, XA_CLIPBOARD, XA_MULTIPLE, XA_MULTIPLE, manager->priv->window, manager->priv->time); } static int find_content_target (TargetData *tdata, Atom target) { return tdata->target == target; } static int find_content_type (TargetData *tdata, Atom type) { return tdata->type == type; } static int find_conversion_requestor (IncrConversion *rdata, XEvent *xev) { return (rdata->requestor == xev->xproperty.window && rdata->property == xev->xproperty.atom); } static void get_property (TargetData *tdata, CsdClipboardManager *manager) { Atom type; int format; unsigned long length; unsigned long remaining; unsigned char *data; XGetWindowProperty (manager->priv->display, manager->priv->window, tdata->target, 0, 0x1FFFFFFF, True, AnyPropertyType, &type, &format, &length, &remaining, &data); if (type == None) { manager->priv->contents = list_remove (manager->priv->contents, tdata); free (tdata); } else if (type == XA_INCR) { tdata->type = type; tdata->length = 0; XFree (data); } else { tdata->type = type; tdata->data = data; tdata->length = length * clipboard_bytes_per_item (format); tdata->format = format; } } static Bool receive_incrementally (CsdClipboardManager *manager, XEvent *xev) { List *list; TargetData *tdata; Atom type; int format; unsigned long length, nitems, remaining; unsigned char *data; if (xev->xproperty.window != manager->priv->window) return False; list = list_find (manager->priv->contents, (ListFindFunc) find_content_target, (void *) xev->xproperty.atom); if (!list) return False; tdata = (TargetData *) list->data; if (tdata->type != XA_INCR) return False; XGetWindowProperty (xev->xproperty.display, xev->xproperty.window, xev->xproperty.atom, 0, 0x1FFFFFFF, True, AnyPropertyType, &type, &format, &nitems, &remaining, &data); length = nitems * clipboard_bytes_per_item (format); if (length == 0) { tdata->type = type; tdata->format = format; if (!list_find (manager->priv->contents, (ListFindFunc) find_content_type, (void *)XA_INCR)) { /* all incremental transfers done */ send_selection_notify (manager, True); manager->priv->requestor = None; } XFree (data); } else { if (!tdata->data) { tdata->data = data; tdata->length = length; } else { tdata->data = realloc (tdata->data, tdata->length + length + 1); memcpy (tdata->data + tdata->length, data, length + 1); tdata->length += length; XFree (data); } } return True; } static Bool send_incrementally (CsdClipboardManager *manager, XEvent *xev) { List *list; IncrConversion *rdata; unsigned long length; unsigned long items; unsigned char *data; list = list_find (manager->priv->conversions, (ListFindFunc) find_conversion_requestor, xev); if (list == NULL) return False; rdata = (IncrConversion *) list->data; data = rdata->data->data + rdata->offset; length = rdata->data->length - rdata->offset; if (length > SELECTION_MAX_SIZE) length = SELECTION_MAX_SIZE; rdata->offset += length; items = length / clipboard_bytes_per_item (rdata->data->format); XChangeProperty (manager->priv->display, rdata->requestor, rdata->property, rdata->data->type, rdata->data->format, PropModeAppend, data, items); if (length == 0) { clipboard_manager_watch_cb (manager, rdata->requestor, False, PropertyChangeMask, NULL); manager->priv->conversions = list_remove (manager->priv->conversions, rdata); conversion_free (rdata); } return True; } static void convert_clipboard_manager (CsdClipboardManager *manager, XEvent *xev) { Atom type = None; int format; unsigned long nitems; unsigned long remaining; Atom *targets = NULL; if (xev->xselectionrequest.target == XA_SAVE_TARGETS) { if (manager->priv->requestor != None || manager->priv->contents != NULL) { /* We're in the middle of a conversion request, or own * the CLIPBOARD already */ finish_selection_request (manager, xev, False); } else { gdk_error_trap_push (); clipboard_manager_watch_cb (manager, xev->xselectionrequest.requestor, True, StructureNotifyMask, NULL); XSelectInput (manager->priv->display, xev->xselectionrequest.requestor, StructureNotifyMask); XSync (manager->priv->display, False); if (gdk_error_trap_pop () != Success) return; gdk_error_trap_push (); if (xev->xselectionrequest.property != None) { XGetWindowProperty (manager->priv->display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, 0, 0x1FFFFFFF, False, XA_ATOM, &type, &format, &nitems, &remaining, (unsigned char **) &targets); if (gdk_error_trap_pop () != Success) { if (targets) XFree (targets); return; } } manager->priv->requestor = xev->xselectionrequest.requestor; manager->priv->property = xev->xselectionrequest.property; manager->priv->time = xev->xselectionrequest.time; if (type == None) XConvertSelection (manager->priv->display, XA_CLIPBOARD, XA_TARGETS, XA_TARGETS, manager->priv->window, manager->priv->time); else save_targets (manager, targets, nitems); } } else if (xev->xselectionrequest.target == XA_TIMESTAMP) { XChangeProperty (manager->priv->display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, XA_INTEGER, 32, PropModeReplace, (unsigned char *) &manager->priv->timestamp, 1); finish_selection_request (manager, xev, True); } else if (xev->xselectionrequest.target == XA_TARGETS) { int n_targets = 0; Atom targets[3]; targets[n_targets++] = XA_TARGETS; targets[n_targets++] = XA_TIMESTAMP; targets[n_targets++] = XA_SAVE_TARGETS; XChangeProperty (manager->priv->display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, XA_ATOM, 32, PropModeReplace, (unsigned char *) targets, n_targets); finish_selection_request (manager, xev, True); } else finish_selection_request (manager, xev, False); } static void convert_clipboard_target (IncrConversion *rdata, CsdClipboardManager *manager) { TargetData *tdata; Atom *targets; int n_targets; List *list; unsigned long items; XWindowAttributes atts; if (rdata->target == XA_TARGETS) { n_targets = list_length (manager->priv->contents) + 2; targets = (Atom *) malloc (n_targets * sizeof (Atom)); n_targets = 0; targets[n_targets++] = XA_TARGETS; targets[n_targets++] = XA_MULTIPLE; for (list = manager->priv->contents; list; list = list->next) { tdata = (TargetData *) list->data; targets[n_targets++] = tdata->target; } XChangeProperty (manager->priv->display, rdata->requestor, rdata->property, XA_ATOM, 32, PropModeReplace, (unsigned char *) targets, n_targets); free (targets); } else { /* Convert from stored CLIPBOARD data */ list = list_find (manager->priv->contents, (ListFindFunc) find_content_target, (void *) rdata->target); /* We got a target that we don't support */ if (!list) return; tdata = (TargetData *)list->data; if (tdata->type == XA_INCR) { /* we haven't completely received this target yet */ rdata->property = None; return; } rdata->data = target_data_ref (tdata); items = tdata->length / clipboard_bytes_per_item (tdata->format); if (tdata->length <= SELECTION_MAX_SIZE) XChangeProperty (manager->priv->display, rdata->requestor, rdata->property, tdata->type, tdata->format, PropModeReplace, tdata->data, items); else { /* start incremental transfer */ rdata->offset = 0; gdk_error_trap_push (); XGetWindowAttributes (manager->priv->display, rdata->requestor, &atts); clipboard_manager_watch_cb (manager, rdata->requestor, True, PropertyChangeMask, NULL); XSelectInput (manager->priv->display, rdata->requestor, atts.your_event_mask | PropertyChangeMask); XChangeProperty (manager->priv->display, rdata->requestor, rdata->property, XA_INCR, 32, PropModeReplace, (unsigned char *) &items, 1); XSync (manager->priv->display, False); gdk_error_trap_pop_ignored (); } } } static void collect_incremental (IncrConversion *rdata, CsdClipboardManager *manager) { if (rdata->offset >= 0) manager->priv->conversions = list_prepend (manager->priv->conversions, rdata); else { if (rdata->data) { target_data_unref (rdata->data); rdata->data = NULL; } free (rdata); } } static void convert_clipboard (CsdClipboardManager *manager, XEvent *xev) { List *list; List *conversions; IncrConversion *rdata; Atom type; int i; int format; unsigned long nitems; unsigned long remaining; Atom *multiple; conversions = NULL; type = None; if (xev->xselectionrequest.target == XA_MULTIPLE) { XGetWindowProperty (xev->xselectionrequest.display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, 0, 0x1FFFFFFF, False, XA_ATOM_PAIR, &type, &format, &nitems, &remaining, (unsigned char **) &multiple); if (type != XA_ATOM_PAIR || nitems == 0) { if (multiple) free (multiple); return; } for (i = 0; i < nitems; i += 2) { rdata = (IncrConversion *) malloc (sizeof (IncrConversion)); rdata->requestor = xev->xselectionrequest.requestor; rdata->target = multiple[i]; rdata->property = multiple[i+1]; rdata->data = NULL; rdata->offset = -1; conversions = list_prepend (conversions, rdata); } } else { multiple = NULL; rdata = (IncrConversion *) malloc (sizeof (IncrConversion)); rdata->requestor = xev->xselectionrequest.requestor; rdata->target = xev->xselectionrequest.target; rdata->property = xev->xselectionrequest.property; rdata->data = NULL; rdata->offset = -1; conversions = list_prepend (conversions, rdata); } list_foreach (conversions, (Callback) convert_clipboard_target, manager); if (conversions->next == NULL && ((IncrConversion *) conversions->data)->property == None) { finish_selection_request (manager, xev, False); } else { if (multiple) { i = 0; for (list = conversions; list; list = list->next) { rdata = (IncrConversion *)list->data; multiple[i++] = rdata->target; multiple[i++] = rdata->property; } XChangeProperty (xev->xselectionrequest.display, xev->xselectionrequest.requestor, xev->xselectionrequest.property, XA_ATOM_PAIR, 32, PropModeReplace, (unsigned char *) multiple, nitems); } finish_selection_request (manager, xev, True); } list_foreach (conversions, (Callback) collect_incremental, manager); list_free (conversions); if (multiple) free (multiple); } static Bool clipboard_manager_process_event (CsdClipboardManager *manager, XEvent *xev) { Atom type; int format; unsigned long nitems; unsigned long remaining; Atom *targets; targets = NULL; switch (xev->xany.type) { case DestroyNotify: if (xev->xdestroywindow.window == manager->priv->requestor) { list_foreach (manager->priv->contents, (Callback)target_data_unref, NULL); list_free (manager->priv->contents); manager->priv->contents = NULL; clipboard_manager_watch_cb (manager, manager->priv->requestor, False, 0, NULL); manager->priv->requestor = None; } break; case PropertyNotify: if (xev->xproperty.state == PropertyNewValue) { return receive_incrementally (manager, xev); } else { return send_incrementally (manager, xev); } case SelectionClear: if (xev->xany.window != manager->priv->window) return False; if (xev->xselectionclear.selection == XA_CLIPBOARD_MANAGER) { /* We lost the manager selection */ if (manager->priv->contents) { list_foreach (manager->priv->contents, (Callback)target_data_unref, NULL); list_free (manager->priv->contents); manager->priv->contents = NULL; XSetSelectionOwner (manager->priv->display, XA_CLIPBOARD, None, manager->priv->time); } return True; } if (xev->xselectionclear.selection == XA_CLIPBOARD) { /* We lost the clipboard selection */ list_foreach (manager->priv->contents, (Callback)target_data_unref, NULL); list_free (manager->priv->contents); manager->priv->contents = NULL; clipboard_manager_watch_cb (manager, manager->priv->requestor, False, 0, NULL); manager->priv->requestor = None; return True; } break; case SelectionNotify: if (xev->xany.window != manager->priv->window) return False; if (xev->xselection.selection == XA_CLIPBOARD) { /* a CLIPBOARD conversion is done */ if (xev->xselection.property == XA_TARGETS) { XGetWindowProperty (xev->xselection.display, xev->xselection.requestor, xev->xselection.property, 0, 0x1FFFFFFF, True, XA_ATOM, &type, &format, &nitems, &remaining, (unsigned char **) &targets); save_targets (manager, targets, nitems); } else if (xev->xselection.property == XA_MULTIPLE) { List *tmp; tmp = list_copy (manager->priv->contents); list_foreach (tmp, (Callback) get_property, manager); list_free (tmp); manager->priv->time = xev->xselection.time; XSetSelectionOwner (manager->priv->display, XA_CLIPBOARD, manager->priv->window, manager->priv->time); if (manager->priv->property != None) XChangeProperty (manager->priv->display, manager->priv->requestor, manager->priv->property, XA_ATOM, 32, PropModeReplace, (unsigned char *)&XA_NULL, 1); if (!list_find (manager->priv->contents, (ListFindFunc)find_content_type, (void *)XA_INCR)) { /* all transfers done */ send_selection_notify (manager, True); clipboard_manager_watch_cb (manager, manager->priv->requestor, False, 0, NULL); manager->priv->requestor = None; } } else if (xev->xselection.property == None) { send_selection_notify (manager, False); clipboard_manager_watch_cb (manager, manager->priv->requestor, False, 0, NULL); manager->priv->requestor = None; } return True; } break; case SelectionRequest: if (xev->xany.window != manager->priv->window) { return False; } if (xev->xselectionrequest.selection == XA_CLIPBOARD_MANAGER) { convert_clipboard_manager (manager, xev); return True; } else if (xev->xselectionrequest.selection == XA_CLIPBOARD) { convert_clipboard (manager, xev); return True; } break; default: ; } return False; } static GdkFilterReturn clipboard_manager_event_filter (GdkXEvent *xevent, GdkEvent *event, CsdClipboardManager *manager) { if (clipboard_manager_process_event (manager, (XEvent *)xevent)) { return GDK_FILTER_REMOVE; } else { return GDK_FILTER_CONTINUE; } } static void clipboard_manager_watch_cb (CsdClipboardManager *manager, Window window, Bool is_start, long mask, void *cb_data) { GdkWindow *gdkwin; GdkDisplay *display; display = gdk_display_get_default (); gdkwin = gdk_x11_window_lookup_for_display (display, window); if (is_start) { if (gdkwin == NULL) { gdkwin = gdk_x11_window_foreign_new_for_display (display, window); } else { g_object_ref (gdkwin); } gdk_window_add_filter (gdkwin, (GdkFilterFunc)clipboard_manager_event_filter, manager); } else { if (gdkwin == NULL) { return; } gdk_window_remove_filter (gdkwin, (GdkFilterFunc)clipboard_manager_event_filter, manager); g_object_unref (gdkwin); } } static gboolean start_clipboard_idle_cb (CsdClipboardManager *manager) { XClientMessageEvent xev; cinnamon_settings_profile_start (NULL); init_atoms (manager->priv->display); /* check if there is a clipboard manager running */ if (XGetSelectionOwner (manager->priv->display, XA_CLIPBOARD_MANAGER)) { g_warning ("Clipboard manager is already running."); return FALSE; } manager->priv->contents = NULL; manager->priv->conversions = NULL; manager->priv->requestor = None; manager->priv->window = XCreateSimpleWindow (manager->priv->display, DefaultRootWindow (manager->priv->display), 0, 0, 10, 10, 0, WhitePixel (manager->priv->display, DefaultScreen (manager->priv->display)), WhitePixel (manager->priv->display, DefaultScreen (manager->priv->display))); clipboard_manager_watch_cb (manager, manager->priv->window, True, PropertyChangeMask, NULL); XSelectInput (manager->priv->display, manager->priv->window, PropertyChangeMask); manager->priv->timestamp = get_server_time (manager->priv->display, manager->priv->window); XSetSelectionOwner (manager->priv->display, XA_CLIPBOARD_MANAGER, manager->priv->window, manager->priv->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 (manager->priv->display, XA_CLIPBOARD_MANAGER) == manager->priv->window) { xev.type = ClientMessage; xev.window = DefaultRootWindow (manager->priv->display); xev.message_type = XA_MANAGER; xev.format = 32; xev.data.l[0] = manager->priv->timestamp; xev.data.l[1] = XA_CLIPBOARD_MANAGER; xev.data.l[2] = manager->priv->window; xev.data.l[3] = 0; /* manager specific data */ xev.data.l[4] = 0; /* manager specific data */ XSendEvent (manager->priv->display, DefaultRootWindow (manager->priv->display), False, StructureNotifyMask, (XEvent *)&xev); } else { clipboard_manager_watch_cb (manager, manager->priv->window, False, 0, NULL); /* FIXME: manager->priv->terminate (manager->priv->cb_data); */ } cinnamon_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } gboolean csd_clipboard_manager_start (CsdClipboardManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_clipboard_idle_cb, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_clipboard_manager_stop (CsdClipboardManager *manager) { g_debug ("Stopping clipboard manager"); if (manager->priv->window != None) { clipboard_manager_watch_cb (manager, manager->priv->window, FALSE, 0, NULL); XDestroyWindow (manager->priv->display, manager->priv->window); manager->priv->window = None; } if (manager->priv->conversions != NULL) { list_foreach (manager->priv->conversions, (Callback) conversion_free, NULL); list_free (manager->priv->conversions); manager->priv->conversions = NULL; } if (manager->priv->contents != NULL) { list_foreach (manager->priv->contents, (Callback) target_data_unref, NULL); list_free (manager->priv->contents); manager->priv->contents = NULL; } } static GObject * csd_clipboard_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdClipboardManager *clipboard_manager; clipboard_manager = CSD_CLIPBOARD_MANAGER (G_OBJECT_CLASS (csd_clipboard_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (clipboard_manager); } static void csd_clipboard_manager_class_init (CsdClipboardManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_clipboard_manager_constructor; object_class->finalize = csd_clipboard_manager_finalize; g_type_class_add_private (klass, sizeof (CsdClipboardManagerPrivate)); } static void csd_clipboard_manager_init (CsdClipboardManager *manager) { manager->priv = CSD_CLIPBOARD_MANAGER_GET_PRIVATE (manager); manager->priv->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); } static void csd_clipboard_manager_finalize (GObject *object) { CsdClipboardManager *clipboard_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_CLIPBOARD_MANAGER (object)); clipboard_manager = CSD_CLIPBOARD_MANAGER (object); g_return_if_fail (clipboard_manager->priv != NULL); if (clipboard_manager->priv->start_idle_id !=0) { g_source_remove (clipboard_manager->priv->start_idle_id); clipboard_manager->priv->start_idle_id = 0; } G_OBJECT_CLASS (csd_clipboard_manager_parent_class)->finalize (object); } CsdClipboardManager * csd_clipboard_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_CLIPBOARD_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_CLIPBOARD_MANAGER (manager_object); } cinnamon-settings-daemon-2.8.3/plugins/clipboard/Makefile.am0000664000175000017500000000173212625665665023053 0ustar fabiofabioNULL = plugin_name = clipboard plugin_LTLIBRARIES = \ libclipboard.la \ $(NULL) libclipboard_la_SOURCES = \ csd-clipboard-plugin.h \ csd-clipboard-plugin.c \ csd-clipboard-manager.h \ csd-clipboard-manager.c \ xutils.h \ xutils.c \ list.h \ list.c \ $(NULL) libclipboard_la_CPPFLAGS = \ $(PLUGIN_CFLAGS) \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libclipboard_la_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) libclipboard_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) \ $(NULL) libclipboard_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(NULL) plugin_in_files = \ clipboard.cinnamon-settings-plugin.in \ $(NULL) plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) \ $(NULL) CLEANFILES = \ $(plugin_DATA) \ $(NULL) DISTCLEANFILES = \ $(plugin_DATA) \ $(NULL) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/a11y-settings/0000775000175000017500000000000012625665665021466 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/a11y-settings/a11y-settings.cinnamon-settings-plugin.in0000664000175000017500000000033412625665665031362 0ustar fabiofabio[Cinnamon Settings Plugin] Module=a11y-settings IAge=0 _Name=Accessibility settings _Description=Accessibility settings plugin Authors=Bastien Nocera Copyright=Copyright © 2011 Red Hat Inc. Website= cinnamon-settings-daemon-2.8.3/plugins/a11y-settings/test-a11y-settings.c0000664000175000017500000000035412625665665025222 0ustar fabiofabio#define NEW csd_a11y_settings_manager_new #define START csd_a11y_settings_manager_start #define STOP csd_a11y_settings_manager_stop #define MANAGER CsdA11ySettingsManager #include "csd-a11y-settings-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/a11y-settings/csd-a11y-settings-plugin.h0000664000175000017500000000446412625665665026323 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * 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, 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_SETTINGS_PLUGIN_H__ #define __CSD_A11Y_SETTINGS_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_A11Y_SETTINGS_PLUGIN (csd_a11y_settings_plugin_get_type ()) #define CSD_A11Y_SETTINGS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_A11Y_SETTINGS_PLUGIN, CsdA11ySettingsPlugin)) #define CSD_A11Y_SETTINGS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_A11Y_SETTINGS_PLUGIN, CsdA11ySettingsPluginClass)) #define CSD_IS_A11Y_SETTINGS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_A11Y_SETTINGS_PLUGIN)) #define CSD_IS_A11Y_SETTINGS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_A11Y_SETTINGS_PLUGIN)) #define CSD_A11Y_SETTINGS_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_A11Y_SETTINGS_PLUGIN, CsdA11ySettingsPluginClass)) typedef struct CsdA11ySettingsPluginPrivate CsdA11ySettingsPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdA11ySettingsPluginPrivate *priv; } CsdA11ySettingsPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdA11ySettingsPluginClass; GType csd_a11y_settings_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_A11Y_SETTINGS_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/a11y-settings/csd-a11y-settings-plugin.c0000664000175000017500000000645412625665665026317 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 "cinnamon-settings-plugin.h" #include "csd-a11y-settings-plugin.h" #include "csd-a11y-settings-manager.h" struct CsdA11ySettingsPluginPrivate { CsdA11ySettingsManager *manager; }; #define CSD_A11Y_SETTINGS_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_A11Y_SETTINGS_PLUGIN, CsdA11ySettingsPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdA11ySettingsPlugin, csd_a11y_settings_plugin) static void csd_a11y_settings_plugin_init (CsdA11ySettingsPlugin *plugin) { plugin->priv = CSD_A11Y_SETTINGS_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdA11ySettingsPlugin initializing"); plugin->priv->manager = csd_a11y_settings_manager_new (); } static void csd_a11y_settings_plugin_finalize (GObject *object) { CsdA11ySettingsPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_A11Y_SETTINGS_PLUGIN (object)); g_debug ("CsdA11ySettingsPlugin finalizing"); plugin = CSD_A11Y_SETTINGS_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_a11y_settings_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating a11y-settings plugin"); error = NULL; res = csd_a11y_settings_manager_start (CSD_A11Y_SETTINGS_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start a11y-settings manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating a11y-settings plugin"); csd_a11y_settings_manager_stop (CSD_A11Y_SETTINGS_PLUGIN (plugin)->priv->manager); } static void csd_a11y_settings_plugin_class_init (CsdA11ySettingsPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_a11y_settings_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdA11ySettingsPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/a11y-settings/Makefile.am0000664000175000017500000000267312625665665023532 0ustar fabiofabioplugin_name = a11y-settings libexec_PROGRAMS = csd-test-a11y-settings csd_test_a11y_settings_SOURCES = \ csd-a11y-settings-manager.h \ csd-a11y-settings-manager.c \ test-a11y-settings.c csd_test_a11y_settings_CFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_test_a11y_settings_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_PLUGIN_LIBS) plugin_LTLIBRARIES = \ liba11y-settings.la liba11y_settings_la_SOURCES = \ csd-a11y-settings-manager.c \ csd-a11y-settings-manager.h \ csd-a11y-settings-plugin.c \ csd-a11y-settings-plugin.h liba11y_settings_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) liba11y_settings_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) liba11y_settings_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) liba11y_settings_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) plugin_in_files = \ a11y-settings.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) CLEANFILES = \ $(plugin_DATA) DISTCLEANFILES = \ $(plugin_DATA) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/a11y-settings/csd-a11y-settings-manager.c0000664000175000017500000001553712625665665026435 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 #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-a11y-settings-manager.h" #define CSD_A11Y_SETTINGS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_A11Y_SETTINGS_MANAGER, CsdA11ySettingsManagerPrivate)) struct CsdA11ySettingsManagerPrivate { GSettings *interface_settings; GSettings *a11y_apps_settings; }; enum { PROP_0, }; static void csd_a11y_settings_manager_class_init (CsdA11ySettingsManagerClass *klass); static void csd_a11y_settings_manager_init (CsdA11ySettingsManager *a11y_settings_manager); static void csd_a11y_settings_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdA11ySettingsManager, csd_a11y_settings_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static void apps_settings_changed (GSettings *settings, const char *key, CsdA11ySettingsManager *manager) { gboolean screen_reader, keyboard; if (g_str_equal (key, "screen-reader-enabled") == FALSE && g_str_equal (key, "screen-keyboard-enabled") == FALSE) return; g_debug ("screen reader or OSK enablement changed"); screen_reader = g_settings_get_boolean (manager->priv->a11y_apps_settings, "screen-reader-enabled"); keyboard = g_settings_get_boolean (manager->priv->a11y_apps_settings, "screen-keyboard-enabled"); if (screen_reader || keyboard) { g_debug ("Enabling toolkit-accessibility, screen reader or OSK enabled"); g_settings_set_boolean (manager->priv->interface_settings, "toolkit-accessibility", TRUE); } else if (screen_reader == FALSE && keyboard == FALSE) { g_debug ("Disabling toolkit-accessibility, screen reader and OSK disabled"); g_settings_set_boolean (manager->priv->interface_settings, "toolkit-accessibility", FALSE); } } gboolean csd_a11y_settings_manager_start (CsdA11ySettingsManager *manager, GError **error) { g_debug ("Starting a11y_settings manager"); cinnamon_settings_profile_start (NULL); manager->priv->interface_settings = g_settings_new ("org.cinnamon.desktop.interface"); manager->priv->a11y_apps_settings = g_settings_new ("org.cinnamon.desktop.a11y.applications"); g_signal_connect (G_OBJECT (manager->priv->a11y_apps_settings), "changed", G_CALLBACK (apps_settings_changed), manager); /* If any of the screen reader or on-screen keyboard are enabled, * make sure a11y is enabled for the toolkits. * We don't do the same thing for the reverse so it's possible to * enable AT-SPI for the toolkits without using an a11y app */ if (g_settings_get_boolean (manager->priv->a11y_apps_settings, "screen-keyboard-enabled") || g_settings_get_boolean (manager->priv->a11y_apps_settings, "screen-reader-enabled")) g_settings_set_boolean (manager->priv->interface_settings, "toolkit-accessibility", TRUE); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_a11y_settings_manager_stop (CsdA11ySettingsManager *manager) { if (manager->priv->interface_settings) { g_object_unref (manager->priv->interface_settings); manager->priv->interface_settings = NULL; } if (manager->priv->a11y_apps_settings) { g_object_unref (manager->priv->a11y_apps_settings); manager->priv->a11y_apps_settings = NULL; } g_debug ("Stopping a11y_settings manager"); } static GObject * csd_a11y_settings_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdA11ySettingsManager *a11y_settings_manager; a11y_settings_manager = CSD_A11Y_SETTINGS_MANAGER (G_OBJECT_CLASS (csd_a11y_settings_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (a11y_settings_manager); } static void csd_a11y_settings_manager_dispose (GObject *object) { G_OBJECT_CLASS (csd_a11y_settings_manager_parent_class)->dispose (object); } static void csd_a11y_settings_manager_class_init (CsdA11ySettingsManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_a11y_settings_manager_constructor; object_class->dispose = csd_a11y_settings_manager_dispose; object_class->finalize = csd_a11y_settings_manager_finalize; g_type_class_add_private (klass, sizeof (CsdA11ySettingsManagerPrivate)); } static void csd_a11y_settings_manager_init (CsdA11ySettingsManager *manager) { manager->priv = CSD_A11Y_SETTINGS_MANAGER_GET_PRIVATE (manager); } static void csd_a11y_settings_manager_finalize (GObject *object) { CsdA11ySettingsManager *a11y_settings_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_A11Y_SETTINGS_MANAGER (object)); a11y_settings_manager = CSD_A11Y_SETTINGS_MANAGER (object); g_return_if_fail (a11y_settings_manager->priv != NULL); G_OBJECT_CLASS (csd_a11y_settings_manager_parent_class)->finalize (object); } CsdA11ySettingsManager * csd_a11y_settings_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_A11Y_SETTINGS_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_A11Y_SETTINGS_MANAGER (manager_object); } cinnamon-settings-daemon-2.8.3/plugins/a11y-settings/csd-a11y-settings-manager.h0000664000175000017500000000474412625665665026440 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_SETTINGS_MANAGER_H #define __CSD_A11Y_SETTINGS_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_A11Y_SETTINGS_MANAGER (csd_a11y_settings_manager_get_type ()) #define CSD_A11Y_SETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_A11Y_SETTINGS_MANAGER, CsdA11ySettingsManager)) #define CSD_A11Y_SETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_A11Y_SETTINGS_MANAGER, CsdA11ySettingsManagerClass)) #define CSD_IS_A11Y_SETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_A11Y_SETTINGS_MANAGER)) #define CSD_IS_A11Y_SETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_A11Y_SETTINGS_MANAGER)) #define CSD_A11Y_SETTINGS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_A11Y_SETTINGS_MANAGER, CsdA11ySettingsManagerClass)) typedef struct CsdA11ySettingsManagerPrivate CsdA11ySettingsManagerPrivate; typedef struct { GObject parent; CsdA11ySettingsManagerPrivate *priv; } CsdA11ySettingsManager; typedef struct { GObjectClass parent_class; } CsdA11ySettingsManagerClass; GType csd_a11y_settings_manager_get_type (void); CsdA11ySettingsManager *csd_a11y_settings_manager_new (void); gboolean csd_a11y_settings_manager_start (CsdA11ySettingsManager *manager, GError **error); void csd_a11y_settings_manager_stop (CsdA11ySettingsManager *manager); G_END_DECLS #endif /* __CSD_A11Y_SETTINGS_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/background/0000775000175000017500000000000012625665665021174 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/background/csd-background-manager.h0000664000175000017500000000462612625665665025653 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_BACKGROUND_MANAGER_H #define __CSD_BACKGROUND_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_BACKGROUND_MANAGER (csd_background_manager_get_type ()) #define CSD_BACKGROUND_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_BACKGROUND_MANAGER, CsdBackgroundManager)) #define CSD_BACKGROUND_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_BACKGROUND_MANAGER, CsdBackgroundManagerClass)) #define CSD_IS_BACKGROUND_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_BACKGROUND_MANAGER)) #define CSD_IS_BACKGROUND_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_BACKGROUND_MANAGER)) #define CSD_BACKGROUND_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_BACKGROUND_MANAGER, CsdBackgroundManagerClass)) typedef struct CsdBackgroundManagerPrivate CsdBackgroundManagerPrivate; typedef struct { GObject parent; CsdBackgroundManagerPrivate *priv; } CsdBackgroundManager; typedef struct { GObjectClass parent_class; } CsdBackgroundManagerClass; GType csd_background_manager_get_type (void); CsdBackgroundManager * csd_background_manager_new (void); gboolean csd_background_manager_start (CsdBackgroundManager *manager, GError **error); void csd_background_manager_stop (CsdBackgroundManager *manager); G_END_DECLS #endif /* __CSD_BACKGROUND_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/background/background.cinnamon-settings-plugin.in0000664000175000017500000000022112625665665030571 0ustar fabiofabio[Cinnamon Settings Plugin] Module=background IAge=0 _Name=Background _Description=Background plugin Authors= Copyright=Copyright © 2007 Website=cinnamon-settings-daemon-2.8.3/plugins/background/csd-background-plugin.h0000664000175000017500000000440312625665665025530 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. * */ #ifndef __CSD_BACKGROUND_PLUGIN_H__ #define __CSD_BACKGROUND_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_BACKGROUND_PLUGIN (csd_background_plugin_get_type ()) #define CSD_BACKGROUND_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_BACKGROUND_PLUGIN, CsdBackgroundPlugin)) #define CSD_BACKGROUND_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_BACKGROUND_PLUGIN, CsdBackgroundPluginClass)) #define CSD_IS_BACKGROUND_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_BACKGROUND_PLUGIN)) #define CSD_IS_BACKGROUND_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_BACKGROUND_PLUGIN)) #define CSD_BACKGROUND_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_BACKGROUND_PLUGIN, CsdBackgroundPluginClass)) typedef struct CsdBackgroundPluginPrivate CsdBackgroundPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdBackgroundPluginPrivate *priv; } CsdBackgroundPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdBackgroundPluginClass; GType csd_background_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_BACKGROUND_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/background/test-background.c0000664000175000017500000000033612625665665024436 0ustar fabiofabio#define NEW csd_background_manager_new #define START csd_background_manager_start #define STOP csd_background_manager_stop #define MANAGER CsdBackgroundManager #include "csd-background-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/background/csd-background-plugin.c0000664000175000017500000000632712625665665025532 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 "cinnamon-settings-plugin.h" #include "csd-background-plugin.h" #include "csd-background-manager.h" struct CsdBackgroundPluginPrivate { CsdBackgroundManager *manager; }; #define CSD_BACKGROUND_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_BACKGROUND_PLUGIN, CsdBackgroundPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdBackgroundPlugin, csd_background_plugin) static void csd_background_plugin_init (CsdBackgroundPlugin *plugin) { plugin->priv = CSD_BACKGROUND_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdBackgroundPlugin initializing"); plugin->priv->manager = csd_background_manager_new (); } static void csd_background_plugin_finalize (GObject *object) { CsdBackgroundPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_BACKGROUND_PLUGIN (object)); g_debug ("CsdBackgroundPlugin finalizing"); plugin = CSD_BACKGROUND_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_background_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating background plugin"); error = NULL; res = csd_background_manager_start (CSD_BACKGROUND_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start background manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating background plugin"); csd_background_manager_stop (CSD_BACKGROUND_PLUGIN (plugin)->priv->manager); } static void csd_background_plugin_class_init (CsdBackgroundPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_background_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdBackgroundPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/background/Makefile.am0000664000175000017500000000365012625665665023234 0ustar fabiofabioNULL = plugin_name = background libexec_PROGRAMS = csd-test-background csd_test_background_SOURCES = \ test-background.c \ csd-background-manager.h \ csd-background-manager.c \ $(NULL) csd_test_background_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) csd_test_background_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(BACKGROUND_CFLAGS) \ $(AM_CFLAGS) csd_test_background_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(SETTINGS_PLUGIN_LIBS) \ $(BACKGROUND_LIBS) \ $(NULL) plugin_LTLIBRARIES = \ libbackground.la \ $(NULL) libbackground_la_SOURCES = \ csd-background-plugin.h \ csd-background-plugin.c \ csd-background-manager.h \ csd-background-manager.c \ $(NULL) libbackground_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/background/libbackground \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libbackground_la_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(BACKGROUND_CFLAGS) \ $(AM_CFLAGS) libbackground_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) \ $(NULL) libbackground_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(BACKGROUND_LIBS) \ $(NULL) plugin_in_files = \ background.cinnamon-settings-plugin.in \ $(NULL) plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) \ $(NULL) CLEANFILES = \ $(plugin_DATA) \ $(NULL) DISTCLEANFILES = \ $(plugin_DATA) \ $(NULL) @CSD_INTLTOOL_PLUGIN_RULE@cinnamon-settings-daemon-2.8.3/plugins/background/csd-background-manager.c0000664000175000017500000003366012625665665025646 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 * Copyright 2007 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 #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include #include "cinnamon-settings-profile.h" #include "csd-background-manager.h" #define CSD_BACKGROUND_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_BACKGROUND_MANAGER, CsdBackgroundManagerPrivate)) struct CsdBackgroundManagerPrivate { GSettings *settings; GnomeBG *bg; GnomeBGCrossfade *fade; GDBusProxy *proxy; guint proxy_signal_id; }; static void csd_background_manager_class_init (CsdBackgroundManagerClass *klass); static void csd_background_manager_init (CsdBackgroundManager *background_manager); static void csd_background_manager_finalize (GObject *object); static void setup_bg (CsdBackgroundManager *manager); static void connect_screen_signals (CsdBackgroundManager *manager); G_DEFINE_TYPE (CsdBackgroundManager, csd_background_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static void on_crossfade_finished (CsdBackgroundManager *manager) { g_object_unref (manager->priv->fade); manager->priv->fade = NULL; } static void draw_background (CsdBackgroundManager *manager, gboolean use_crossfade) { GdkDisplay *display; int n_screens; int i; cinnamon_settings_profile_start (NULL); display = gdk_display_get_default (); n_screens = gdk_display_get_n_screens (display); for (i = 0; i < n_screens; ++i) { GdkScreen *screen; GdkWindow *root_window; cairo_surface_t *surface; screen = gdk_display_get_screen (display, i); root_window = gdk_screen_get_root_window (screen); surface = gnome_bg_create_surface (manager->priv->bg, root_window, gdk_screen_get_width (screen), gdk_screen_get_height (screen), TRUE); if (FALSE) { /* use_crossfade - buggy now? need to look at cinnamon-desktop */ if (manager->priv->fade != NULL) { g_object_unref (manager->priv->fade); } manager->priv->fade = gnome_bg_set_surface_as_root_with_crossfade (screen, surface); g_signal_connect_swapped (manager->priv->fade, "finished", G_CALLBACK (on_crossfade_finished), manager); } else { gnome_bg_set_surface_as_root (screen, surface); } cairo_surface_destroy (surface); } cinnamon_settings_profile_end (NULL); } static void on_bg_transitioned (GnomeBG *bg, CsdBackgroundManager *manager) { draw_background (manager, FALSE); } static gboolean settings_change_event_cb (GSettings *settings, gpointer keys, gint n_keys, CsdBackgroundManager *manager) { gnome_bg_load_from_preferences (manager->priv->bg, manager->priv->settings); gnome_bg_set_accountsservice_background(gnome_bg_get_filename(manager->priv->bg)); return FALSE; } static void on_screen_size_changed (GdkScreen *screen, CsdBackgroundManager *manager) { draw_background (manager, FALSE); } static void watch_bg_preferences (CsdBackgroundManager *manager) { g_signal_connect (manager->priv->settings, "change-event", G_CALLBACK (settings_change_event_cb), manager); } static void on_bg_changed (GnomeBG *bg, CsdBackgroundManager *manager) { draw_background (manager, TRUE); } static void setup_bg (CsdBackgroundManager *manager) { if (manager->priv->bg != NULL) return; manager->priv->bg = gnome_bg_new (); g_signal_connect (manager->priv->bg, "changed", G_CALLBACK (on_bg_changed), manager); g_signal_connect (manager->priv->bg, "transitioned", G_CALLBACK (on_bg_transitioned), manager); connect_screen_signals (manager); watch_bg_preferences (manager); gnome_bg_load_from_preferences (manager->priv->bg, manager->priv->settings); } static void setup_bg_and_draw_background (CsdBackgroundManager *manager) { setup_bg (manager); draw_background (manager, FALSE); } static void disconnect_session_manager_listener (CsdBackgroundManager *manager) { if (manager->priv->proxy && manager->priv->proxy_signal_id) { g_signal_handler_disconnect (manager->priv->proxy, manager->priv->proxy_signal_id); manager->priv->proxy_signal_id = 0; } } static void on_session_manager_signal (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { CsdBackgroundManager *manager = CSD_BACKGROUND_MANAGER (user_data); if (g_strcmp0 (signal_name, "SessionRunning") == 0) { setup_bg_and_draw_background (manager); disconnect_session_manager_listener (manager); } } static void draw_background_after_session_loads (CsdBackgroundManager *manager) { GError *error = NULL; GDBusProxyFlags flags; GVariant *var = NULL; gboolean running = FALSE; flags = G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START; manager->priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, flags, NULL, /* GDBusInterfaceInfo */ "org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", NULL, /* GCancellable */ &error); if (manager->priv->proxy == NULL) { g_warning ("Could not listen to session manager: %s", error->message); g_error_free (error); return; } var = g_dbus_proxy_call_sync (manager->priv->proxy, "IsSessionRunning", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); if (var != NULL) { g_variant_get (var, "(b)", &running); g_variant_unref (var); } if (running) { setup_bg_and_draw_background (manager); } else { manager->priv->proxy_signal_id = g_signal_connect (manager->priv->proxy, "g-signal", G_CALLBACK (on_session_manager_signal), manager); } } static void disconnect_screen_signals (CsdBackgroundManager *manager) { GdkDisplay *display; int i; int n_screens; display = gdk_display_get_default (); n_screens = gdk_display_get_n_screens (display); for (i = 0; i < n_screens; ++i) { GdkScreen *screen; screen = gdk_display_get_screen (display, i); g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (on_screen_size_changed), manager); } } static void connect_screen_signals (CsdBackgroundManager *manager) { GdkDisplay *display; int i; int n_screens; display = gdk_display_get_default (); n_screens = gdk_display_get_n_screens (display); for (i = 0; i < n_screens; ++i) { GdkScreen *screen; screen = gdk_display_get_screen (display, i); g_signal_connect (screen, "monitors-changed", G_CALLBACK (on_screen_size_changed), manager); g_signal_connect (screen, "size-changed", G_CALLBACK (on_screen_size_changed), manager); } } gboolean csd_background_manager_start (CsdBackgroundManager *manager, GError **error) { g_debug ("Starting background manager"); cinnamon_settings_profile_start (NULL); manager->priv->settings = g_settings_new ("org.cinnamon.desktop.background"); draw_background_after_session_loads (manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_background_manager_stop (CsdBackgroundManager *manager) { CsdBackgroundManagerPrivate *p = manager->priv; g_debug ("Stopping background manager"); disconnect_screen_signals (manager); if (manager->priv->proxy) { disconnect_session_manager_listener (manager); g_object_unref (manager->priv->proxy); } g_signal_handlers_disconnect_by_func (manager->priv->settings, settings_change_event_cb, manager); if (p->settings != NULL) { g_object_unref (p->settings); p->settings = NULL; } if (p->bg != NULL) { g_object_unref (p->bg); p->bg = NULL; } } static GObject * csd_background_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdBackgroundManager *background_manager; background_manager = CSD_BACKGROUND_MANAGER (G_OBJECT_CLASS (csd_background_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (background_manager); } static void csd_background_manager_class_init (CsdBackgroundManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_background_manager_constructor; object_class->finalize = csd_background_manager_finalize; g_type_class_add_private (klass, sizeof (CsdBackgroundManagerPrivate)); } static void csd_background_manager_init (CsdBackgroundManager *manager) { manager->priv = CSD_BACKGROUND_MANAGER_GET_PRIVATE (manager); } static void csd_background_manager_finalize (GObject *object) { CsdBackgroundManager *background_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_BACKGROUND_MANAGER (object)); background_manager = CSD_BACKGROUND_MANAGER (object); g_return_if_fail (background_manager->priv != NULL); G_OBJECT_CLASS (csd_background_manager_parent_class)->finalize (object); } CsdBackgroundManager * csd_background_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_BACKGROUND_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_BACKGROUND_MANAGER (manager_object); } cinnamon-settings-daemon-2.8.3/plugins/datetime/0000775000175000017500000000000012625665665020651 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/datetime/csd-datetime-mechanism-debian.h0000664000175000017500000000221712625665665026551 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-2.8.3/plugins/datetime/csd-datetime-mechanism.h0000664000175000017500000001321312625665665025327 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-2.8.3/plugins/datetime/csd-datetime-mechanism.xml0000664000175000017500000001236512625665665025707 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-2.8.3/plugins/datetime/system-timezone.h0000664000175000017500000000504512625665665024202 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__ */ ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootcinnamon-settings-daemon-2.8.3/plugins/datetime/org.cinnamon.settingsdaemon.datetimemechanism.policy.incinnamon-settings-daemon-2.8.3/plugins/datetime/org.cinnamon.settingsdaemon.datetimemechanism.policy0000664000175000017500000000137012625665665033166 0ustar fabiofabio Cinnamon http://cinnamon.linuxmint.com/ gnome-panel-clock <_description>Change system time and date settings <_message>To change time or date settings, you need to authenticate. no no auth_admin_keep cinnamon-settings-daemon-2.8.3/plugins/datetime/csd-datetime-mechanism-suse.h0000664000175000017500000000264712625665665026315 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-2.8.3/plugins/datetime/org.cinnamon.SettingsDaemon.DateTimeMechanism.conf0000664000175000017500000000117112625665665032353 0ustar fabiofabio cinnamon-settings-daemon-2.8.3/plugins/datetime/system-timezone.c0000664000175000017500000007141712625665665024203 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-2.8.3/plugins/datetime/csd-datetime-mechanism-fedora.c0000664000175000017500000001711312625665665026563 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-2.8.3/plugins/datetime/csd-datetime-mechanism-main.c0000664000175000017500000001112212625665665026241 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; if (! g_thread_supported ()) { g_thread_init (NULL); } dbus_g_thread_init (); g_type_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; } ././@LongLink0000644000000000000000000000015100000000000011600 Lustar rootrootcinnamon-settings-daemon-2.8.3/plugins/datetime/org.cinnamon.SettingsDaemon.DateTimeMechanism.service.incinnamon-settings-daemon-2.8.3/plugins/datetime/org.cinnamon.SettingsDaemon.DateTimeMechanism.servic0000664000175000017500000000016612625665665032724 0ustar fabiofabio[D-BUS Service] Name=org.cinnamon.SettingsDaemon.DateTimeMechanism Exec=@LIBEXECDIR@/csd-datetime-mechanism User=root cinnamon-settings-daemon-2.8.3/plugins/datetime/csd-datetime-mechanism.c0000664000175000017500000006445612625665665025341 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({%lld,%lld}): %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/fedora-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/fedora-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/fedora-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-2.8.3/plugins/datetime/csd-datetime-mechanism-suse.c0000664000175000017500000001574712625665665026315 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-2.8.3/plugins/datetime/test-system-timezone.c0000664000175000017500000000447412625665665025157 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; g_type_init (); 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-2.8.3/plugins/datetime/csd-datetime-mechanism-debian.c0000664000175000017500000001631712625665665026552 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; } } cinnamon-settings-daemon-2.8.3/plugins/datetime/csd-datetime-mechanism-fedora.h0000664000175000017500000000257212625665665026573 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-2.8.3/plugins/datetime/Makefile.am0000664000175000017500000000412512625665665022707 0ustar fabiofabioplugin_name = datetime dbus_servicesdir = $(datadir)/dbus-1/system-services dbus_confdir = $(sysconfdir)/dbus-1/system.d polkitdir = $(datadir)/polkit-1/actions dbus_services_in_files = org.cinnamon.SettingsDaemon.DateTimeMechanism.service.in polkit_in_files = org.cinnamon.settingsdaemon.datetimemechanism.policy.in csd-datetime-mechanism-glue.h: $(srcdir)/csd-datetime-mechanism.xml $(AM_V_GEN) dbus-binding-tool \ --prefix=csd_datetime_mechanism --mode=glib-server \ --output=csd-datetime-mechanism-glue.h \ $(srcdir)/csd-datetime-mechanism.xml if HAVE_POLKIT libexec_PROGRAMS = csd-datetime-mechanism noinst_PROGRAMS = test-system-timezone endif csd_datetime_mechanism_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 \ system-timezone.c \ system-timezone.h if HAVE_POLKIT BUILT_SOURCES = csd-datetime-mechanism-glue.h endif AM_CFLAGS = $(PLUGIN_CFLAGS) $(SETTINGS_PLUGIN_CFLAGS) $(POLKIT_CFLAGS) csd_datetime_mechanism_LDADD = $(POLKIT_LIBS) $(SETTINGS_PLUGIN_LIBS) test_system_timezone_SOURCES = test-system-timezone.c system-timezone.c system-timezone.h test_system_timezone_LDADD = $(POLKIT_LIBS) $(SETTINGS_PLUGIN_LIBS) if HAVE_POLKIT dbus_services_DATA = $(dbus_services_in_files:.service.in=.service) $(dbus_services_DATA): $(dbus_services_in_files) $(AM_V_GEN)sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|" $< > $@ dbus_conf_DATA = org.cinnamon.SettingsDaemon.DateTimeMechanism.conf @INTLTOOL_POLICY_RULE@ polkit_DATA = $(polkit_in_files:.policy.in=.policy) else dbus_services_DATA = dbus_conf_DATA = polkit_DATA = endif EXTRA_DIST = \ $(dbus_services_in_files) \ org.cinnamon.SettingsDaemon.DateTimeMechanism.conf \ $(polkit_in_files) \ csd-datetime-mechanism.xml CLEANFILES = \ org.cinnamon.SettingsDaemon.DateTimeMechanism.service \ org.cinnamon.settingsdaemon.datetimemechanism.policy \ $(BUILT_SOURCES) cinnamon-settings-daemon-2.8.3/plugins/xrandr/0000775000175000017500000000000012625665665020353 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/xrandr/csd-xrandr-32.png0000664000175000017500000000310212625665665023344 0ustar fabiofabio‰PNG  IHDR szzôbKGDÿÿÿ ½§“tIMEÖ  jéV†äIDATX…½–kp”ÕÇïy÷Ên’+ q"ÆTA.– PÑÑNUd´g:#ýÖÎtÊû¡ÔQÉLû¥T¦ÃL/c[ÔQTÊØ*BBj  H0”Ël"…ÉBÂfwóÞÎé‡Ýl6ÙÍÅÊøŸ9³ïyæœçù?·³dáOÏë[ùš!²7šÆë{;<ûÿØŽïë" ìÚµËkKãweñŸ~¯féj†"H·#õò[nб¥aã‡oêñ§ÚÔ~Óà(ó¹¶onÜÖØO˪G©¬9Ééïæî÷PÓðíy+Wjî3š¦y#‘Ë[Þ>°ÿ%àiWJ(¾¯t÷J*«¨dÍæíôtî 2pÆ{~î´‘\+¹25!…RP[['\B#yýCê–µ°°¬šžÞ`p¬•¨uçŒjGbY&ñx2-™J#‹@~"À™‘'1N¼Ç•ÈyîZÿžÀB’#ð׳~Ëè9ºàµË\ŒmÆQ cÜ ‘LL&±m#‚3RO#izè~˜³‘ þy`77®Gñ¯ÇÄIœbÕ½[inª¢±h/FüCCC\½v•X,–1žém;s H=0ÅsÉ Wb~ðõ M„Â÷a&Αˆþƒ¥«(-[Œ§ûŽË‘Kæòkö(¥@ILËʬh¼˜Eáäékyÿ÷HÊð¶¿~„`Ðaͦï²fùZëzš3“[sE@¡”D*(l{2wJ)’¶M×@+µÃIÆ_fEëÊ«ÛHÜèí VoxŒ…}]:9vþf`ÖäPJ¢”J¢©$–¾=É|zJƒ¾ORUûW~ 31@|ø0w¬£tQ~O'=Ã\­ÊÒ?ÒA×›kG¥#B:"ß9©—Eà+ ãòV¡¸¤™µ·á;ö7ÎE¢¿t{Ú¹R J9t½»“𷣤ƒR’¾“çiס”ƒ’’³§ -/O’œ;;L¨iŸŸ‹²¬aA«7>AÁ‰NJ]:Ó:s ” ‰í8øK¢¢>Ì‚Òj©‚¬\z•@Ù¢ŒÇ•ã×)¬,ÊxTeߤ¨º0õ-cU"Uã+Z·P\rŠB߇ |úEëŸÉ%066††äý}íH¥¡ký½zæ ®9ôÏÚ ‡þã"k/3{]HÎ~’Û`º\îù1>WN% Yµõ –ebÛ¹-4µxÔ4y¾W>ŸLÃåÒ …–Ó3°g’€ã¨¾úúey.ý?˜}6ÓuŽe“¤ñ“ß¼ôëßú|ÞÙ›öÁ7L…|æ1UìüÕÎÖO{Ouµ„[¼.— Ç:Bt]G×u„ÐÒ¿©ý±î®DÍâÊÕÏ>ûó¾¹ôÏú_`&“›C¡ÙÜÜ<Ř®ëhÚ‰l2:7F¢rdtô~`Ny#ÐÑѱÄãÓ_@ÓîšVóÀæ- Tv4MËZ „È´ÛÆâqþz`E¿m[GQãÏíØÑ><™‰ˆî}åÏ=RJu+‹ÅTÇ/_ø;P äŒÕÙ)p“j΂¡/†î¼„Ûí™é¡˜¦†hJ€1@bù@:%R:ÞW^{õ+Ÿ_ZwNʧ ܤÂä<¤æ…/7O…Lë°Hq²ŠÙ”UãÓ‰ä}þ %t¾šnIEND®B`‚cinnamon-settings-daemon-2.8.3/plugins/xrandr/csd-xrandr-24.png0000664000175000017500000000161512625665665023354 0ustar fabiofabio‰PNG  IHDRàw=øbKGDùC» pHYs × ×B(›xtIMEÖ !˜“HIDATHǽ–Mh\U€¿wï}“`BÒ,ŠDœ]¬Î®;Akˆ6¡E7œ-FŠ¥OêJQ1¡´ˆÅ.ºÌB:ÅŸ¬ÁV‘i¡ZH©´´³Èß»3oîqñî¼™$ÆŸúàpÎ{¼{¾ósïyþÇ+¸oN£èä×I’¼z0ÿ!ßÏF;åû| [·ª©sZ¦Îi±¶!q\ß–X[—ååÕ$ŠN €iáœ/¹r¡›7O=½íЯLOë–¬³ò…"_¼5Î7×ßM‹(âuHGu¥­ƒ¡üídÇ; ZF§ÇZ­L¾PdxßGˆ"~Î¥÷"âµï;ünXkSC"Â꽋ä E^Ü÷1"ç"Á!έ·q[Dœ×MaaöfyéñO,z/Npâ.…Öc»5À˜0ÐLÓ%`aö rè‰OÁI;Kç²’­,/Q­V™›ŸÛÈšÜÕÕå×:€‰«o0ÂöBFøŒ ?ÒH:Ö։㵬ôZ©­3h:¯‘'ϬËäð3§¹w÷.KKKÔmŒR íEy@+À¿ÎÀ7tÏ#»QZãœCiC˜ËAcŠ|¡H‰q>¿8Á?O—M8—p{~Žž]Cô âæëô?ô  ¼ÌʯÙ9) Mü­ãœZ^ŸA.—i2í<üvù”?Ošk“ïøh¿<î#( Mlyâë®—©¯xÖ´w‘áÑçQJÿ§ñúÝÁ¶ÝA«öª¯óC¨T®288¸#c´R©ljòh¹|ét¹|i'?£«ø¦g­Tzû—½{4ÆÐ)JiÂ0DkÍÌÌÌOÇŽ½w`ƒst®»)t÷öö†'N|0iL8Ð××·kÿþ§´R­µw u[OOÿ˜,.VïX[¯Ž½óœwÞ,`MGôÝ@ÏÑ£c GŽNúûûÍ¿©Ãðð Ø]«ÕÖÖVïDÑñ‡}Àɺm 4}œ=û¥ÙFÍ[kjÀÊÆ„>‹®z¨ñ¢}tM/ÎkëeÅ‹õÈ}ÿUù¶Ú¾èdŒ6ÌIEND®B`‚cinnamon-settings-daemon-2.8.3/plugins/xrandr/csd-xrandr-plugin.c0000664000175000017500000000613312625665665024063 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 "cinnamon-settings-plugin.h" #include "csd-xrandr-plugin.h" #include "csd-xrandr-manager.h" struct CsdXrandrPluginPrivate { CsdXrandrManager *manager; }; #define CSD_XRANDR_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_XRANDR_PLUGIN, CsdXrandrPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdXrandrPlugin, csd_xrandr_plugin) static void csd_xrandr_plugin_init (CsdXrandrPlugin *plugin) { plugin->priv = CSD_XRANDR_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdXrandrPlugin initializing"); plugin->priv->manager = csd_xrandr_manager_new (); } static void csd_xrandr_plugin_finalize (GObject *object) { CsdXrandrPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_XRANDR_PLUGIN (object)); g_debug ("CsdXrandrPlugin finalizing"); plugin = CSD_XRANDR_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_xrandr_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating xrandr plugin"); error = NULL; res = csd_xrandr_manager_start (CSD_XRANDR_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start xrandr manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating xrandr plugin"); csd_xrandr_manager_stop (CSD_XRANDR_PLUGIN (plugin)->priv->manager); } static void csd_xrandr_plugin_class_init (CsdXrandrPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_xrandr_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdXrandrPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/xrandr/csd-xrandr-manager.h0000664000175000017500000000443112625665665024203 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_XRANDR_MANAGER_H #define __CSD_XRANDR_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_XRANDR_MANAGER (csd_xrandr_manager_get_type ()) #define CSD_XRANDR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_XRANDR_MANAGER, CsdXrandrManager)) #define CSD_XRANDR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_XRANDR_MANAGER, CsdXrandrManagerClass)) #define CSD_IS_XRANDR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_XRANDR_MANAGER)) #define CSD_IS_XRANDR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_XRANDR_MANAGER)) #define CSD_XRANDR_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_XRANDR_MANAGER, CsdXrandrManagerClass)) typedef struct CsdXrandrManagerPrivate CsdXrandrManagerPrivate; typedef struct { GObject parent; CsdXrandrManagerPrivate *priv; } CsdXrandrManager; typedef struct { GObjectClass parent_class; } CsdXrandrManagerClass; GType csd_xrandr_manager_get_type (void); CsdXrandrManager * csd_xrandr_manager_new (void); gboolean csd_xrandr_manager_start (CsdXrandrManager *manager, GError **error); void csd_xrandr_manager_stop (CsdXrandrManager *manager); G_END_DECLS #endif /* __CSD_XRANDR_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/xrandr/csd-xrandr-plugin.h0000664000175000017500000000424312625665665024070 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. * */ #ifndef __CSD_XRANDR_PLUGIN_H__ #define __CSD_XRANDR_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_XRANDR_PLUGIN (csd_xrandr_plugin_get_type ()) #define CSD_XRANDR_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_XRANDR_PLUGIN, CsdXrandrPlugin)) #define CSD_XRANDR_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_XRANDR_PLUGIN, CsdXrandrPluginClass)) #define CSD_IS_XRANDR_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_XRANDR_PLUGIN)) #define CSD_IS_XRANDR_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_XRANDR_PLUGIN)) #define CSD_XRANDR_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_XRANDR_PLUGIN, CsdXrandrPluginClass)) typedef struct CsdXrandrPluginPrivate CsdXrandrPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdXrandrPluginPrivate *priv; } CsdXrandrPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdXrandrPluginClass; GType csd_xrandr_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_XRANDR_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/xrandr/csd-xrandr-22.png0000664000175000017500000000154212625665665023351 0ustar fabiofabio‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÖ "ýŠ„çïIDAT8Ë­”OhWÀóÞ›M0!b¢B‘®R µî­gÿ„¨¹"íU…î‚•¦ˆâŠ=µÚbA/zð˜CQÐ’SS¨¶Èê!ØZB,›Šî!ÆììÎ~_óvv× HȃoÞîÌo~ï›÷=HFÀ: X<{=Žã/öe¿ã—ÙâzqoÅâY;ÿsg³ÈVQÕµYP¯ÇsçÎ[ ¢ ›Ësÿf7_^üdͪ÷§§-€ˆ¢júG6—çÒWüüø›¤òª>€¶}må @U¹}g*½ÇT« XUX©Ü&›Ë3¼ã{TU¯*"É\UýO­9¯UÏ$ÆQ2SAUyõâÙ\ž;~@UUAT¤óY VoÜUfŸ¦ðƒžGS[¢ˆz°$/«U£Õ`çÂLÃ…ÙSø¡?‚hkU"ii–_.Q.—™›Ÿë;€®®.ÿŒ¤[mòáF¸Âø?qó1êqL½^#ŠjT«+ii­1«›àö1òÑ€óÑÝ—yñü9KKKÔ¢*ƬãÁM±Ncÿ¡¶¼¿ c-"‚±Ž0“ú¯dsy LpáÖHÒ oÆ"1ÿÍÏѳqˆžC<}ò˜þÍŸ³aà3ž”¤û¼04ùVhƼLŒ3™ hƒùG7@á¯{}XM$ðvߛ𦅡É7vhMz°sŽm{1ƶúþÚ÷î¾ÖuCk‚Î]Q*=dppp]޵R©”›GËë|m+7m§ …±?·oÿ`Ð9G{c Ãk-333¿Ÿ8ñí§¯A&0t÷öö†§OŸ™r.èëëÛ¸k×ÇÖ‹µÖC¬måééßâÅÅò³(ª•ÇÇ¿Þã¡u rÞ²è9~||áðáѸ¿¿ß½Ëz‡‡÷;`S¥RXYyõ¬X<µÕ‹ÆM@Ã[sõê5·†š6Ÿy¨Ë͇޺«-‡þe·õ6 âsäcÙGÄÿ„tÛ4·† IEND®B`‚cinnamon-settings-daemon-2.8.3/plugins/xrandr/xrandr.cinnamon-settings-plugin.in0000664000175000017500000000025712625665665027140 0ustar fabiofabio[Cinnamon Settings Plugin] Module=xrandr IAge=0 _Name=XRandR _Description=Set up screen size and rotation settings Authors=Various Copyright=Copyright © 2007 Novell Website= cinnamon-settings-daemon-2.8.3/plugins/xrandr/csd-xrandr.svg0000664000175000017500000004573712625665665023161 0ustar fabiofabio image/svg+xml Change Resolution Jakub Steiner display resolution video Andreas Nilsson Luca Ferretti <elle.uca@libero.it> http://www.gnome.org cinnamon-settings-daemon-2.8.3/plugins/xrandr/Makefile.am0000664000175000017500000000453712625665665022420 0ustar fabiofabioplugin_name = xrandr icondir = $(datadir)/icons/hicolor context = apps ICON_FILES = \ csd-xrandr-16.png \ csd-xrandr-22.png \ csd-xrandr-24.png \ csd-xrandr-32.png \ csd-xrandr.svg install-data-local: $(mkinstalldirs) $(DESTDIR)$(sysconfdir)/cinnamon-settings-daemon/xrandr $(mkinstalldirs) $(DESTDIR)$(icondir)/16x16/$(context) $(mkinstalldirs) $(DESTDIR)$(icondir)/22x22/$(context) $(mkinstalldirs) $(DESTDIR)$(icondir)/24x24/$(context) $(mkinstalldirs) $(DESTDIR)$(icondir)/32x32/$(context) $(mkinstalldirs) $(DESTDIR)$(icondir)/scalable/$(context) $(INSTALL_DATA) $(srcdir)/csd-xrandr-16.png $(DESTDIR)$(icondir)/16x16/$(context)/csd-xrandr.png $(INSTALL_DATA) $(srcdir)/csd-xrandr-22.png $(DESTDIR)$(icondir)/22x22/$(context)/csd-xrandr.png $(INSTALL_DATA) $(srcdir)/csd-xrandr-24.png $(DESTDIR)$(icondir)/24x24/$(context)/csd-xrandr.png $(INSTALL_DATA) $(srcdir)/csd-xrandr-32.png $(DESTDIR)$(icondir)/32x32/$(context)/csd-xrandr.png $(INSTALL_DATA) $(srcdir)/csd-xrandr.svg $(DESTDIR)$(icondir)/scalable/$(context)/csd-xrandr.svg uninstall-local: rm -f $(DESTDIR)$(icondir)/16x16/$(context)/csd-xrandr.png rm -f $(DESTDIR)$(icondir)/22x22/$(context)/csd-xrandr.png rm -f $(DESTDIR)$(icondir)/24x24/$(context)/csd-xrandr.png rm -f $(DESTDIR)$(icondir)/32x32/$(context)/csd-xrandr.png rm -f $(DESTDIR)$(icondir)/scalable/$(context)/csd-xrandr.svg plugin_LTLIBRARIES = \ libxrandr.la libxrandr_la_SOURCES = \ csd-xrandr-plugin.h \ csd-xrandr-plugin.c \ csd-xrandr-manager.h \ csd-xrandr-manager.c libxrandr_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/plugins/common/ \ -DBINDIR=\"$(bindir)\" \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libxrandr_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(XRANDR_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(WACOM_CFLAGS) \ $(AM_CFLAGS) libxrandr_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) libxrandr_la_LIBADD = \ $(top_builddir)/plugins/common/libcommon.la \ $(XRANDR_LIBS) \ $(WACOM_LIBS) \ $(SETTINGS_PLUGIN_LIBS) plugin_in_files = \ xrandr.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = $(plugin_in_files) $(ICON_FILES) CLEANFILES = $(plugin_DATA) DISTCLEANFILES = $(plugin_DATA) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/xrandr/csd-xrandr-16.png0000664000175000017500000000114512625665665023353 0ustar fabiofabio‰PNG  IHDRóÿabKGDùC» pHYs × ×B(›xtIMEÖ 6± ÷òIDAT8Ë•’ÏkA†ŸMš&¡±I!£æâQ VZü âAÔCÿ²…@`iÄS©˜@õðâMAň`Õ‹UðmÚ”=ˆ¸kµjgzØ$¨©Æ¾ðÁÌÀ÷ð¾ß7à+Q¯šº^55;”œ™¹ü°ÕjMÀ,ÙœM½ZÖw—ÿjŽF£¥çySS§ùº8 @6g¿(—¯•ßÐZñíÓm²9›W·vs®rø¯Í÷ïÔüJ)ÿU+´Ö¬¬‘ÍÙÌåËÜx~¶¯ùÁ£…ÞYX–ì8Ø­i.­õ g]ûg  }›h­1 ÁÚr«â¹ív»: ü]ý ñ¾xh…RŠÔÞ=¤÷§HH Ã:ÙœÍùɛۺ”úɇÕáÄ$áä š¯_2œ<ÅЮ“¼{ZÙ"{ô&«/®ƒ†7O*™ï;‚· À`.ÿ¬0§¤»«Bìô'cüzqœÒÒøøX³ÑX9&„@J‰iš½Êdöµççk+ŽSû-ÀôôE[)I¥R£±Ø(¦)0M ¥DË’Aàˆã”òŽS¬ô†èGÐWŠÅ‚N$’Áx<þyd$æF"7 ¹–e¹¦)]­ ³P¸ €rŸ€Ré’ ujÂÀú&íĘ­IEND®B`‚cinnamon-settings-daemon-2.8.3/plugins/xrandr/csd-xrandr-manager.c0000664000175000017500000024124412625665665024203 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2007, 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. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include #include #ifdef HAVE_WACOM #include #endif #include "csd-enums.h" #include "csd-input-helper.h" #include "cinnamon-settings-profile.h" #include "cinnamon-settings-session.h" #include "csd-xrandr-manager.h" #define CSD_XRANDR_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_XRANDR_MANAGER, CsdXrandrManagerPrivate)) #define CONF_SCHEMA "org.cinnamon.settings-daemon.plugins.xrandr" #define CONF_KEY_DEFAULT_MONITORS_SETUP "default-monitors-setup" #define CONF_KEY_DEFAULT_CONFIGURATION_FILE "default-configuration-file" /* Number of seconds that the confirmation dialog will last before it resets the * RANDR configuration to its old state. */ #define CONFIRMATION_DIALOG_SECONDS 30 /* name of the icon files (csd-xrandr.svg, etc.) */ #define CSD_XRANDR_ICON_NAME "csd-xrandr" #define CSD_DBUS_PATH "/org/cinnamon/SettingsDaemon" #define CSD_XRANDR_DBUS_PATH CSD_DBUS_PATH "/XRANDR" static const gchar introspection_xml[] = "" " " " " " " " " " " "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; struct CsdXrandrManagerPrivate { GnomeRRScreen *rw_screen; gboolean running; UpClient *upower_client; gboolean laptop_lid_is_closed; GSettings *settings; GDBusNodeInfo *introspection_data; GDBusConnection *connection; GCancellable *bus_cancellable; /* fn-F7 status */ int current_fn_f7_config; /* -1 if no configs */ GnomeRRConfig **fn_f7_configs; /* NULL terminated, NULL if there are no configs */ /* Last time at which we got a "screen got reconfigured" event; see on_randr_event() */ guint32 last_config_timestamp; #ifdef HAVE_WACOM WacomDeviceDatabase *wacom_db; #endif }; static const GnomeRRRotation possible_rotations[] = { GNOME_RR_ROTATION_0, GNOME_RR_ROTATION_90, GNOME_RR_ROTATION_180, GNOME_RR_ROTATION_270 /* We don't allow REFLECT_X or REFLECT_Y for now, as gnome-display-properties doesn't allow them, either */ }; static void csd_xrandr_manager_class_init (CsdXrandrManagerClass *klass); static void csd_xrandr_manager_init (CsdXrandrManager *xrandr_manager); static void csd_xrandr_manager_finalize (GObject *object); static void error_message (CsdXrandrManager *mgr, const char *primary_text, GError *error_to_display, const char *secondary_text); static void get_allowed_rotations_for_output (GnomeRRConfig *config, GnomeRRScreen *rr_screen, GnomeRROutputInfo *output, int *out_num_rotations, GnomeRRRotation *out_rotations); static void handle_fn_f7 (CsdXrandrManager *mgr, guint32 timestamp); static void handle_rotate_windows (CsdXrandrManager *mgr, GnomeRRRotation rotation, guint32 timestamp); G_DEFINE_TYPE (CsdXrandrManager, csd_xrandr_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static FILE *log_file; static void log_open (void) { char *toggle_filename; char *log_filename; struct stat st; if (log_file) return; toggle_filename = g_build_filename (g_get_home_dir (), "csd-debug-randr", NULL); log_filename = g_build_filename (g_get_home_dir (), "csd-debug-randr.log", NULL); if (stat (toggle_filename, &st) != 0) goto out; log_file = fopen (log_filename, "a"); if (log_file && ftell (log_file) == 0) fprintf (log_file, "To keep this log from being created, please rm ~/csd-debug-randr\n"); out: g_free (toggle_filename); g_free (log_filename); } static void log_close (void) { if (log_file) { fclose (log_file); log_file = NULL; } } static void log_msg (const char *format, ...) { if (log_file) { va_list args; va_start (args, format); vfprintf (log_file, format, args); va_end (args); } } static void log_output (GnomeRROutputInfo *output) { gchar *name = gnome_rr_output_info_get_name (output); gchar *display_name = gnome_rr_output_info_get_display_name (output); log_msg (" %s: ", name ? name : "unknown"); if (gnome_rr_output_info_is_connected (output)) { if (gnome_rr_output_info_is_active (output)) { int x, y, width, height; gnome_rr_output_info_get_geometry (output, &x, &y, &width, &height); log_msg ("%dx%d@%d +%d+%d", width, height, gnome_rr_output_info_get_refresh_rate (output), x, y); } else log_msg ("off"); } else log_msg ("disconnected"); if (display_name) log_msg (" (%s)", display_name); if (gnome_rr_output_info_get_primary (output)) log_msg (" (primary output)"); log_msg ("\n"); } static void log_configuration (GnomeRRConfig *config) { int i; GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); log_msg (" cloned: %s\n", gnome_rr_config_get_clone (config) ? "yes" : "no"); for (i = 0; outputs[i] != NULL; i++) log_output (outputs[i]); if (i == 0) log_msg (" no outputs!\n"); } static char timestamp_relationship (guint32 a, guint32 b) { if (a < b) return '<'; else if (a > b) return '>'; else return '='; } static void log_screen (GnomeRRScreen *screen) { GnomeRRConfig *config; int min_w, min_h, max_w, max_h; guint32 change_timestamp, config_timestamp; if (!log_file) return; config = gnome_rr_config_new_current (screen, NULL); gnome_rr_screen_get_ranges (screen, &min_w, &max_w, &min_h, &max_h); gnome_rr_screen_get_timestamps (screen, &change_timestamp, &config_timestamp); log_msg (" Screen min(%d, %d), max(%d, %d), change=%u %c config=%u\n", min_w, min_h, max_w, max_h, change_timestamp, timestamp_relationship (change_timestamp, config_timestamp), config_timestamp); log_configuration (config); g_object_unref (config); } static void log_configurations (GnomeRRConfig **configs) { int i; if (!configs) { log_msg (" No configurations\n"); return; } for (i = 0; configs[i]; i++) { log_msg (" Configuration %d\n", i); log_configuration (configs[i]); } } static void show_timestamps_dialog (CsdXrandrManager *manager, const char *msg) { #if 1 return; #else struct CsdXrandrManagerPrivate *priv = manager->priv; GtkWidget *dialog; guint32 change_timestamp, config_timestamp; static int serial; gnome_rr_screen_get_timestamps (priv->rw_screen, &change_timestamp, &config_timestamp); dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "RANDR timestamps (%d):\n%s\nchange: %u\nconfig: %u", serial++, msg, change_timestamp, config_timestamp); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); gtk_widget_show (dialog); #endif } static void print_output (GnomeRROutputInfo *info) { int x, y, width, height; g_print (" Output: %s attached to %s\n", gnome_rr_output_info_get_display_name (info), gnome_rr_output_info_get_name (info)); g_print (" status: %s\n", gnome_rr_output_info_is_active (info) ? "on" : "off"); gnome_rr_output_info_get_geometry (info, &x, &y, &width, &height); g_print (" width: %d\n", width); g_print (" height: %d\n", height); g_print (" rate: %d\n", gnome_rr_output_info_get_refresh_rate (info)); g_print (" primary: %s\n", gnome_rr_output_info_get_primary (info) ? "true" : "false"); g_print (" position: %d %d\n", x, y); } static void print_configuration (GnomeRRConfig *config, const char *header) { int i; GnomeRROutputInfo **outputs; g_print ("=== %s Configuration ===\n", header); if (!config) { g_print (" none\n"); return; } g_print (" Clone: %s\n", gnome_rr_config_get_clone (config) ? "true" : "false"); outputs = gnome_rr_config_get_outputs (config); for (i = 0; outputs[i] != NULL; ++i) print_output (outputs[i]); } static gboolean is_laptop (GnomeRRScreen *screen, GnomeRROutputInfo *output) { GnomeRROutput *rr_output; rr_output = gnome_rr_screen_get_output_by_name (screen, gnome_rr_output_info_get_name (output)); return gnome_rr_output_is_laptop (rr_output); } static GnomeRROutputInfo * get_laptop_output_info (GnomeRRScreen *screen, GnomeRRConfig *config) { int i; GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (config); for (i = 0; outputs[i] != NULL; i++) { if (is_laptop (screen, outputs[i])) return outputs[i]; } return NULL; } static gboolean non_laptop_outputs_are_active (GnomeRRConfig *config, GnomeRROutputInfo *laptop_info) { GnomeRROutputInfo **outputs; int i; outputs = gnome_rr_config_get_outputs (config); for (i = 0; outputs[i] != NULL; i++) { if (outputs[i] == laptop_info) continue; if (gnome_rr_output_info_is_active (outputs[i])) return TRUE; } return FALSE; } static void turn_off_laptop_display_in_configuration (GnomeRRScreen *screen, GnomeRRConfig *config) { GnomeRROutputInfo *laptop_info; laptop_info = get_laptop_output_info (screen, config); if (laptop_info) { /* Turn off the laptop's screen only if other displays are on. This is to avoid an all-black-screens scenario. */ if (non_laptop_outputs_are_active (config, laptop_info)) gnome_rr_output_info_set_active (laptop_info, FALSE); } /* Adjust the offsets of outputs so they start at (0, 0) */ gnome_rr_config_sanitize (config); } /* This function effectively centralizes the use of gnome_rr_config_apply_from_filename_with_time(). * * Optionally filters out GNOME_RR_ERROR_NO_MATCHING_CONFIG from the matching * process(), since that is not usually an error. */ static gboolean apply_configuration_from_filename (CsdXrandrManager *manager, const char *filename, gboolean no_matching_config_is_an_error, guint32 timestamp, GError **error) { struct CsdXrandrManagerPrivate *priv = manager->priv; GnomeRRConfig *config; GError *my_error; gboolean success; char *str; str = g_strdup_printf ("Applying %s with timestamp %d", filename, timestamp); show_timestamps_dialog (manager, str); g_free (str); my_error = NULL; config = g_object_new (GNOME_TYPE_RR_CONFIG, "screen", priv->rw_screen, NULL); if (!gnome_rr_config_load_filename (config, filename, &my_error)) { g_object_unref (config); if (g_error_matches (my_error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_MATCHING_CONFIG)) { if (no_matching_config_is_an_error) { g_propagate_error (error, my_error); return FALSE; } else { /* This is not an error; the user probably changed his monitors * and so they don't match any of the stored configurations. */ g_error_free (my_error); return TRUE; } } else { g_propagate_error (error, my_error); return FALSE; } } if (up_client_get_lid_is_closed (priv->upower_client)) turn_off_laptop_display_in_configuration (priv->rw_screen, config); gnome_rr_config_ensure_primary (config); success = gnome_rr_config_apply_with_time (config, priv->rw_screen, timestamp, error); g_object_unref (config); return success; } /* This function centralizes the use of gnome_rr_config_apply_with_time(). * * Applies a configuration. * We just return whether setting the configuration succeeded. */ static gboolean apply_configuration (CsdXrandrManager *manager, GnomeRRConfig *config, guint32 timestamp, gboolean save_configuration) { CsdXrandrManagerPrivate *priv = manager->priv; GError *error; gboolean success; gnome_rr_config_ensure_primary (config); print_configuration (config, "Applying Configuration"); error = NULL; success = gnome_rr_config_apply_with_time (config, priv->rw_screen, timestamp, &error); if (success) { if (save_configuration) gnome_rr_config_save (config, NULL); /* NULL-GError - there's not much we can do if this fails */ } else { log_msg ("Could not switch to the following configuration (timestamp %u): %s\n", timestamp, error->message); log_configuration (config); g_error_free (error); } return success; } static void restore_backup_configuration_without_messages (const char *backup_filename, const char *intended_filename) { backup_filename = gnome_rr_config_get_backup_filename (); rename (backup_filename, intended_filename); } static void restore_backup_configuration (CsdXrandrManager *manager, const char *backup_filename, const char *intended_filename, guint32 timestamp) { int saved_errno; if (rename (backup_filename, intended_filename) == 0) { GError *error; error = NULL; if (!apply_configuration_from_filename (manager, intended_filename, FALSE, timestamp, &error)) { error_message (manager, _("Could not restore the display's configuration"), error, NULL); if (error) g_error_free (error); } return; } saved_errno = errno; /* ENOENT means the original file didn't exist. That is *not* an error; * the backup was not created because there wasn't even an original * monitors.xml (such as on a first-time login). Note that *here* there * is a "didn't work" monitors.xml, so we must delete that one. */ if (saved_errno == ENOENT) unlink (intended_filename); else { char *msg; msg = g_strdup_printf ("Could not rename %s to %s: %s", backup_filename, intended_filename, g_strerror (saved_errno)); error_message (manager, _("Could not restore the display's configuration from a backup"), NULL, msg); g_free (msg); } unlink (backup_filename); } typedef struct { CsdXrandrManager *manager; GtkWidget *dialog; int countdown; int response_id; } TimeoutDialog; static void print_countdown_text (TimeoutDialog *timeout) { gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (timeout->dialog), ngettext ("The display will be reset to its previous configuration in %d second", "The display will be reset to its previous configuration in %d seconds", timeout->countdown), timeout->countdown); } static gboolean timeout_cb (gpointer data) { TimeoutDialog *timeout = data; timeout->countdown--; if (timeout->countdown == 0) { timeout->response_id = GTK_RESPONSE_CANCEL; gtk_main_quit (); } else { print_countdown_text (timeout); } return TRUE; } static void timeout_response_cb (GtkDialog *dialog, int response_id, gpointer data) { TimeoutDialog *timeout = data; if (response_id == GTK_RESPONSE_DELETE_EVENT) { /* The user closed the dialog or pressed ESC, revert */ timeout->response_id = GTK_RESPONSE_CANCEL; } else timeout->response_id = response_id; gtk_main_quit (); } static gboolean user_says_things_are_ok (CsdXrandrManager *manager, GdkWindow *parent_window) { TimeoutDialog timeout; guint timeout_id; timeout.manager = manager; timeout.dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Does the display look OK?")); timeout.countdown = CONFIRMATION_DIALOG_SECONDS; print_countdown_text (&timeout); gtk_window_set_title (GTK_WINDOW (timeout.dialog), _("Confirm New Configuration")); gtk_window_set_icon_name (GTK_WINDOW (timeout.dialog), "preferences-desktop-display"); gtk_dialog_add_button (GTK_DIALOG (timeout.dialog), _("_Restore Previous Configuration"), GTK_RESPONSE_CANCEL); gtk_dialog_add_button (GTK_DIALOG (timeout.dialog), _("_Keep This Configuration"), GTK_RESPONSE_ACCEPT); gtk_dialog_set_default_response (GTK_DIALOG (timeout.dialog), GTK_RESPONSE_ACCEPT); /* ah, the optimism */ g_signal_connect (timeout.dialog, "response", G_CALLBACK (timeout_response_cb), &timeout); gtk_widget_realize (timeout.dialog); if (parent_window) gdk_window_set_transient_for (gtk_widget_get_window (timeout.dialog), parent_window); gtk_widget_show_all (timeout.dialog); /* We don't use g_timeout_add_seconds() since we actually care that the user sees "real" second ticks in the dialog */ timeout_id = g_timeout_add (1000, timeout_cb, &timeout); gtk_main (); gtk_widget_destroy (timeout.dialog); g_source_remove (timeout_id); if (timeout.response_id == GTK_RESPONSE_ACCEPT) return TRUE; else return FALSE; } struct confirmation { CsdXrandrManager *manager; GdkWindow *parent_window; guint32 timestamp; }; static gboolean confirm_with_user_idle_cb (gpointer data) { struct confirmation *confirmation = data; char *backup_filename; char *intended_filename; backup_filename = gnome_rr_config_get_backup_filename (); intended_filename = gnome_rr_config_get_intended_filename (); if (user_says_things_are_ok (confirmation->manager, confirmation->parent_window)) unlink (backup_filename); else restore_backup_configuration (confirmation->manager, backup_filename, intended_filename, confirmation->timestamp); g_free (confirmation); return FALSE; } static void queue_confirmation_by_user (CsdXrandrManager *manager, GdkWindow *parent_window, guint32 timestamp) { struct confirmation *confirmation; confirmation = g_new (struct confirmation, 1); confirmation->manager = manager; confirmation->parent_window = parent_window; confirmation->timestamp = timestamp; g_idle_add (confirm_with_user_idle_cb, confirmation); } static gboolean try_to_apply_intended_configuration (CsdXrandrManager *manager, GdkWindow *parent_window, guint32 timestamp, GError **error) { char *backup_filename; char *intended_filename; gboolean result; /* Try to apply the intended configuration */ backup_filename = gnome_rr_config_get_backup_filename (); intended_filename = gnome_rr_config_get_intended_filename (); result = apply_configuration_from_filename (manager, intended_filename, FALSE, timestamp, error); if (!result) { error_message (manager, _("The selected configuration for displays could not be applied"), error ? *error : NULL, NULL); restore_backup_configuration_without_messages (backup_filename, intended_filename); goto out; } else { /* We need to return as quickly as possible, so instead of * confirming with the user right here, we do it in an idle * handler. The caller only expects a status for "could you * change the RANDR configuration?", not "is the user OK with it * as well?". */ queue_confirmation_by_user (manager, parent_window, timestamp); } out: g_free (backup_filename); g_free (intended_filename); return result; } /* DBus method for org.cinnamon.SettingsDaemon.XRANDR_2 ApplyConfiguration; see csd-xrandr-manager.xml for the interface definition */ static gboolean csd_xrandr_manager_2_apply_configuration (CsdXrandrManager *manager, gint64 parent_window_id, gint64 timestamp, GError **error) { GdkWindow *parent_window; gboolean result; if (parent_window_id != 0) parent_window = gdk_x11_window_foreign_new_for_display (gdk_display_get_default (), (Window) parent_window_id); else parent_window = NULL; result = try_to_apply_intended_configuration (manager, parent_window, (guint32) timestamp, error); if (parent_window) g_object_unref (parent_window); return result; } /* DBus method for org.cinnamon.SettingsDaemon.XRANDR_2 VideoModeSwitch; see csd-xrandr-manager.xml for the interface definition */ static gboolean csd_xrandr_manager_2_video_mode_switch (CsdXrandrManager *manager, guint32 timestamp, GError **error) { handle_fn_f7 (manager, timestamp); return TRUE; } /* DBus method for org.cinnamon.SettingsDaemon.XRANDR_2 Rotate; see csd-xrandr-manager.xml for the interface definition */ static gboolean csd_xrandr_manager_2_rotate (CsdXrandrManager *manager, guint32 timestamp, GError **error) { handle_rotate_windows (manager, GNOME_RR_ROTATION_NEXT, timestamp); return TRUE; } /* DBus method for org.cinnamon.SettingsDaemon.XRANDR_2 RotateTo; see csd-xrandr-manager.xml for the interface definition */ static gboolean csd_xrandr_manager_2_rotate_to (CsdXrandrManager *manager, GnomeRRRotation rotation, guint32 timestamp, GError **error) { guint i; gboolean found; found = FALSE; for (i = 0; i < G_N_ELEMENTS (possible_rotations); i++) { if (rotation == possible_rotations[i]) { found = TRUE; break; } } if (found == FALSE) { g_debug ("Not setting out of bounds rotation '%d'", rotation); return FALSE; } handle_rotate_windows (manager, rotation, timestamp); return TRUE; } static gboolean get_clone_size (GnomeRRScreen *screen, int *width, int *height) { GnomeRRMode **modes = gnome_rr_screen_list_clone_modes (screen); int best_w, best_h; int i; best_w = 0; best_h = 0; for (i = 0; modes[i] != NULL; ++i) { GnomeRRMode *mode = modes[i]; int w, h; w = gnome_rr_mode_get_width (mode); h = gnome_rr_mode_get_height (mode); if (w * h > best_w * best_h) { best_w = w; best_h = h; } } if (best_w > 0 && best_h > 0) { if (width) *width = best_w; if (height) *height = best_h; return TRUE; } return FALSE; } static gboolean config_is_all_off (GnomeRRConfig *config) { int j; GnomeRROutputInfo **outputs; outputs = gnome_rr_config_get_outputs (config); for (j = 0; outputs[j] != NULL; ++j) { if (gnome_rr_output_info_is_active (outputs[j])) { return FALSE; } } return TRUE; } static gboolean laptop_lid_is_closed (CsdXrandrManager *manager) { return up_client_get_lid_is_closed (manager->priv->upower_client); } static gboolean is_laptop_with_closed_lid (CsdXrandrManager *manager, GnomeRRScreen *screen, GnomeRROutputInfo *info) { return is_laptop (screen, info) && laptop_lid_is_closed (manager); } static GnomeRRConfig * make_clone_setup (CsdXrandrManager *manager, GnomeRRScreen *screen) { GnomeRRConfig *result; GnomeRROutputInfo **outputs; int width, height; int i; if (!get_clone_size (screen, &width, &height)) return NULL; result = gnome_rr_config_new_current (screen, NULL); gnome_rr_config_set_clone (result, TRUE); outputs = gnome_rr_config_get_outputs (result); for (i = 0; outputs[i] != NULL; ++i) { GnomeRROutputInfo *info = outputs[i]; gnome_rr_output_info_set_active (info, FALSE); if (!is_laptop_with_closed_lid (manager, screen, info) && gnome_rr_output_info_is_connected (info)) { GnomeRROutput *output = gnome_rr_screen_get_output_by_name (screen, gnome_rr_output_info_get_name (info)); GnomeRRMode **modes = gnome_rr_output_list_modes (output); int j; int best_rate = 0; for (j = 0; modes[j] != NULL; ++j) { GnomeRRMode *mode = modes[j]; int w, h; w = gnome_rr_mode_get_width (mode); h = gnome_rr_mode_get_height (mode); if (w == width && h == height) { int r = gnome_rr_mode_get_freq (mode); if (r > best_rate) best_rate = r; } } if (best_rate > 0) { gnome_rr_output_info_set_active (info, TRUE); gnome_rr_output_info_set_rotation (info, GNOME_RR_ROTATION_0); gnome_rr_output_info_set_refresh_rate (info, best_rate); gnome_rr_output_info_set_geometry (info, 0, 0, width, height); } } } if (config_is_all_off (result)) { g_object_unref (G_OBJECT (result)); result = NULL; } print_configuration (result, "clone setup"); return result; } static GnomeRRMode * find_best_mode (GnomeRROutput *output) { GnomeRRMode *preferred; GnomeRRMode **modes; int best_size; int best_width, best_height, best_rate; int i; GnomeRRMode *best_mode; preferred = gnome_rr_output_get_preferred_mode (output); if (preferred) return preferred; modes = gnome_rr_output_list_modes (output); if (!modes) return NULL; best_size = best_width = best_height = best_rate = 0; best_mode = NULL; for (i = 0; modes[i] != NULL; i++) { int w, h, r; int size; w = gnome_rr_mode_get_width (modes[i]); h = gnome_rr_mode_get_height (modes[i]); r = gnome_rr_mode_get_freq (modes[i]); size = w * h; if (size > best_size) { best_size = size; best_width = w; best_height = h; best_rate = r; best_mode = modes[i]; } else if (size == best_size) { if (r > best_rate) { best_rate = r; best_mode = modes[i]; } } } return best_mode; } static gboolean turn_on (GnomeRRScreen *screen, GnomeRROutputInfo *info, int x, int y) { GnomeRROutput *output = gnome_rr_screen_get_output_by_name (screen, gnome_rr_output_info_get_name (info)); GnomeRRMode *mode = find_best_mode (output); if (mode) { gnome_rr_output_info_set_active (info, TRUE); gnome_rr_output_info_set_geometry (info, x, y, gnome_rr_mode_get_width (mode), gnome_rr_mode_get_height (mode)); gnome_rr_output_info_set_rotation (info, GNOME_RR_ROTATION_0); gnome_rr_output_info_set_refresh_rate (info, gnome_rr_mode_get_freq (mode)); return TRUE; } return FALSE; } static GnomeRRConfig * make_laptop_setup (CsdXrandrManager *manager, GnomeRRScreen *screen) { /* Turn on the laptop, disable everything else */ GnomeRRConfig *result = gnome_rr_config_new_current (screen, NULL); GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (result); int i; gnome_rr_config_set_clone (result, FALSE); for (i = 0; outputs[i] != NULL; ++i) { GnomeRROutputInfo *info = outputs[i]; if (is_laptop (screen, info) && !laptop_lid_is_closed (manager)) { if (!turn_on (screen, info, 0, 0)) { g_object_unref (G_OBJECT (result)); result = NULL; break; } } else { gnome_rr_output_info_set_active (info, FALSE); } } if (config_is_all_off (result)) { g_object_unref (G_OBJECT (result)); result = NULL; } print_configuration (result, "Laptop setup"); /* FIXME - Maybe we should return NULL if there is more than * one connected "laptop" screen? */ return result; } static int turn_on_and_get_rightmost_offset (GnomeRRScreen *screen, GnomeRROutputInfo *info, int x) { if (turn_on (screen, info, x, 0)) { int width; gnome_rr_output_info_get_geometry (info, NULL, NULL, &width, NULL); x += width; } return x; } /* Used from g_ptr_array_sort(); compares outputs based on their X position */ static int compare_output_positions (gconstpointer a, gconstpointer b) { GnomeRROutputInfo **oa = (GnomeRROutputInfo **) a; GnomeRROutputInfo **ob = (GnomeRROutputInfo **) b; int xa, xb; gnome_rr_output_info_get_geometry (*oa, &xa, NULL, NULL, NULL); gnome_rr_output_info_get_geometry (*ob, &xb, NULL, NULL, NULL); return xb - xa; } /* A set of outputs with already-set sizes and positions may not fit in the * frame buffer that is available. Turn off outputs right-to-left until we find * a size that fits. Returns whether something applicable was found * (i.e. something that fits and that does not consist of only-off outputs). */ static gboolean trim_rightmost_outputs_that_dont_fit_in_framebuffer (GnomeRRScreen *rr_screen, GnomeRRConfig *config) { GnomeRROutputInfo **outputs; int i; gboolean applicable; GPtrArray *sorted_outputs; outputs = gnome_rr_config_get_outputs (config); g_return_val_if_fail (outputs != NULL, FALSE); /* How many are on? */ sorted_outputs = g_ptr_array_new (); for (i = 0; outputs[i] != NULL; i++) { if (gnome_rr_output_info_is_active (outputs[i])) g_ptr_array_add (sorted_outputs, outputs[i]); } /* Lay them out from left to right */ g_ptr_array_sort (sorted_outputs, compare_output_positions); /* Trim! */ applicable = FALSE; for (i = sorted_outputs->len - 1; i >= 0; i--) { GError *error = NULL; gboolean is_bounds_error; applicable = gnome_rr_config_applicable (config, rr_screen, &error); if (applicable) break; is_bounds_error = g_error_matches (error, GNOME_RR_ERROR, GNOME_RR_ERROR_BOUNDS_ERROR); g_error_free (error); if (!is_bounds_error) break; gnome_rr_output_info_set_active (sorted_outputs->pdata[i], FALSE); } if (config_is_all_off (config)) applicable = FALSE; g_ptr_array_free (sorted_outputs, FALSE); return applicable; } static gboolean follow_laptop_lid(CsdXrandrManager *manager) { CsdXrandrBootBehaviour val; val = g_settings_get_enum (manager->priv->settings, CONF_KEY_DEFAULT_MONITORS_SETUP); return val == CSD_XRANDR_BOOT_BEHAVIOUR_FOLLOW_LID || val == CSD_XRANDR_BOOT_BEHAVIOUR_CLONE; } static GnomeRRConfig * make_xinerama_setup (CsdXrandrManager *manager, GnomeRRScreen *screen) { /* Turn on everything that has a preferred mode, and * position it from left to right */ GnomeRRConfig *result = gnome_rr_config_new_current (screen, NULL); GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (result); int i; int x; gnome_rr_config_set_clone (result, FALSE); x = 0; for (i = 0; outputs[i] != NULL; ++i) { GnomeRROutputInfo *info = outputs[i]; if (is_laptop (screen, info)) { if (laptop_lid_is_closed (manager) && follow_laptop_lid (manager)) gnome_rr_output_info_set_active (info, FALSE); else { gnome_rr_output_info_set_primary (info, TRUE); x = turn_on_and_get_rightmost_offset (screen, info, x); } } } for (i = 0; outputs[i] != NULL; ++i) { GnomeRROutputInfo *info = outputs[i]; if (gnome_rr_output_info_is_connected (info) && !is_laptop (screen, info)) { gnome_rr_output_info_set_primary (info, FALSE); x = turn_on_and_get_rightmost_offset (screen, info, x); } } if (!trim_rightmost_outputs_that_dont_fit_in_framebuffer (screen, result)) { g_object_unref (G_OBJECT (result)); result = NULL; } print_configuration (result, "xinerama setup"); return result; } static GnomeRRConfig * make_other_setup (GnomeRRScreen *screen) { /* Turn off all laptops, and make all external monitors clone * from (0, 0) */ GnomeRRConfig *result = gnome_rr_config_new_current (screen, NULL); GnomeRROutputInfo **outputs = gnome_rr_config_get_outputs (result); int i; gnome_rr_config_set_clone (result, FALSE); for (i = 0; outputs[i] != NULL; ++i) { GnomeRROutputInfo *info = outputs[i]; if (is_laptop (screen, info)) { gnome_rr_output_info_set_active (info, FALSE); } else { if (gnome_rr_output_info_is_connected (info)) turn_on (screen, info, 0, 0); } } if (!trim_rightmost_outputs_that_dont_fit_in_framebuffer (screen, result)) { g_object_unref (G_OBJECT (result)); result = NULL; } print_configuration (result, "other setup"); return result; } static GPtrArray * sanitize (CsdXrandrManager *manager, GPtrArray *array) { int i; GPtrArray *new; g_debug ("before sanitizing"); for (i = 0; i < array->len; ++i) { if (array->pdata[i]) { print_configuration (array->pdata[i], "before"); } } /* Remove configurations that are duplicates of * configurations earlier in the cycle */ for (i = 0; i < array->len; i++) { int j; for (j = i + 1; j < array->len; j++) { GnomeRRConfig *this = array->pdata[j]; GnomeRRConfig *other = array->pdata[i]; if (this && other && gnome_rr_config_equal (this, other)) { g_debug ("removing duplicate configuration"); g_object_unref (this); array->pdata[j] = NULL; break; } } } for (i = 0; i < array->len; ++i) { GnomeRRConfig *config = array->pdata[i]; if (config && config_is_all_off (config)) { g_debug ("removing configuration as all outputs are off"); g_object_unref (array->pdata[i]); array->pdata[i] = NULL; } } /* Do a final sanitization pass. This will remove configurations that * don't fit in the framebuffer's Virtual size. */ for (i = 0; i < array->len; i++) { GnomeRRConfig *config = array->pdata[i]; if (config) { GError *error; error = NULL; if (!gnome_rr_config_applicable (config, manager->priv->rw_screen, &error)) { /* NULL-GError */ g_debug ("removing configuration which is not applicable because %s", error->message); g_error_free (error); g_object_unref (config); array->pdata[i] = NULL; } } } /* Remove NULL configurations */ new = g_ptr_array_new (); for (i = 0; i < array->len; ++i) { if (array->pdata[i]) { g_ptr_array_add (new, array->pdata[i]); print_configuration (array->pdata[i], "Final"); } } if (new->len > 0) { g_ptr_array_add (new, NULL); } else { g_ptr_array_free (new, TRUE); new = NULL; } g_ptr_array_free (array, TRUE); return new; } static void generate_fn_f7_configs (CsdXrandrManager *mgr) { GPtrArray *array = g_ptr_array_new (); GnomeRRScreen *screen = mgr->priv->rw_screen; g_debug ("Generating configurations"); /* Free any existing list of configurations */ if (mgr->priv->fn_f7_configs) { int i; for (i = 0; mgr->priv->fn_f7_configs[i] != NULL; ++i) g_object_unref (mgr->priv->fn_f7_configs[i]); g_free (mgr->priv->fn_f7_configs); mgr->priv->fn_f7_configs = NULL; mgr->priv->current_fn_f7_config = -1; } g_ptr_array_add (array, gnome_rr_config_new_current (screen, NULL)); g_ptr_array_add (array, make_clone_setup (mgr, screen)); g_ptr_array_add (array, make_xinerama_setup (mgr, screen)); g_ptr_array_add (array, make_other_setup (screen)); g_ptr_array_add (array, make_laptop_setup (mgr, screen)); array = sanitize (mgr, array); if (array) { mgr->priv->fn_f7_configs = (GnomeRRConfig **)g_ptr_array_free (array, FALSE); mgr->priv->current_fn_f7_config = 0; } } static void error_message (CsdXrandrManager *mgr, const char *primary_text, GError *error_to_display, const char *secondary_text) { g_warning("%s\n%s\n%s", primary_text? primary_text : "", secondary_text? secondary_text : "", error_to_display? error_to_display->message : ""); } static void handle_fn_f7 (CsdXrandrManager *mgr, guint32 timestamp) { CsdXrandrManagerPrivate *priv = mgr->priv; GnomeRRScreen *screen = priv->rw_screen; GnomeRRConfig *current; GError *error; /* Theory of fn-F7 operation * * We maintain a datastructure "fn_f7_status", that contains * a list of GnomeRRConfig's. Each of the GnomeRRConfigs has a * mode (or "off") for each connected output. * * When the user hits fn-F7, we cycle to the next GnomeRRConfig * in the data structure. If the data structure does not exist, it * is generated. If the configs in the data structure do not match * the current hardware reality, it is regenerated. * */ g_debug ("Handling fn-f7"); log_open (); log_msg ("Handling XF86Display hotkey - timestamp %u\n", timestamp); error = NULL; if (!gnome_rr_screen_refresh (screen, &error) && error) { char *str; str = g_strdup_printf (_("Could not refresh the screen information: %s"), error->message); g_error_free (error); log_msg ("%s\n", str); error_message (mgr, str, NULL, _("Trying to switch the monitor configuration anyway.")); g_free (str); } if (!priv->fn_f7_configs) { log_msg ("Generating stock configurations:\n"); generate_fn_f7_configs (mgr); log_configurations (priv->fn_f7_configs); } current = gnome_rr_config_new_current (screen, NULL); if (priv->fn_f7_configs && (!gnome_rr_config_match (current, priv->fn_f7_configs[0]) || !gnome_rr_config_equal (current, priv->fn_f7_configs[mgr->priv->current_fn_f7_config]))) { /* Our view of the world is incorrect, so regenerate the * configurations */ generate_fn_f7_configs (mgr); log_msg ("Regenerated stock configurations:\n"); log_configurations (priv->fn_f7_configs); } g_object_unref (current); if (priv->fn_f7_configs) { guint32 server_timestamp; gboolean success; mgr->priv->current_fn_f7_config++; if (priv->fn_f7_configs[mgr->priv->current_fn_f7_config] == NULL) mgr->priv->current_fn_f7_config = 0; g_debug ("cycling to next configuration (%d)", mgr->priv->current_fn_f7_config); print_configuration (priv->fn_f7_configs[mgr->priv->current_fn_f7_config], "new config"); g_debug ("applying"); /* See https://bugzilla.gnome.org/show_bug.cgi?id=610482 * * Sometimes we'll get two rapid XF86Display keypress events, * but their timestamps will be out of order with respect to the * RANDR timestamps. This *may* be due to stupid BIOSes sending * out display-switch keystrokes "to make Windows work". * * The X server will error out if the timestamp provided is * older than a previous change configuration timestamp. We * assume here that we do want this event to go through still, * since kernel timestamps may be skewed wrt the X server. */ gnome_rr_screen_get_timestamps (screen, NULL, &server_timestamp); if (timestamp < server_timestamp) timestamp = server_timestamp; success = apply_configuration (mgr, priv->fn_f7_configs[mgr->priv->current_fn_f7_config], timestamp, TRUE); if (success) { log_msg ("Successfully switched to configuration (timestamp %u):\n", timestamp); log_configuration (priv->fn_f7_configs[mgr->priv->current_fn_f7_config]); } } else { g_debug ("no configurations generated"); } log_close (); g_debug ("done handling fn-f7"); } static GnomeRRRotation get_next_rotation (GnomeRRRotation allowed_rotations, GnomeRRRotation current_rotation) { int i; int current_index; /* First, find the index of the current rotation */ current_index = -1; for (i = 0; i < G_N_ELEMENTS (possible_rotations); i++) { GnomeRRRotation r; r = possible_rotations[i]; if (r == current_rotation) { current_index = i; break; } } if (current_index == -1) { /* Huh, the current_rotation was not one of the supported rotations. Bail out. */ return current_rotation; } /* Then, find the next rotation that is allowed */ i = (current_index + 1) % G_N_ELEMENTS (possible_rotations); while (1) { GnomeRRRotation r; r = possible_rotations[i]; if (r == current_rotation) { /* We wrapped around and no other rotation is suported. Bummer. */ return current_rotation; } else if (r & allowed_rotations) return r; i = (i + 1) % G_N_ELEMENTS (possible_rotations); } } struct { GnomeRRRotation rotation; gfloat matrix[9]; } evdev_rotations[] = { { GNOME_RR_ROTATION_0, {1, 0, 0, 0, 1, 0, 0, 0, 1}}, { GNOME_RR_ROTATION_90, {0, -1, 1, 1, 0, 0, 0, 0, 1}}, { GNOME_RR_ROTATION_180, {-1, 0, 1, 0, -1, 1, 0, 0, 1}}, { GNOME_RR_ROTATION_270, {0, 1, 0, -1, 0, 1, 0, 0, 1}} }; static guint get_rotation_index (GnomeRRRotation rotation) { guint i; for (i = 0; i < G_N_ELEMENTS (evdev_rotations); i++) { if (evdev_rotations[i].rotation == rotation) return i; } g_assert_not_reached (); } static gboolean is_wacom_tablet_device (CsdXrandrManager *mgr, XDeviceInfo *device_info) { #ifdef HAVE_WACOM CsdXrandrManagerPrivate *priv = mgr->priv; gchar *device_node; WacomDevice *wacom_device; gboolean is_tablet = FALSE; if (priv->wacom_db == NULL) priv->wacom_db = libwacom_database_new (); device_node = xdevice_get_device_node (device_info->id); if (device_node == NULL) return FALSE; wacom_device = libwacom_new_from_path (priv->wacom_db, device_node, FALSE, NULL); g_free (device_node); if (wacom_device == NULL) { g_free (device_node); return FALSE; } is_tablet = libwacom_has_touch (wacom_device) && libwacom_is_builtin (wacom_device); libwacom_destroy (wacom_device); return is_tablet; #else return FALSE; #endif } static void rotate_touchscreens (CsdXrandrManager *mgr, GnomeRRRotation rotation) { XDeviceInfo *device_info; gint n_devices; guint i, rot_idx; Atom float_atom = XInternAtom(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "FLOAT", True); if (!supports_xinput_devices ()) return; g_debug ("Rotating touchscreen devices"); device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return; rot_idx = get_rotation_index (rotation); for (i = 0; i < n_devices; i++) { if (is_wacom_tablet_device (mgr, &device_info[i])) { g_debug ("Not rotating tablet device '%s'", device_info[i].name); continue; } if (device_info_is_touchscreen (&device_info[i]) || device_info_is_tablet (&device_info[i])) { XDevice *device; gfloat *m = evdev_rotations[rot_idx].matrix; PropertyHelper matrix = { .name = "Coordinate Transformation Matrix", .nitems = 9, .format = 32, .type = float_atom, .data.i = (int *)m, }; g_debug ("About to rotate '%s'", device_info[i].name); gdk_error_trap_push (); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_error_trap_pop () || (device == NULL)) continue; if (device_set_property (device, device_info[i].name, &matrix) != FALSE) { g_print ("Rotated '%s' to configuration '%f, %f, %f, %f, %f, %f, %f, %f, %f'\n", device_info[i].name, evdev_rotations[rot_idx].matrix[0], evdev_rotations[rot_idx].matrix[1], evdev_rotations[rot_idx].matrix[2], evdev_rotations[rot_idx].matrix[3], evdev_rotations[rot_idx].matrix[4], evdev_rotations[rot_idx].matrix[5], evdev_rotations[rot_idx].matrix[6], evdev_rotations[rot_idx].matrix[7], evdev_rotations[rot_idx].matrix[8]); } xdevice_close (device); } } XFreeDeviceList (device_info); } /* We use this when the XF86RotateWindows key is pressed, or the * orientation of a tablet changes. The key is present * on some tablet PCs; they use it so that the user can rotate the tablet * easily. Some other tablet PCs will have an accelerometer instead. */ static void handle_rotate_windows (CsdXrandrManager *mgr, GnomeRRRotation rotation, guint32 timestamp) { CsdXrandrManagerPrivate *priv = mgr->priv; GnomeRRScreen *screen = priv->rw_screen; GnomeRRConfig *current; GnomeRROutputInfo *rotatable_output_info; int num_allowed_rotations; GnomeRRRotation allowed_rotations; GnomeRRRotation next_rotation; gboolean success; g_debug ("Handling XF86RotateWindows with rotation %d", rotation); /* Which output? */ current = gnome_rr_config_new_current (screen, NULL); rotatable_output_info = get_laptop_output_info (screen, current); if (rotatable_output_info == NULL) { g_debug ("No laptop outputs found to rotate; XF86RotateWindows key will do nothing"); goto out; } if (rotation <= GNOME_RR_ROTATION_NEXT) { /* Which rotation? */ get_allowed_rotations_for_output (current, priv->rw_screen, rotatable_output_info, &num_allowed_rotations, &allowed_rotations); next_rotation = get_next_rotation (allowed_rotations, gnome_rr_output_info_get_rotation (rotatable_output_info)); if (next_rotation == gnome_rr_output_info_get_rotation (rotatable_output_info)) { g_debug ("No rotations are supported other than the current one; XF86RotateWindows key will do nothing"); goto out; } } else { next_rotation = rotation; } /* Rotate */ gnome_rr_output_info_set_rotation (rotatable_output_info, next_rotation); success = apply_configuration (mgr, current, timestamp, TRUE); if (success) rotate_touchscreens (mgr, next_rotation); out: g_object_unref (current); } static GnomeRRConfig * make_default_setup (CsdXrandrManager *manager) { CsdXrandrManagerPrivate *priv = manager->priv; GnomeRRConfig *config; CsdXrandrBootBehaviour boot; boot = g_settings_get_enum (priv->settings, CONF_KEY_DEFAULT_MONITORS_SETUP); g_debug ("xrandr default monitors setup: %d\n", boot); switch (boot) { case CSD_XRANDR_BOOT_BEHAVIOUR_DO_NOTHING: config = make_xinerama_setup (manager, priv->rw_screen); break; case CSD_XRANDR_BOOT_BEHAVIOUR_FOLLOW_LID: if (laptop_lid_is_closed (manager)) config = make_other_setup (priv->rw_screen); else config = make_xinerama_setup (manager, priv->rw_screen); break; case CSD_XRANDR_BOOT_BEHAVIOUR_CLONE: config = make_clone_setup (manager, priv->rw_screen); break; case CSD_XRANDR_BOOT_BEHAVIOUR_DOCK: config = make_other_setup (priv->rw_screen); break; default: g_assert_not_reached (); } return config; } static void auto_configure_outputs (CsdXrandrManager *manager, guint32 timestamp) { GnomeRRConfig *config; g_debug ("xrandr auto-configure\n"); config = make_default_setup (manager); if (config) { apply_configuration (manager, config, timestamp, FALSE); g_object_unref (config); } else { g_debug ("No applicable configuration found during auto-configure"); } } static void use_stored_configuration_or_auto_configure_outputs (CsdXrandrManager *manager, guint32 timestamp) { CsdXrandrManagerPrivate *priv = manager->priv; char *intended_filename; GError *error; gboolean success; intended_filename = gnome_rr_config_get_intended_filename (); error = NULL; success = apply_configuration_from_filename (manager, intended_filename, TRUE, timestamp, &error); g_free (intended_filename); if (!success) { /* We don't bother checking the error type. * * Both G_FILE_ERROR_NOENT and * GNOME_RR_ERROR_NO_MATCHING_CONFIG would mean, "there * was no configuration to apply, or none that matched * the current outputs", and in that case we need to run * our fallback. * * Any other error means "we couldn't do the smart thing * of using a previously- saved configuration, anyway, * for some other reason. In that case, we also need to * run our fallback to avoid leaving the user with a * bogus configuration. */ if (error) g_error_free (error); if (timestamp != priv->last_config_timestamp || timestamp == GDK_CURRENT_TIME) { priv->last_config_timestamp = timestamp; auto_configure_outputs (manager, timestamp); log_msg (" Automatically configured outputs\n"); } else log_msg (" Ignored autoconfiguration as old and new config timestamps are the same\n"); } else log_msg ("Applied stored configuration\n"); } static void on_randr_event (GnomeRRScreen *screen, gpointer data) { CsdXrandrManager *manager = CSD_XRANDR_MANAGER (data); CsdXrandrManagerPrivate *priv = manager->priv; guint32 change_timestamp, config_timestamp; if (!priv->running) return; gnome_rr_screen_get_timestamps (screen, &change_timestamp, &config_timestamp); log_open (); log_msg ("Got RANDR event with timestamps change=%u %c config=%u\n", change_timestamp, timestamp_relationship (change_timestamp, config_timestamp), config_timestamp); if (change_timestamp >= config_timestamp) { GnomeRRConfig *rr_config; /* The event is due to an explicit configuration change. * * If the change was performed by us, then we need to do nothing. * * If the change was done by some other X client, we don't need * to do anything, either; the screen is already configured. */ /* Check if we need to update the primary */ rr_config = gnome_rr_config_new_current (priv->rw_screen, NULL); if (gnome_rr_config_ensure_primary (rr_config)) { if (gnome_rr_config_applicable (rr_config, priv->rw_screen, NULL)) { print_configuration (rr_config, "Updating for primary"); priv->last_config_timestamp = config_timestamp; gnome_rr_config_apply_with_time (rr_config, priv->rw_screen, config_timestamp, NULL); } } g_object_unref (rr_config); show_timestamps_dialog (manager, "ignoring since change > config"); log_msg (" Ignoring event since change >= config\n"); } else { /* Here, config_timestamp > change_timestamp. This means that * the screen got reconfigured because of hotplug/unplug; the X * server is just notifying us, and we need to configure the * outputs in a sane way. */ show_timestamps_dialog (manager, "need to deal with reconfiguration, as config > change"); use_stored_configuration_or_auto_configure_outputs (manager, config_timestamp); } log_close (); } static void get_allowed_rotations_for_output (GnomeRRConfig *config, GnomeRRScreen *rr_screen, GnomeRROutputInfo *output, int *out_num_rotations, GnomeRRRotation *out_rotations) { GnomeRRRotation current_rotation; int i; *out_num_rotations = 0; *out_rotations = 0; current_rotation = gnome_rr_output_info_get_rotation (output); /* Yay for brute force */ for (i = 0; i < G_N_ELEMENTS (possible_rotations); i++) { GnomeRRRotation rotation_to_test; rotation_to_test = possible_rotations[i]; gnome_rr_output_info_set_rotation (output, rotation_to_test); if (gnome_rr_config_applicable (config, rr_screen, NULL)) { /* NULL-GError */ (*out_num_rotations)++; (*out_rotations) |= rotation_to_test; } } gnome_rr_output_info_set_rotation (output, current_rotation); if (*out_num_rotations == 0 || *out_rotations == 0) { g_warning ("Huh, output %p says it doesn't support any rotations, and yet it has a current rotation?", output); *out_num_rotations = 1; *out_rotations = gnome_rr_output_info_get_rotation (output); } } static gboolean apply_intended_configuration (CsdXrandrManager *manager, const char *intended_filename, guint32 timestamp) { GError *my_error; gboolean result; my_error = NULL; result = apply_configuration_from_filename (manager, intended_filename, TRUE, timestamp, &my_error); if (!result) { if (my_error) { if (!g_error_matches (my_error, G_FILE_ERROR, G_FILE_ERROR_NOENT) && !g_error_matches (my_error, GNOME_RR_ERROR, GNOME_RR_ERROR_NO_MATCHING_CONFIG)) error_message (manager, _("Could not apply the stored configuration for monitors"), my_error, NULL); g_error_free (my_error); } } return result; } static void apply_default_boot_configuration (CsdXrandrManager *mgr, guint32 timestamp) { CsdXrandrManagerPrivate *priv = mgr->priv; GnomeRRConfig *config; CsdXrandrBootBehaviour boot; boot = g_settings_get_enum (priv->settings, CONF_KEY_DEFAULT_MONITORS_SETUP); if (boot == CSD_XRANDR_BOOT_BEHAVIOUR_DO_NOTHING) return; config = make_default_setup (mgr); if (config) { /* We don't save the configuration (the "false" parameter to the following function) because we don't want to * install a user-side setting when *here* we are using a system-default setting. */ apply_configuration (mgr, config, timestamp, FALSE); g_object_unref (config); } } static gboolean apply_stored_configuration_at_startup (CsdXrandrManager *manager, guint32 timestamp) { GError *my_error; gboolean success; char *backup_filename; char *intended_filename; GnomePnpIds *pnp_ids; /* This avoids the GnomePnpIds object being created multiple times. * See c9240e8b69c5833074508b46bc56307aac12ec19 */ pnp_ids = gnome_pnp_ids_new (); backup_filename = gnome_rr_config_get_backup_filename (); intended_filename = gnome_rr_config_get_intended_filename (); /* 1. See if there was a "saved" configuration. If there is one, it means * that the user had selected to change the display configuration, but the * machine crashed. In that case, we'll apply *that* configuration and save it on top of the * "intended" one. */ my_error = NULL; success = apply_configuration_from_filename (manager, backup_filename, FALSE, timestamp, &my_error); if (success) { /* The backup configuration existed, and could be applied * successfully, so we must restore it on top of the * failed/intended one. */ restore_backup_configuration (manager, backup_filename, intended_filename, timestamp); goto out; } if (!g_error_matches (my_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { /* Epic fail: there (probably) was a backup configuration, but * we could not apply it. The only thing we can do is delete * the backup configuration. Let's hope that the user doesn't * get left with an unusable display... */ unlink (backup_filename); goto out; } /* 2. There was no backup configuration! This means we are * good. Apply the intended configuration instead. */ success = apply_intended_configuration (manager, intended_filename, timestamp); out: g_object_unref (pnp_ids); if (my_error) g_error_free (my_error); g_free (backup_filename); g_free (intended_filename); return success; } static gboolean apply_default_configuration_from_file (CsdXrandrManager *manager, guint32 timestamp) { CsdXrandrManagerPrivate *priv = manager->priv; char *default_config_filename; gboolean result; default_config_filename = g_settings_get_string (priv->settings, CONF_KEY_DEFAULT_CONFIGURATION_FILE); if (!default_config_filename) return FALSE; result = apply_configuration_from_filename (manager, default_config_filename, TRUE, timestamp, NULL); g_free (default_config_filename); return result; } static void turn_off_laptop_display (CsdXrandrManager *manager, guint32 timestamp) { CsdXrandrManagerPrivate *priv = manager->priv; GnomeRRConfig *config; config = gnome_rr_config_new_current (priv->rw_screen, NULL); turn_off_laptop_display_in_configuration (priv->rw_screen, config); /* We don't turn the laptop's display off if it is the only display present. */ if (!config_is_all_off (config)) { /* We don't save the configuration (the "false" parameter to the following function) because we * wouldn't want to restore a configuration with the laptop's display turned off, if at some * point later the user booted his laptop with the lid open. */ apply_configuration (manager, config, timestamp, FALSE); } g_object_unref (config); } static void #if UP_CHECK_VERSION(0,99,0) lid_state_changed_cb (UpClient *client, GParamSpec *pspec, gpointer data) #else power_client_changed_cb (UpClient *client, gpointer data) #endif { CsdXrandrManager *manager = data; CsdXrandrManagerPrivate *priv = manager->priv; gboolean is_closed; is_closed = up_client_get_lid_is_closed (priv->upower_client); if (is_closed != priv->laptop_lid_is_closed) { priv->laptop_lid_is_closed = is_closed; if (!follow_laptop_lid (manager)) return; /* Refresh the RANDR state. The lid just got opened/closed, so we can afford to * probe the outputs right now. It will also help the case where we can't detect * hotplug/unplug, but the fact that the lid's state changed lets us know that the * user probably did something interesting. */ gnome_rr_screen_refresh (priv->rw_screen, NULL); /* NULL-GError */ if (is_closed) turn_off_laptop_display (manager, GDK_CURRENT_TIME); /* sucks not to have a timestamp for the notification */ /* Use stored configuration or auto-configure outputs all the * time. Don't switch between 2 possibilities; notebook can be * woken up with lid closed and then no output is activated. */ use_stored_configuration_or_auto_configure_outputs (manager, GDK_CURRENT_TIME); } } gboolean csd_xrandr_manager_start (CsdXrandrManager *manager, GError **error) { g_debug ("Starting xrandr manager"); cinnamon_settings_profile_start (NULL); log_open (); log_msg ("------------------------------------------------------------\nSTARTING XRANDR PLUGIN\n"); manager->priv->rw_screen = gnome_rr_screen_new (gdk_screen_get_default (), error); if (manager->priv->rw_screen == NULL) { log_msg ("Could not initialize the RANDR plugin%s%s\n", (error && *error) ? ": " : "", (error && *error) ? (*error)->message : ""); log_close (); return FALSE; } g_signal_connect (manager->priv->rw_screen, "changed", G_CALLBACK (on_randr_event), manager); manager->priv->upower_client = up_client_new (); manager->priv->laptop_lid_is_closed = up_client_get_lid_is_closed (manager->priv->upower_client); #if UP_CHECK_VERSION(0,99,0) g_signal_connect (manager->priv->upower_client, "notify::lid-is-closed", G_CALLBACK (lid_state_changed_cb), manager); #else g_signal_connect (manager->priv->upower_client, "changed", G_CALLBACK (power_client_changed_cb), manager); #endif log_msg ("State of screen at startup:\n"); log_screen (manager->priv->rw_screen); manager->priv->running = TRUE; manager->priv->settings = g_settings_new (CONF_SCHEMA); show_timestamps_dialog (manager, "Startup"); if (!apply_stored_configuration_at_startup (manager, GDK_CURRENT_TIME)) /* we don't have a real timestamp at startup anyway */ if (!apply_default_configuration_from_file (manager, GDK_CURRENT_TIME)) apply_default_boot_configuration (manager, GDK_CURRENT_TIME); log_msg ("State of screen after initial configuration:\n"); log_screen (manager->priv->rw_screen); log_close (); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_xrandr_manager_stop (CsdXrandrManager *manager) { g_debug ("Stopping xrandr manager"); manager->priv->running = FALSE; 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->settings != NULL) { g_object_unref (manager->priv->settings); manager->priv->settings = NULL; } if (manager->priv->rw_screen != NULL) { g_object_unref (manager->priv->rw_screen); manager->priv->rw_screen = NULL; } if (manager->priv->upower_client != NULL) { g_signal_handlers_disconnect_by_data (manager->priv->upower_client, manager); g_object_unref (manager->priv->upower_client); manager->priv->upower_client = NULL; } if (manager->priv->introspection_data) { g_dbus_node_info_unref (manager->priv->introspection_data); manager->priv->introspection_data = NULL; } if (manager->priv->connection != NULL) { g_object_unref (manager->priv->connection); manager->priv->connection = NULL; } #ifdef HAVE_WACOM if (manager->priv->wacom_db != NULL) { libwacom_database_destroy (manager->priv->wacom_db); manager->priv->wacom_db = NULL; } #endif log_open (); log_msg ("STOPPING XRANDR PLUGIN\n------------------------------------------------------------\n"); log_close (); } static GObject * csd_xrandr_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdXrandrManager *xrandr_manager; xrandr_manager = CSD_XRANDR_MANAGER (G_OBJECT_CLASS (csd_xrandr_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (xrandr_manager); } static void csd_xrandr_manager_class_init (CsdXrandrManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_xrandr_manager_constructor; object_class->finalize = csd_xrandr_manager_finalize; g_type_class_add_private (klass, sizeof (CsdXrandrManagerPrivate)); } static void csd_xrandr_manager_init (CsdXrandrManager *manager) { manager->priv = CSD_XRANDR_MANAGER_GET_PRIVATE (manager); manager->priv->current_fn_f7_config = -1; manager->priv->fn_f7_configs = NULL; } static void csd_xrandr_manager_finalize (GObject *object) { CsdXrandrManager *xrandr_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_XRANDR_MANAGER (object)); xrandr_manager = CSD_XRANDR_MANAGER (object); g_return_if_fail (xrandr_manager->priv != NULL); G_OBJECT_CLASS (csd_xrandr_manager_parent_class)->finalize (object); } static void handle_method_call_xrandr_2 (CsdXrandrManager *manager, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation) { gint64 timestamp; GError *error = NULL; g_debug ("Calling method '%s' for org.cinnamon.SettingsDaemon.XRANDR_2", method_name); if (g_strcmp0 (method_name, "ApplyConfiguration") == 0) { gint64 parent_window_id; g_variant_get (parameters, "(xx)", &parent_window_id, ×tamp); if (csd_xrandr_manager_2_apply_configuration (manager, parent_window_id, timestamp, &error) == FALSE) { g_dbus_method_invocation_return_gerror (invocation, error); } else { g_dbus_method_invocation_return_value (invocation, NULL); } } else if (g_strcmp0 (method_name, "VideoModeSwitch") == 0) { g_variant_get (parameters, "(x)", ×tamp); csd_xrandr_manager_2_video_mode_switch (manager, timestamp, NULL); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "Rotate") == 0) { g_variant_get (parameters, "(x)", ×tamp); csd_xrandr_manager_2_rotate (manager, timestamp, NULL); g_dbus_method_invocation_return_value (invocation, NULL); } else if (g_strcmp0 (method_name, "RotateTo") == 0) { GnomeRRRotation rotation; g_variant_get (parameters, "(ix)", &rotation, ×tamp); csd_xrandr_manager_2_rotate_to (manager, rotation, timestamp, NULL); g_dbus_method_invocation_return_value (invocation, NULL); } } 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) { CsdXrandrManager *manager = (CsdXrandrManager *) user_data; g_debug ("Handling method call %s.%s", interface_name, method_name); if (g_strcmp0 (interface_name, "org.cinnamon.SettingsDaemon.XRANDR_2") == 0) handle_method_call_xrandr_2 (manager, method_name, parameters, invocation); else g_warning ("unknown interface: %s", interface_name); } static const GDBusInterfaceVTable interface_vtable = { handle_method_call, NULL, /* Get Property */ NULL, /* Set Property */ }; static void on_bus_gotten (GObject *source_object, GAsyncResult *res, CsdXrandrManager *manager) { GDBusConnection *connection; GError *error = NULL; GDBusInterfaceInfo **infos; int i; 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; for (i = 0; infos[i] != NULL; i++) { g_dbus_connection_register_object (connection, CSD_XRANDR_DBUS_PATH, infos[i], &interface_vtable, manager, NULL, NULL); } } static void register_manager_dbus (CsdXrandrManager *manager) { manager->priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); manager->priv->bus_cancellable = g_cancellable_new (); g_assert (manager->priv->introspection_data != NULL); g_bus_get (G_BUS_TYPE_SESSION, manager->priv->bus_cancellable, (GAsyncReadyCallback) on_bus_gotten, manager); } CsdXrandrManager * csd_xrandr_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_XRANDR_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); register_manager_dbus (manager_object); } return CSD_XRANDR_MANAGER (manager_object); } cinnamon-settings-daemon-2.8.3/plugins/common/0000775000175000017500000000000012625665665020345 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/common/test-egg-key-parsing.c0000664000175000017500000000110512625665665024454 0ustar fabiofabio#include #define KEY "XF86AudioMute" int main (int argc, char **argv) { guint gdk_accel_key; guint *gdk_accel_codes; GdkModifierType gdk_mods; gtk_init (&argc, &argv); g_message ("gdk_keyval_from_name ('%s') == %d", KEY, gdk_keyval_from_name(KEY)); gtk_accelerator_parse_with_keycode (KEY, &gdk_accel_key, &gdk_accel_codes, &gdk_mods); g_message ("gtk_accelerator_parse_full ('%s') returned keyval '%d' keycode[0]: '%d' mods: 0x%x", KEY, gdk_accel_key, gdk_accel_codes ? gdk_accel_codes[0] : 0, gdk_mods); g_free (gdk_accel_codes); return 0; } cinnamon-settings-daemon-2.8.3/plugins/common/csd-input-helper.h0000664000175000017500000000634112625665665023705 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 touchpad_is_present (void); gboolean touchscreen_is_present (void); gboolean mouse_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-2.8.3/plugins/common/test-plugin.h0000664000175000017500000000450112625665665022771 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 "test-plugin.h" */ #include "config.h" #include #include #include #include #ifndef SCHEMA_NAME #define SCHEMA_NAME PLUGIN_NAME #endif #ifndef PLUGIN_NAME #error Include PLUGIN_CFLAGS in the test application s CFLAGS #endif /* !PLUGIN_NAME */ static MANAGER *manager = NULL; static gboolean has_settings (void) { const gchar * const * list; guint i; list = g_settings_list_schemas (); for (i = 0; list[i] != NULL; i++) { if (g_str_equal (list[i], "org.cinnamon.settings-daemon.plugins." SCHEMA_NAME)) return TRUE; } return FALSE; } int main (int argc, char **argv) { GError *error; GSettings *settings; bindtextdomain (GETTEXT_PACKAGE, CINNAMON_SETTINGS_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); notify_init ("cinnamon-settings-daemon"); g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); error = NULL; if (! gtk_init_with_args (&argc, &argv, NULL, NULL, NULL, &error)) { fprintf (stderr, "%s\n", error->message); g_error_free (error); exit (1); } if (has_settings () == FALSE) { fprintf (stderr, "The schemas for plugin '%s' aren't available, check your installation.\n", SCHEMA_NAME); exit (1); } settings = g_settings_new ("org.cinnamon.settings-daemon.plugins." SCHEMA_NAME); if (g_settings_get_boolean (settings, "active") != FALSE) { fprintf (stderr, "Plugin '%s' is not disabled. You need to disable it before launching the test application.\n", SCHEMA_NAME); fprintf (stderr, "To deactivate:\n"); fprintf (stderr, "\tgsettings set org.cinnamon.settings-daemon.plugins." SCHEMA_NAME " active false\n"); fprintf (stderr, "To reactivate:\n"); fprintf (stderr, "\tgsettings set org.cinnamon.settings-daemon.plugins." SCHEMA_NAME " active true\n"); exit (1); } manager = NEW (); error = NULL; START (manager, &error); gtk_main (); STOP (manager); g_object_unref (manager); return 0; } cinnamon-settings-daemon-2.8.3/plugins/common/csd-power-helper.c0000664000175000017500000001443712625665665023702 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 "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" 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 void logind_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, "Suspend", 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 upower_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 UPower: %s", error->message); g_error_free (error); } else { g_variant_unref (result); } } static void upower_suspend (GDBusProxy *upower_proxy) { g_dbus_proxy_call (upower_proxy, "Suspend", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, upower_sleep_cb, NULL); } static void upower_hibernate (GDBusProxy *upower_proxy) { g_dbus_proxy_call (upower_proxy, "Hibernate", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, upower_sleep_cb, NULL); } void csd_power_suspend (gboolean use_logind, GDBusProxy *upower_proxy) { if (use_logind) { logind_suspend (); } else { upower_suspend (upower_proxy); } } void csd_power_poweroff (gboolean use_logind) { if (use_logind) { logind_stop (); } else { consolekit_stop (); } } void csd_power_hibernate (gboolean use_logind, GDBusProxy *upower_proxy) { if (use_logind) { logind_hibernate (); } else { upower_hibernate (upower_proxy); } } cinnamon-settings-daemon-2.8.3/plugins/common/csd-keygrab.h0000664000175000017500000000373412625665665022720 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-2.8.3/plugins/common/csd-keygrab.c0000664000175000017500000003237312625665665022714 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_error_trap_push (); * * grab_key_unsafe (key, grab, screens); * * gdk_flush (); * if (gdk_error_trap_pop ()) * 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_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-2.8.3/plugins/common/test-input-helper.c0000664000175000017500000000677212625665665024116 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; guint 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_error_trap_push (); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_error_trap_pop () || (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-2.8.3/plugins/common/csd-input-helper.c0000664000175000017500000003732212625665665023703 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 "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, 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_error_trap_push (); 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 != property->type || realformat != property->format || nitems < property->nitems) { gdk_error_trap_pop_ignored (); 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; } } XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, realtype, realformat, PropModeReplace, data, nitems); XFree (data); if (gdk_error_trap_pop ()) { 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_error_trap_push (); major = 2; #ifdef XI_23 minor = 3; #else minor = 0; #endif if (XIQueryVersion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &major, &minor) != Success) { gdk_error_trap_pop_ignored (); #ifndef XI_23 /* try for 2.2, maybe gtk has already announced 2.2 support */ gdk_error_trap_push (); major = 2; minor = 2; if (XIQueryVersion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &major, &minor) != Success) { gdk_error_trap_pop_ignored (); return FALSE; } #else return FALSE; #endif } gdk_error_trap_pop_ignored (); 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; /* we don't check on the type being XI_TOUCHPAD here, * but having a "Synaptics Off" property should be enough */ prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Off", False); if (!prop) return FALSE; gdk_error_trap_push (); 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_error_trap_pop_ignored (); XFree (data); return TRUE; } gdk_error_trap_pop_ignored (); 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)); } static gboolean device_type_is_present (InfoIdentifyFunc info_func, DeviceIdentifyFunc device_func) { XDeviceInfo *device_info; gint n_devices; guint 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_error_trap_push (); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_error_trap_pop () || (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); } 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_error_trap_push (); 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_error_trap_pop_ignored (); return NULL; } if (gdk_error_trap_pop ()) 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_error_trap_push (); 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_error_trap_pop_ignored (); goto out; } if (gdk_error_trap_pop ()) 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_error_trap_push (); value = enabled ? 1 : 0; XIChangeProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_id, prop, XA_INTEGER, 8, PropModeReplace, &value, 1); if (gdk_error_trap_pop ()) 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] = "-t"; argv[2] = (char *) custom_command_to_string (command); argv[3] = "-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; guint 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_error_trap_push (); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice); gdk_error_trap_pop_ignored(); } cinnamon-settings-daemon-2.8.3/plugins/common/csd-power-helper.h0000664000175000017500000000230312625665665023674 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 #include void csd_power_suspend (gboolean use_logind, GDBusProxy *upower_proxy); void csd_power_hibernate (gboolean use_logind, GDBusProxy *upower_proxy); void csd_power_poweroff (gboolean use_logind); G_END_DECLS #endif /* __CSD_POWER_HELPER_H */ cinnamon-settings-daemon-2.8.3/plugins/common/Makefile.am0000664000175000017500000000200012625665665022371 0ustar fabiofabioplugin_name = common noinst_LTLIBRARIES = libcommon.la libcommon_la_SOURCES = \ csd-keygrab.c \ csd-keygrab.h \ csd-input-helper.c \ csd-input-helper.h \ csd-power-helper.c \ csd-power-helper.h libcommon_la_CPPFLAGS = \ $(AM_CPPFLAGS) libcommon_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(COMMON_CFLAGS) \ $(AM_CFLAGS) libcommon_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) libcommon_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(COMMON_LIBS) libexec_PROGRAMS = csd-test-input-helper csd_test_input_helper_SOURCES = test-input-helper.c csd_test_input_helper_LDADD = libcommon.la csd_test_input_helper_CFLAGS = $(libcommon_la_CFLAGS) noinst_PROGRAMS = test-egg-key-parsing test_egg_key_parsing_SOURCES = test-egg-key-parsing.c test_egg_key_parsing_LDADD = libcommon.la $(COMMON_LIBS) test_egg_key_parsing_CFLAGS = $(libcommon_la_CFLAGS) scriptsdir = $(datadir)/cinnamon-settings-daemon-@CSD_API_VERSION@ scripts_DATA = input-device-example.sh EXTRA_DIST = $(scripts_DATA) test-plugin.h cinnamon-settings-daemon-2.8.3/plugins/common/input-device-example.sh0000664000175000017500000000301412625665665024724 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-2.8.3/plugins/mouse/0000775000175000017500000000000012625665665020205 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/mouse/csd-locate-pointer.h0000664000175000017500000000153312625665665024054 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-2.8.3/plugins/mouse/mouse.cinnamon-settings-plugin.in0000664000175000017500000000020412625665665026614 0ustar fabiofabio[Cinnamon Settings Plugin] Module=mouse IAge=0 _Name=Mouse _Description=Mouse plugin Authors= Copyright=Copyright © 2007 Website= cinnamon-settings-daemon-2.8.3/plugins/mouse/csd-timeline.c0000664000175000017500000004741112625665665022735 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 neccesary */ 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-2.8.3/plugins/mouse/csd-locate-pointer.c0000664000175000017500000003572312625665665024057 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; 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); gdk_window_get_pointer (gdk_screen_get_root_window (screen), &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) { cairo_region_t *region; gint cursor_x, cursor_y; gdk_window_get_pointer (gdk_screen_get_root_window (screen), &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; int n_screens; int n_keys; gboolean has_entries; static const guint keyvals[] = { GDK_KEY_Control_L, GDK_KEY_Control_R }; unsigned j; display = gdk_display_get_default (); n_screens = gdk_display_get_n_screens (display); 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) { gint i, j; for (i = 0; i < n_keys; i++) { for (j = 0; j < n_screens; j++) { GdkScreen *screen; Window xroot; screen = gdk_display_get_screen (display, j); xroot = gdk_x11_window_get_xid (gdk_screen_get_root_window (screen)); 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); for (i = 0; i < n_screens; i++) { GdkScreen *screen; screen = gdk_display_get_screen (display, i); 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-2.8.3/plugins/mouse/test-mouse.c0000664000175000017500000000030512625665665022454 0ustar fabiofabio#define NEW csd_mouse_manager_new #define START csd_mouse_manager_start #define STOP csd_mouse_manager_stop #define MANAGER CsdMouseManager #include "csd-mouse-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/mouse/csd-mouse-manager.c0000664000175000017500000015114012625665665023662 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" /* Keys for both touchpad and mouse */ #define KEY_LEFT_HANDED "left-handed" /* a boolean for mouse, an enum for touchpad */ #define KEY_MOTION_ACCELERATION "motion-acceleration" #define KEY_MOTION_THRESHOLD "motion-threshold" /* Touchpad settings */ #define KEY_TOUCHPAD_DISABLE_W_TYPING "disable-while-typing" #define KEY_PAD_HORIZ_SCROLL "horiz-scroll-enabled" #define KEY_SCROLL_METHOD "scroll-method" #define KEY_TAP_TO_CLICK "tap-to-click" #define KEY_TWO_FINGER_CLICK "two-finger-click" #define KEY_THREE_FINGER_CLICK "three-finger-click" #define KEY_TOUCHPAD_ENABLED "touchpad-enabled" #define KEY_NATURAL_SCROLL_ENABLED "natural-scroll" /* 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" struct CsdMouseManagerPrivate { guint start_idle_id; GSettings *touchpad_settings; GSettings *mouse_settings; GSettings *mouse_a11y_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_class_init (CsdMouseManagerClass *klass); static void csd_mouse_manager_init (CsdMouseManager *mouse_manager); 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 enable_two_finger_click, gint enable_three_finger_click); 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 GObject * csd_mouse_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdMouseManager *mouse_manager; mouse_manager = CSD_MOUSE_MANAGER (G_OBJECT_CLASS (csd_mouse_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (mouse_manager); } static void csd_mouse_manager_dispose (GObject *object) { G_OBJECT_CLASS (csd_mouse_manager_parent_class)->dispose (object); } static void csd_mouse_manager_class_init (CsdMouseManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_mouse_manager_constructor; object_class->dispose = csd_mouse_manager_dispose; 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_error_trap_push (); xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id); if (gdk_error_trap_pop () != 0) return NULL; return xdevice; } 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 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 = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Capabilities", False); if (!prop) return FALSE; gdk_error_trap_push (); 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_error_trap_pop_ignored (); return is_single_button; } static void set_left_handed (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; } 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); gdk_error_trap_push (); XSetDeviceButtonMapping (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, buttons, n_buttons); gdk_error_trap_pop_ignored (); out: xdevice_close (xdevice); g_free (buttons); } static void set_motion (CsdMouseManager *manager, GdkDevice *device) { XDevice *xdevice; XPtrFeedbackControl feedback; XFeedbackState *states, *state; int num_feedbacks; int numerator, denominator; gfloat motion_acceleration; int motion_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); 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; } /* And threshold */ motion_threshold = g_settings_get_int (settings, KEY_MOTION_THRESHOLD); /* 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); } XFreeFeedbackList (states); out: xdevice_close (xdevice); } static void set_middle_button (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 = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Evdev Middle Button Emulation", True); 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_error_trap_push (); 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_error_trap_pop ()) g_warning ("Error in setting middle button emulation on \"%s\"", gdk_device_get_name (device)); if (rc == Success) XFree (data); xdevice_close (xdevice); } /* 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 (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 void set_tap_to_click (GdkDevice *device, gboolean state, gboolean left_handed) { int format, rc; unsigned long nitems, bytes_after; XDevice *xdevice; unsigned char* data; Atom prop, type; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Tap Action", False); 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_error_trap_push (); 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_error_trap_pop ()) g_warning ("Error in setting tap to click on \"%s\"", gdk_device_get_name (device)); xdevice_close (xdevice); } static void set_click_actions (GdkDevice *device, gint enable_two_finger_click, gint enable_three_finger_click) { int format, rc; unsigned long nitems, bytes_after; XDevice *xdevice; unsigned char* data; Atom prop, type; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Click Action", False); 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_error_trap_push (); 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 >= 3) { data[0] = 1; data[1] = enable_two_finger_click; data[2] = enable_three_finger_click; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (rc == Success) XFree (data); if (gdk_error_trap_pop ()) g_warning ("Error in setting click actions on \"%s\"", gdk_device_get_name (device)); xdevice_close (xdevice); } static void set_horiz_scroll (GdkDevice *device, gboolean state) { int rc; XDevice *xdevice; Atom act_type, prop_edge, prop_twofinger; int act_format; unsigned long nitems, bytes_after; unsigned char *data; prop_edge = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Edge Scrolling", False); prop_twofinger = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Two-Finger Scrolling", False); if (!prop_edge || !prop_twofinger) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("setting horiz scroll on %s", gdk_device_get_name (device)); gdk_error_trap_push (); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_edge, 0, 1, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success && act_type == XA_INTEGER && act_format == 8 && nitems >= 2) { data[1] = (state && data[0]); XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_edge, XA_INTEGER, 8, PropModeReplace, data, nitems); } XFree (data); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_twofinger, 0, 1, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success && act_type == XA_INTEGER && act_format == 8 && nitems >= 2) { data[1] = (state && data[0]); XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_twofinger, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (gdk_error_trap_pop ()) g_warning ("Error in setting horiz scroll on \"%s\"", gdk_device_get_name (device)); if (rc == Success) XFree (data); xdevice_close (xdevice); } static void set_edge_scroll (GdkDevice *device, CsdTouchpadScrollMethod method) { int rc; XDevice *xdevice; Atom act_type, prop_edge, prop_twofinger; int act_format; unsigned long nitems, bytes_after; unsigned char *data; prop_edge = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Edge Scrolling", False); prop_twofinger = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Two-Finger Scrolling", False); if (!prop_edge || !prop_twofinger) return; xdevice = open_gdk_device (device); if (xdevice == NULL) return; if (!device_is_touchpad (xdevice)) { xdevice_close (xdevice); return; } g_debug ("setting edge scroll on %s", gdk_device_get_name (device)); gdk_error_trap_push (); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_edge, 0, 1, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success && act_type == XA_INTEGER && act_format == 8 && nitems >= 2) { data[0] = (method == CSD_TOUCHPAD_SCROLL_METHOD_EDGE_SCROLLING) ? 1 : 0; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_edge, XA_INTEGER, 8, PropModeReplace, data, nitems); } XFree (data); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_twofinger, 0, 1, False, XA_INTEGER, &act_type, &act_format, &nitems, &bytes_after, &data); if (rc == Success && act_type == XA_INTEGER && act_format == 8 && nitems >= 2) { data[0] = (method == CSD_TOUCHPAD_SCROLL_METHOD_TWO_FINGER_SCROLLING) ? 1 : 0; XChangeDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, prop_twofinger, XA_INTEGER, 8, PropModeReplace, data, nitems); } if (gdk_error_trap_pop ()) g_warning ("Error in setting edge scroll on \"%s\"", gdk_device_get_name (device)); if (rc == Success) XFree (data); xdevice_close (xdevice); } 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_error_trap_push (); xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id); if (gdk_error_trap_pop () != 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) { GtkWidget *dialog; 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); } dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("Could not enable mouse accessibility features")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("Mouse accessibility requires Mousetweaks " "to be installed on your system.")); gtk_window_set_title (GTK_WINDOW (dialog), _("Universal Access")); gtk_window_set_icon_name (GTK_WINDOW (dialog), "preferences-desktop-accessibility"); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } 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_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_TWO_FINGER_CLICK), g_settings_get_int (manager->priv->touchpad_settings, KEY_THREE_FINGER_CLICK)); set_edge_scroll (device, g_settings_get_enum (manager->priv->touchpad_settings, KEY_SCROLL_METHOD)); set_horiz_scroll (device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_PAD_HORIZ_SCROLL)); set_natural_scroll (manager, device, g_settings_get_boolean (manager->priv->touchpad_settings, KEY_NATURAL_SCROLL_ENABLED)); if (g_settings_get_boolean (manager->priv->touchpad_settings, KEY_TOUCHPAD_ENABLED) == FALSE) set_touchpad_disabled (device); } static void set_natural_scroll (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 = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Synaptics Scrolling Distance", False); gdk_error_trap_push (); 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_error_trap_pop ()) 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 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 (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_MOTION_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)); } } g_list_free (devices); } 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; } 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 (g_str_equal (key, KEY_TAP_TO_CLICK)) { set_tap_to_click (device, g_settings_get_boolean (settings, key), g_settings_get_boolean (manager->priv->touchpad_settings, KEY_LEFT_HANDED)); } else if (g_str_equal (key, KEY_TWO_FINGER_CLICK) || g_str_equal (key, KEY_THREE_FINGER_CLICK)) { set_click_actions( device, g_settings_get_int (manager->priv->touchpad_settings, KEY_TWO_FINGER_CLICK), g_settings_get_int (manager->priv->touchpad_settings, KEY_THREE_FINGER_CLICK)); } else if (g_str_equal (key, KEY_SCROLL_METHOD)) { set_edge_scroll (device, g_settings_get_enum (settings, key)); set_horiz_scroll (device, g_settings_get_boolean (settings, KEY_PAD_HORIZ_SCROLL)); } else if (g_str_equal (key, KEY_PAD_HORIZ_SCROLL)) { set_horiz_scroll (device, g_settings_get_boolean (settings, key)); } 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_MOTION_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)); } } 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)); } } 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->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)); 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); 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 (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; } if (p->mouse_a11y_settings != NULL) { g_object_unref (p->mouse_a11y_settings); p->mouse_a11y_settings = NULL; } if (p->mouse_settings != NULL) { g_object_unref (p->mouse_settings); p->mouse_settings = NULL; } if (p->touchpad_settings != NULL) { g_object_unref (p->touchpad_settings); p->touchpad_settings = NULL; } 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); if (mouse_manager->priv->blacklist != NULL) g_hash_table_destroy (mouse_manager->priv->blacklist); if (mouse_manager->priv->start_idle_id != 0) { g_source_remove (mouse_manager->priv->start_idle_id); mouse_manager->priv->start_idle_id = 0; } if (mouse_manager->priv->device_manager != NULL) { g_signal_handler_disconnect (mouse_manager->priv->device_manager, mouse_manager->priv->device_added_id); g_signal_handler_disconnect (mouse_manager->priv->device_manager, mouse_manager->priv->device_removed_id); } if (mouse_manager->priv->mouse_settings != NULL) g_object_unref (mouse_manager->priv->mouse_settings); if (mouse_manager->priv->mouse_a11y_settings != NULL) g_object_unref (mouse_manager->priv->mouse_a11y_settings); if (mouse_manager->priv->touchpad_settings != NULL) g_object_unref (mouse_manager->priv->touchpad_settings); 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-2.8.3/plugins/mouse/csd-mouse-plugin.h0000664000175000017500000000421312625665665023551 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. * */ #ifndef __CSD_MOUSE_PLUGIN_H__ #define __CSD_MOUSE_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_MOUSE_PLUGIN (csd_mouse_plugin_get_type ()) #define CSD_MOUSE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_MOUSE_PLUGIN, CsdMousePlugin)) #define CSD_MOUSE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_MOUSE_PLUGIN, CsdMousePluginClass)) #define CSD_IS_MOUSE_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_MOUSE_PLUGIN)) #define CSD_IS_MOUSE_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_MOUSE_PLUGIN)) #define CSD_MOUSE_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_MOUSE_PLUGIN, CsdMousePluginClass)) typedef struct CsdMousePluginPrivate CsdMousePluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdMousePluginPrivate *priv; } CsdMousePlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdMousePluginClass; GType csd_mouse_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_MOUSE_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/mouse/csd-mouse-manager.h0000664000175000017500000000437312625665665023674 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-2.8.3/plugins/mouse/csd-timeline.h0000664000175000017500000001210512625665665022732 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-2.8.3/plugins/mouse/Makefile.am0000664000175000017500000000373412625665665022250 0ustar fabiofabioplugin_name = mouse plugin_LTLIBRARIES = libmouse.la libmouse_la_SOURCES = \ csd-mouse-plugin.h \ csd-mouse-plugin.c \ csd-mouse-manager.h \ csd-mouse-manager.c libmouse_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common/ \ -I$(top_srcdir)/data/ \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) libmouse_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(MOUSE_CFLAGS) \ $(AM_CFLAGS) libmouse_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) libmouse_la_LIBADD = \ $(MOUSE_LIBS) \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_PLUGIN_LIBS) plugin_in_files = mouse.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) libexec_PROGRAMS = csd-locate-pointer csd_locate_pointer_SOURCES = \ csd-locate-pointer.h \ csd-locate-pointer.c \ csd-timeline.h \ csd-timeline.c csd_locate_pointer_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(MOUSE_CFLAGS) \ $(AM_CFLAGS) csd_locate_pointer_LDADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(MOUSE_LIBS) \ -lm libexec_PROGRAMS += csd-test-mouse csd_test_mouse_SOURCES = \ test-mouse.c \ csd-mouse-manager.c \ csd-mouse-manager.h csd_test_mouse_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) csd_test_mouse_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(MOUSE_CFLAGS) \ $(AM_CFLAGS) csd_test_mouse_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(MOUSE_LIBS) \ -lm EXTRA_DIST = $(plugin_in_files) CLEANFILES = $(plugin_DATA) DISTCLEANFILES = $(plugin_DATA) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/mouse/csd-mouse-plugin.c0000664000175000017500000000607412625665665023553 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 "cinnamon-settings-plugin.h" #include "csd-mouse-plugin.h" #include "csd-mouse-manager.h" struct CsdMousePluginPrivate { CsdMouseManager *manager; }; #define CSD_MOUSE_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_MOUSE_PLUGIN, CsdMousePluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdMousePlugin, csd_mouse_plugin) static void csd_mouse_plugin_init (CsdMousePlugin *plugin) { plugin->priv = CSD_MOUSE_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdMousePlugin initializing"); plugin->priv->manager = csd_mouse_manager_new (); } static void csd_mouse_plugin_finalize (GObject *object) { CsdMousePlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_MOUSE_PLUGIN (object)); g_debug ("CsdMousePlugin finalizing"); plugin = CSD_MOUSE_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_mouse_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating mouse plugin"); error = NULL; res = csd_mouse_manager_start (CSD_MOUSE_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start mouse manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating mouse plugin"); csd_mouse_manager_stop (CSD_MOUSE_PLUGIN (plugin)->priv->manager); } static void csd_mouse_plugin_class_init (CsdMousePluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_mouse_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdMousePluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/power/0000775000175000017500000000000012625665665020211 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/power/gpm-idletime.h0000664000175000017500000000544012625665665022742 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GPM_IDLETIME_H #define __GPM_IDLETIME_H #include G_BEGIN_DECLS #define GPM_IDLETIME_TYPE (gpm_idletime_get_type ()) #define GPM_IDLETIME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPM_IDLETIME_TYPE, GpmIdletime)) #define GPM_IDLETIME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPM_IDLETIME_TYPE, GpmIdletimeClass)) #define GPM_IS_IDLETIME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPM_IDLETIME_TYPE)) #define GPM_IS_IDLETIME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPM_IDLETIME_TYPE)) #define GPM_IDLETIME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPM_IDLETIME_TYPE, GpmIdletimeClass)) typedef struct GpmIdletimePrivate GpmIdletimePrivate; typedef struct { GObject parent; GpmIdletimePrivate *priv; } GpmIdletime; typedef struct { GObjectClass parent_class; void (* alarm_expired) (GpmIdletime *idletime, guint timer_id); void (* reset) (GpmIdletime *idletime); } GpmIdletimeClass; GType gpm_idletime_get_type (void); GpmIdletime *gpm_idletime_new (void); void gpm_idletime_alarm_reset_all (GpmIdletime *idletime); gboolean gpm_idletime_alarm_set (GpmIdletime *idletime, guint alarm_id, guint timeout); gboolean gpm_idletime_alarm_remove (GpmIdletime *idletime, guint alarm_id); gint64 gpm_idletime_get_time (GpmIdletime *idletime); G_END_DECLS #endif /* __GPM_IDLETIME_H */ cinnamon-settings-daemon-2.8.3/plugins/power/gpm-phone.h0000664000175000017500000000627312625665665022264 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GPMPHONE_H #define __GPMPHONE_H #include G_BEGIN_DECLS #define GPM_TYPE_PHONE (gpm_phone_get_type ()) #define GPM_PHONE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPM_TYPE_PHONE, GpmPhone)) #define GPM_PHONE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPM_TYPE_PHONE, GpmPhoneClass)) #define GPM_IS_PHONE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPM_TYPE_PHONE)) #define GPM_IS_PHONE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPM_TYPE_PHONE)) #define GPM_PHONE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPM_TYPE_PHONE, GpmPhoneClass)) #define CINNAMON_PHONE_MANAGER_DBUS_SERVICE "org.cinnamon.phone" #define CINNAMON_PHONE_MANAGER_DBUS_PATH "/org/cinnamon/phone/Manager" #define CINNAMON_PHONE_MANAGER_DBUS_INTERFACE "org.cinnamon.phone.Manager" typedef struct GpmPhonePrivate GpmPhonePrivate; typedef struct { GObject parent; GpmPhonePrivate *priv; } GpmPhone; typedef struct { GObjectClass parent_class; void (* device_added) (GpmPhone *phone, guint idx); void (* device_removed) (GpmPhone *phone, guint idx); void (* device_refresh) (GpmPhone *phone, guint idx); } GpmPhoneClass; GType gpm_phone_get_type (void); GpmPhone *gpm_phone_new (void); gboolean gpm_phone_get_present (GpmPhone *phone, guint idx); guint gpm_phone_get_percentage (GpmPhone *phone, guint idx); gboolean gpm_phone_get_on_ac (GpmPhone *phone, guint idx); guint gpm_phone_get_num_batteries (GpmPhone *phone); gboolean gpm_phone_coldplug (GpmPhone *phone); G_END_DECLS #endif /* __GPMPHONE_H */ cinnamon-settings-daemon-2.8.3/plugins/power/csd-power-plugin.c0000664000175000017500000000607412625665665023563 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 "cinnamon-settings-plugin.h" #include "csd-power-plugin.h" #include "csd-power-manager.h" struct CsdPowerPluginPrivate { CsdPowerManager *manager; }; #define CSD_POWER_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_POWER_PLUGIN, CsdPowerPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdPowerPlugin, csd_power_plugin) static void csd_power_plugin_init (CsdPowerPlugin *plugin) { plugin->priv = CSD_POWER_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdPowerPlugin initializing"); plugin->priv->manager = csd_power_manager_new (); } static void csd_power_plugin_finalize (GObject *object) { CsdPowerPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_POWER_PLUGIN (object)); g_debug ("CsdPowerPlugin finalizing"); plugin = CSD_POWER_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_power_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating power plugin"); error = NULL; res = csd_power_manager_start (CSD_POWER_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start power manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating power plugin"); csd_power_manager_stop (CSD_POWER_PLUGIN (plugin)->priv->manager); } static void csd_power_plugin_class_init (CsdPowerPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_power_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdPowerPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/power/csd-power-manager.h0000664000175000017500000000467512625665665023711 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_POWER_MANAGER_H #define __CSD_POWER_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_POWER_MANAGER (csd_power_manager_get_type ()) #define CSD_POWER_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_POWER_MANAGER, CsdPowerManager)) #define CSD_POWER_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_POWER_MANAGER, CsdPowerManagerClass)) #define CSD_IS_POWER_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_POWER_MANAGER)) #define CSD_IS_POWER_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_POWER_MANAGER)) #define CSD_POWER_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_POWER_MANAGER, CsdPowerManagerClass)) #define CSD_POWER_MANAGER_ERROR (csd_power_manager_error_quark ()) typedef struct CsdPowerManagerPrivate CsdPowerManagerPrivate; typedef struct { GObject parent; CsdPowerManagerPrivate *priv; } CsdPowerManager; typedef struct { GObjectClass parent_class; } CsdPowerManagerClass; enum { CSD_POWER_MANAGER_ERROR_FAILED }; GType csd_power_manager_get_type (void); GQuark csd_power_manager_error_quark (void); CsdPowerManager * csd_power_manager_new (void); gboolean csd_power_manager_start (CsdPowerManager *manager, GError **error); void csd_power_manager_stop (CsdPowerManager *manager); G_END_DECLS #endif /* __CSD_POWER_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/power/power.cinnamon-settings-plugin.in0000664000175000017500000000024012625665665026624 0ustar fabiofabio[Cinnamon Settings Plugin] Module=power IAge=0 _Name=Power _Description=Power plugin Authors=Richard Hughes Copyright=Copyright © 2011 Richard Hughes Website= cinnamon-settings-daemon-2.8.3/plugins/power/csd-power-plugin.h0000664000175000017500000000421312625665665023561 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. * */ #ifndef __CSD_POWER_PLUGIN_H__ #define __CSD_POWER_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_POWER_PLUGIN (csd_power_plugin_get_type ()) #define CSD_POWER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_POWER_PLUGIN, CsdPowerPlugin)) #define CSD_POWER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_POWER_PLUGIN, CsdPowerPluginClass)) #define CSD_IS_POWER_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_POWER_PLUGIN)) #define CSD_IS_POWER_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_POWER_PLUGIN)) #define CSD_POWER_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_POWER_PLUGIN, CsdPowerPluginClass)) typedef struct CsdPowerPluginPrivate CsdPowerPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdPowerPluginPrivate *priv; } CsdPowerPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdPowerPluginClass; GType csd_power_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_POWER_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/power/gpm-common.c0000664000175000017500000011477412625665665022444 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2005-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include "gpm-common.h" #define GPM_UP_TIME_PRECISION 5*60 #define GPM_UP_TEXT_MIN_TIME 120 /** * Return value: The time string, e.g. "2 hours 3 minutes" **/ gchar * gpm_get_timestring (guint time_secs) { char* timestring = NULL; gint hours; gint minutes; /* Add 0.5 to do rounding */ minutes = (int) ( ( time_secs / 60.0 ) + 0.5 ); if (minutes == 0) { timestring = g_strdup (_("Unknown time")); return timestring; } if (minutes < 60) { timestring = g_strdup_printf (ngettext ("%i minute", "%i minutes", minutes), minutes); return timestring; } hours = minutes / 60; minutes = minutes % 60; if (minutes == 0) timestring = g_strdup_printf (ngettext ( "%i hour", "%i hours", hours), hours); else /* TRANSLATOR: "%i %s %i %s" are "%i hours %i minutes" * Swap order with "%2$s %2$i %1$s %1$i if needed */ timestring = g_strdup_printf (_("%i %s %i %s"), hours, ngettext ("hour", "hours", hours), minutes, ngettext ("minute", "minutes", minutes)); return timestring; } static const gchar * gpm_upower_get_device_icon_index (UpDevice *device) { gdouble percentage; /* get device properties */ g_object_get (device, "percentage", &percentage, NULL); if (percentage < 10) return "000"; else if (percentage < 30) return "020"; else if (percentage < 50) return "040"; else if (percentage < 70) return "060"; else if (percentage < 90) return "080"; return "100"; } static const gchar * gpm_upower_get_device_icon_suffix (UpDevice *device) { gdouble percentage; /* get device properties */ g_object_get (device, "percentage", &percentage, NULL); if (percentage < 10) return "caution"; else if (percentage < 30) return "low"; else if (percentage < 60) return "good"; return "full"; } GIcon * gpm_upower_get_device_icon (UpDevice *device, gboolean use_symbolic) { GString *filename; gchar **iconnames; const gchar *kind_str; const gchar *suffix_str; const gchar *index_str; UpDeviceKind kind; UpDeviceState state; gboolean is_present; gdouble percentage; GIcon *icon = NULL; g_return_val_if_fail (device != NULL, NULL); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "percentage", &percentage, "is-present", &is_present, NULL); /* get correct icon prefix */ filename = g_string_new (NULL); /* get the icon from some simple rules */ if (kind == UP_DEVICE_KIND_LINE_POWER) { if (use_symbolic) g_string_append (filename, "ac-adapter-symbolic;"); g_string_append (filename, "ac-adapter;"); } else if (kind == UP_DEVICE_KIND_MONITOR) { if (use_symbolic) g_string_append (filename, "gpm-monitor-symbolic;"); g_string_append (filename, "gpm-monitor;"); } else { kind_str = up_device_kind_to_string (kind); if (!is_present) { if (use_symbolic) g_string_append (filename, "battery-missing-symbolic;"); g_string_append_printf (filename, "gpm-%s-missing;", kind_str); g_string_append_printf (filename, "gpm-%s-000;", kind_str); g_string_append (filename, "battery-missing;"); } else { switch (state) { case UP_DEVICE_STATE_EMPTY: if (use_symbolic) g_string_append (filename, "battery-empty-symbolic;"); g_string_append_printf (filename, "gpm-%s-empty;", kind_str); g_string_append_printf (filename, "gpm-%s-000;", kind_str); g_string_append (filename, "battery-empty;"); break; case UP_DEVICE_STATE_FULLY_CHARGED: if (use_symbolic) { g_string_append (filename, "battery-full-charged-symbolic;"); g_string_append (filename, "battery-full-charging-symbolic;"); } g_string_append_printf (filename, "gpm-%s-full;", kind_str); g_string_append_printf (filename, "gpm-%s-100;", kind_str); g_string_append (filename, "battery-full-charged;"); g_string_append (filename, "battery-full-charging;"); break; case UP_DEVICE_STATE_CHARGING: case UP_DEVICE_STATE_PENDING_CHARGE: suffix_str = gpm_upower_get_device_icon_suffix (device); index_str = gpm_upower_get_device_icon_index (device); if (use_symbolic) g_string_append_printf (filename, "battery-%s-charging-symbolic;", suffix_str); g_string_append_printf (filename, "gpm-%s-%s-charging;", kind_str, index_str); g_string_append_printf (filename, "battery-%s-charging;", suffix_str); break; case UP_DEVICE_STATE_DISCHARGING: case UP_DEVICE_STATE_PENDING_DISCHARGE: suffix_str = gpm_upower_get_device_icon_suffix (device); index_str = gpm_upower_get_device_icon_index (device); if (use_symbolic) g_string_append_printf (filename, "battery-%s-symbolic;", suffix_str); g_string_append_printf (filename, "gpm-%s-%s;", kind_str, index_str); g_string_append_printf (filename, "battery-%s;", suffix_str); break; default: if (use_symbolic) g_string_append (filename, "battery-missing-symbolic;"); g_string_append (filename, "gpm-battery-missing;"); g_string_append (filename, "battery-missing;"); } } } /* nothing matched */ if (filename->len == 0) { g_warning ("nothing matched, falling back to default icon"); g_string_append (filename, "dialog-warning;"); } g_debug ("got filename: %s", filename->str); iconnames = g_strsplit (filename->str, ";", -1); icon = g_themed_icon_new_from_names (iconnames, -1); g_strfreev (iconnames); g_string_free (filename, TRUE); return icon; } /** * gpm_precision_round_down: * @value: The input value * @smallest: The smallest increment allowed * * 101, 10 100 * 95, 10 90 * 0, 10 0 * 112, 10 110 * 100, 10 100 **/ static gint gpm_precision_round_down (gfloat value, gint smallest) { gfloat division; if (fabs (value) < 0.01) return 0; if (smallest == 0) { g_warning ("divisor zero"); return 0; } division = (gfloat) value / (gfloat) smallest; division = floorf (division); division *= smallest; return (gint) division; } gchar * gpm_upower_get_device_summary (UpDevice *device) { const gchar *kind_desc = NULL; const gchar *device_desc = NULL; GString *description; guint time_to_full_round; guint time_to_empty_round; gchar *time_to_full_str = NULL; gchar *time_to_empty_str = NULL; UpDeviceKind kind; UpDeviceState state; gdouble percentage; gboolean is_present; gint64 time_to_full; gint64 time_to_empty; /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "percentage", &percentage, "is-present", &is_present, "time-to-full", &time_to_full, "time-to-empty", &time_to_empty, NULL); description = g_string_new (NULL); kind_desc = gpm_device_kind_to_localised_string (kind, 1); device_desc = gpm_device_to_localised_string (device); /* not installed */ if (!is_present) { g_string_append (description, device_desc); goto out; } /* don't display all the extra stuff for keyboards and mice */ if (kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD || kind == UP_DEVICE_KIND_PDA) { g_string_append (description, kind_desc); g_string_append_printf (description, " (%.0f%%)", percentage); goto out; } /* we care if we are on AC */ if (kind == UP_DEVICE_KIND_PHONE) { if (state == UP_DEVICE_STATE_CHARGING || !(state == UP_DEVICE_STATE_DISCHARGING)) { g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); goto out; } g_string_append (description, kind_desc); g_string_append_printf (description, " (%.0f%%)", percentage); goto out; } /* precalculate so we don't get Unknown time remaining */ time_to_full_round = gpm_precision_round_down (time_to_full, GPM_UP_TIME_PRECISION); time_to_empty_round = gpm_precision_round_down (time_to_empty, GPM_UP_TIME_PRECISION); /* we always display "Laptop battery 16 minutes remaining" as we need to clarify what device we are refering to */ if (state == UP_DEVICE_STATE_FULLY_CHARGED) { g_string_append (description, device_desc); if (kind == UP_DEVICE_KIND_BATTERY && time_to_empty_round > GPM_UP_TEXT_MIN_TIME) { time_to_empty_str = gpm_get_timestring (time_to_empty_round); g_string_append (description, " - "); /* TRANSLATORS: The laptop battery is charged, and we know a time. * The parameter is the time, e.g. 7 hours 6 minutes */ g_string_append_printf (description, _("provides %s laptop runtime"), time_to_empty_str); } goto out; } if (state == UP_DEVICE_STATE_DISCHARGING) { if (time_to_empty_round > GPM_UP_TEXT_MIN_TIME) { time_to_empty_str = gpm_get_timestring (time_to_empty_round); /* TRANSLATORS: the device is discharging, and we have a time remaining * The first parameter is the device type, e.g. "Laptop battery" and * the second is the time, e.g. 7 hours 6 minutes */ g_string_append_printf (description, _("%s %s remaining"), kind_desc, time_to_empty_str); g_string_append_printf (description, " (%.0f%%)", percentage); } else { g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); } goto out; } if (state == UP_DEVICE_STATE_CHARGING) { if (time_to_full_round > GPM_UP_TEXT_MIN_TIME && time_to_empty_round > GPM_UP_TEXT_MIN_TIME) { /* display both discharge and charge time */ time_to_full_str = gpm_get_timestring (time_to_full_round); time_to_empty_str = gpm_get_timestring (time_to_empty_round); /* TRANSLATORS: device is charging, and we have a time to full and a percentage * The first parameter is the device type, e.g. "Laptop battery" and * the second is the time, e.g. "7 hours 6 minutes" */ g_string_append_printf (description, _("%s %s until charged"), kind_desc, time_to_full_str); g_string_append_printf (description, " (%.0f%%)", percentage); g_string_append (description, " - "); /* TRANSLATORS: the device is charging, and we have a time to full and empty. * The parameter is a time string, e.g. "7 hours 6 minutes" */ g_string_append_printf (description, _("provides %s battery runtime"), time_to_empty_str); } else if (time_to_full_round > GPM_UP_TEXT_MIN_TIME) { /* display only charge time */ time_to_full_str = gpm_get_timestring (time_to_full_round); /* TRANSLATORS: device is charging, and we have a time to full and a percentage. * The first parameter is the device type, e.g. "Laptop battery" and * the second is the time, e.g. "7 hours 6 minutes" */ g_string_append_printf (description, _("%s %s until charged"), kind_desc, time_to_full_str); g_string_append_printf (description, " (%.0f%%)", percentage); } else { g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); } goto out; } if (state == UP_DEVICE_STATE_PENDING_DISCHARGE) { g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); goto out; } if (state == UP_DEVICE_STATE_PENDING_CHARGE) { g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); goto out; } if (state == UP_DEVICE_STATE_EMPTY) { g_string_append (description, device_desc); goto out; } /* fallback */ g_warning ("in an undefined state we are not charging or " "discharging and the batteries are also not charged"); g_string_append (description, device_desc); g_string_append_printf (description, " (%.0f%%)", percentage); out: g_free (time_to_full_str); g_free (time_to_empty_str); return g_string_free (description, FALSE); } gchar * gpm_upower_get_device_description (UpDevice *device) { GString *details; const gchar *text; gchar *time_str; UpDeviceKind kind; UpDeviceState state; UpDeviceTechnology technology; gdouble percentage; gdouble capacity; gdouble energy; gdouble energy_full; gdouble energy_full_design; gdouble energy_rate; gboolean is_present; gint64 time_to_full; gint64 time_to_empty; gchar *vendor = NULL; gchar *serial = NULL; gchar *model = NULL; g_return_val_if_fail (device != NULL, NULL); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "percentage", &percentage, "is-present", &is_present, "time-to-full", &time_to_full, "time-to-empty", &time_to_empty, "technology", &technology, "capacity", &capacity, "energy", &energy, "energy-full", &energy_full, "energy-full-design", &energy_full_design, "energy-rate", &energy_rate, "vendor", &vendor, "serial", &serial, "model", &model, NULL); details = g_string_new (""); text = gpm_device_kind_to_localised_string (kind, 1); /* TRANSLATORS: the type of data, e.g. Laptop battery */ g_string_append_printf (details, "%s %s\n", _("Product:"), text); if (!is_present) { /* TRANSLATORS: device is missing */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Missing")); } else if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: device is charged */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Charged")); } else if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: device is charging */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Charging")); } else if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: device is discharging */ g_string_append_printf (details, "%s %s\n", _("Status:"), _("Discharging")); } if (percentage >= 0) { /* TRANSLATORS: percentage */ g_string_append_printf (details, "%s %.1f%%\n", _("Percentage charge:"), percentage); } if (vendor) { /* TRANSLATORS: manufacturer */ g_string_append_printf (details, "%s %s\n", _("Vendor:"), vendor); } if (technology != UP_DEVICE_TECHNOLOGY_UNKNOWN) { text = gpm_device_technology_to_localised_string (technology); /* TRANSLATORS: how the battery is made, e.g. Lithium Ion */ g_string_append_printf (details, "%s %s\n", _("Technology:"), text); } if (serial) { /* TRANSLATORS: serial number of the battery */ g_string_append_printf (details, "%s %s\n", _("Serial number:"), serial); } if (model) { /* TRANSLATORS: model number of the battery */ g_string_append_printf (details, "%s %s\n", _("Model:"), model); } if (time_to_full > 0) { time_str = gpm_get_timestring (time_to_full); /* TRANSLATORS: time to fully charged */ g_string_append_printf (details, "%s %s\n", _("Charge time:"), time_str); g_free (time_str); } if (time_to_empty > 0) { time_str = gpm_get_timestring (time_to_empty); /* TRANSLATORS: time to empty */ g_string_append_printf (details, "%s %s\n", _("Discharge time:"), time_str); g_free (time_str); } if (capacity > 0) { const gchar *condition; if (capacity > 99) { /* TRANSLATORS: Excellent, Good, Fair and Poor are all related to battery Capacity */ condition = _("Excellent"); } else if (capacity > 90) { condition = _("Good"); } else if (capacity > 70) { condition = _("Fair"); } else { condition = _("Poor"); } /* TRANSLATORS: %.1f is a percentage and %s the condition (Excellent, Good, ...) */ g_string_append_printf (details, "%s %.1f%% (%s)\n", _("Capacity:"), capacity, condition); } if (kind == UP_DEVICE_KIND_BATTERY) { if (energy > 0) { /* TRANSLATORS: current charge */ g_string_append_printf (details, "%s %.1f Wh\n", _("Current charge:"), energy); } if (energy_full > 0 && energy_full_design != energy_full) { /* TRANSLATORS: last full is the charge the battery was seen to charge to */ g_string_append_printf (details, "%s %.1f Wh\n", _("Last full charge:"), energy_full); } if (energy_full_design > 0) { /* Translators: */ /* TRANSLATORS: Design charge is the amount of charge the battery is designed to have when brand new */ g_string_append_printf (details, "%s %.1f Wh\n", _("Design charge:"), energy_full_design); } if (energy_rate > 0) { /* TRANSLATORS: the charge or discharge rate */ g_string_append_printf (details, "%s %.1f W\n", _("Charge rate:"), energy_rate); } } if (kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD) { if (energy > 0) { /* TRANSLATORS: the current charge for CSR devices */ g_string_append_printf (details, "%s %.0f/7\n", _("Current charge:"), energy); } if (energy_full_design > 0) { /* TRANSLATORS: the design charge for CSR devices */ g_string_append_printf (details, "%s %.0f/7\n", _("Design charge:"), energy_full_design); } } /* remove the last \n */ g_string_truncate (details, details->len-1); g_free (vendor); g_free (serial); g_free (model); return g_string_free (details, FALSE); } const gchar * gpm_device_kind_to_localised_string (UpDeviceKind kind, guint number) { const gchar *text = NULL; switch (kind) { case UP_DEVICE_KIND_LINE_POWER: /* TRANSLATORS: system power cord */ text = ngettext ("AC adapter", "AC adapters", number); break; case UP_DEVICE_KIND_BATTERY: /* TRANSLATORS: laptop primary battery */ text = ngettext ("Laptop battery", "Laptop batteries", number); break; case UP_DEVICE_KIND_UPS: /* TRANSLATORS: battery-backed AC power source */ text = ngettext ("UPS", "UPSs", number); break; case UP_DEVICE_KIND_MONITOR: /* TRANSLATORS: a monitor is a device to measure voltage and current */ text = ngettext ("Monitor", "Monitors", number); break; case UP_DEVICE_KIND_MOUSE: /* TRANSLATORS: wireless mice with internal batteries */ text = ngettext ("Mouse", "Mice", number); break; case UP_DEVICE_KIND_KEYBOARD: /* TRANSLATORS: wireless keyboard with internal battery */ text = ngettext ("Keyboard", "Keyboards", number); break; case UP_DEVICE_KIND_PDA: /* TRANSLATORS: portable device */ text = ngettext ("PDA", "PDAs", number); break; case UP_DEVICE_KIND_PHONE: /* TRANSLATORS: cell phone (mobile...) */ text = ngettext ("Cell phone", "Cell phones", number); break; case UP_DEVICE_KIND_MEDIA_PLAYER: /* TRANSLATORS: media player, mp3 etc */ text = ngettext ("Media player", "Media players", number); break; case UP_DEVICE_KIND_TABLET: /* TRANSLATORS: tablet device */ text = ngettext ("Tablet", "Tablets", number); break; case UP_DEVICE_KIND_COMPUTER: /* TRANSLATORS: tablet device */ text = ngettext ("Computer", "Computers", number); break; default: g_warning ("enum unrecognised: %i", kind); text = up_device_kind_to_string (kind); } return text; } const gchar * gpm_device_kind_to_icon (UpDeviceKind kind) { const gchar *icon = NULL; switch (kind) { case UP_DEVICE_KIND_LINE_POWER: icon = "ac-adapter"; break; case UP_DEVICE_KIND_BATTERY: icon = "battery"; break; case UP_DEVICE_KIND_UPS: icon = "network-wired"; break; case UP_DEVICE_KIND_MONITOR: icon = "application-certificate"; break; case UP_DEVICE_KIND_MOUSE: icon = "input-mouse"; break; case UP_DEVICE_KIND_KEYBOARD: icon = "input-keyboard"; break; case UP_DEVICE_KIND_PDA: icon = "pda"; break; case UP_DEVICE_KIND_PHONE: icon = "phone"; break; case UP_DEVICE_KIND_MEDIA_PLAYER: icon = "multimedia-player"; break; case UP_DEVICE_KIND_TABLET: icon = "input-tablet"; break; case UP_DEVICE_KIND_COMPUTER: icon = "computer-apple-ipad"; break; default: g_warning ("enum unrecognised: %i", kind); icon = "gtk-help"; } return icon; } const gchar * gpm_device_technology_to_localised_string (UpDeviceTechnology technology_enum) { const gchar *technology = NULL; switch (technology_enum) { case UP_DEVICE_TECHNOLOGY_LITHIUM_ION: /* TRANSLATORS: battery technology */ technology = _("Lithium Ion"); break; case UP_DEVICE_TECHNOLOGY_LITHIUM_POLYMER: /* TRANSLATORS: battery technology */ technology = _("Lithium Polymer"); break; case UP_DEVICE_TECHNOLOGY_LITHIUM_IRON_PHOSPHATE: /* TRANSLATORS: battery technology */ technology = _("Lithium Iron Phosphate"); break; case UP_DEVICE_TECHNOLOGY_LEAD_ACID: /* TRANSLATORS: battery technology */ technology = _("Lead acid"); break; case UP_DEVICE_TECHNOLOGY_NICKEL_CADMIUM: /* TRANSLATORS: battery technology */ technology = _("Nickel Cadmium"); break; case UP_DEVICE_TECHNOLOGY_NICKEL_METAL_HYDRIDE: /* TRANSLATORS: battery technology */ technology = _("Nickel metal hydride"); break; case UP_DEVICE_TECHNOLOGY_UNKNOWN: /* TRANSLATORS: battery technology */ technology = _("Unknown technology"); break; default: g_assert_not_reached (); break; } return technology; } const gchar * gpm_device_state_to_localised_string (UpDeviceState state) { const gchar *state_string = NULL; switch (state) { case UP_DEVICE_STATE_CHARGING: /* TRANSLATORS: battery state */ state_string = _("Charging"); break; case UP_DEVICE_STATE_DISCHARGING: /* TRANSLATORS: battery state */ state_string = _("Discharging"); break; case UP_DEVICE_STATE_EMPTY: /* TRANSLATORS: battery state */ state_string = _("Empty"); break; case UP_DEVICE_STATE_FULLY_CHARGED: /* TRANSLATORS: battery state */ state_string = _("Charged"); break; case UP_DEVICE_STATE_PENDING_CHARGE: /* TRANSLATORS: battery state */ state_string = _("Waiting to charge"); break; case UP_DEVICE_STATE_PENDING_DISCHARGE: /* TRANSLATORS: battery state */ state_string = _("Waiting to discharge"); break; default: g_assert_not_reached (); break; } return state_string; } const gchar * gpm_device_to_localised_string (UpDevice *device) { UpDeviceState state; UpDeviceKind kind; gboolean present; /* get device parameters */ g_object_get (device, "is-present", &present, "kind", &kind, "state", &state, NULL); /* laptop battery */ if (kind == UP_DEVICE_KIND_BATTERY) { if (!present) { /* TRANSLATORS: device not present */ return _("Laptop battery not present"); } if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Laptop battery is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Laptop battery is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Laptop battery is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Laptop battery is charged"); } if (state == UP_DEVICE_STATE_PENDING_CHARGE) { /* TRANSLATORS: battery state */ return _("Laptop battery is waiting to charge"); } if (state == UP_DEVICE_STATE_PENDING_DISCHARGE) { /* TRANSLATORS: battery state */ return _("Laptop battery is waiting to discharge"); } } /* UPS */ if (kind == UP_DEVICE_KIND_UPS) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("UPS is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("UPS is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("UPS is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("UPS is charged"); } } /* mouse */ if (kind == UP_DEVICE_KIND_MOUSE) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Mouse is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Mouse is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Mouse is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Mouse is charged"); } } /* keyboard */ if (kind == UP_DEVICE_KIND_KEYBOARD) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Keyboard is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Keyboard is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Keyboard is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Keyboard is charged"); } } /* PDA */ if (kind == UP_DEVICE_KIND_PDA) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("PDA is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("PDA is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("PDA is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("PDA is charged"); } } /* phone */ if (kind == UP_DEVICE_KIND_PHONE) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Cell phone is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Cell phone is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Cell phone is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Cell phone is charged"); } } /* media player */ if (kind == UP_DEVICE_KIND_MEDIA_PLAYER) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Media player is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Media player is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Media player is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Media player is charged"); } } /* tablet */ if (kind == UP_DEVICE_KIND_TABLET) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Tablet is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Tablet is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Tablet is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Tablet is charged"); } } /* computer */ if (kind == UP_DEVICE_KIND_COMPUTER) { if (state == UP_DEVICE_STATE_CHARGING) { /* TRANSLATORS: battery state */ return _("Computer is charging"); } if (state == UP_DEVICE_STATE_DISCHARGING) { /* TRANSLATORS: battery state */ return _("Computer is discharging"); } if (state == UP_DEVICE_STATE_EMPTY) { /* TRANSLATORS: battery state */ return _("Computer is empty"); } if (state == UP_DEVICE_STATE_FULLY_CHARGED) { /* TRANSLATORS: battery state */ return _("Computer is charged"); } } return gpm_device_kind_to_localised_string (kind, 1); } cinnamon-settings-daemon-2.8.3/plugins/power/test-power.c0000664000175000017500000000030512625665665022464 0ustar fabiofabio#define NEW csd_power_manager_new #define START csd_power_manager_start #define STOP csd_power_manager_stop #define MANAGER CsdPowerManager #include "csd-power-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/power/gpm-idletime.c0000664000175000017500000003734712625665665022750 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include "gpm-idletime.h" static void gpm_idletime_finalize (GObject *object); #define GPM_IDLETIME_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_IDLETIME_TYPE, GpmIdletimePrivate)) struct GpmIdletimePrivate { gint sync_event; gboolean reset_set; XSyncCounter idle_counter; GPtrArray *array; Display *dpy; }; typedef struct { guint id; XSyncValue timeout; XSyncAlarm xalarm; GpmIdletime *idletime; } GpmIdletimeAlarm; enum { SIGNAL_ALARM_EXPIRED, SIGNAL_RESET, LAST_SIGNAL }; typedef enum { GPM_IDLETIME_ALARM_TYPE_POSITIVE, GPM_IDLETIME_ALARM_TYPE_NEGATIVE, GPM_IDLETIME_ALARM_TYPE_DISABLED } GpmIdletimeAlarmType; static guint signals [LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (GpmIdletime, gpm_idletime, G_TYPE_OBJECT) static gint64 gpm_idletime_xsyncvalue_to_int64 (XSyncValue value) { return ((guint64) XSyncValueHigh32 (value)) << 32 | (guint64) XSyncValueLow32 (value); } /* gets the IDLETIME counter value, or 0 for invalid */ gint64 gpm_idletime_get_time (GpmIdletime *idletime) { XSyncValue value; /* we don't have IDLETIME support */ if (!idletime->priv->idle_counter) return 0; /* NX explodes if you query the counter */ gdk_error_trap_push (); XSyncQueryCounter (idletime->priv->dpy, idletime->priv->idle_counter, &value); if (gdk_error_trap_pop ()) return 0; return gpm_idletime_xsyncvalue_to_int64 (value); } static void gpm_idletime_xsync_alarm_set (GpmIdletime *idletime, GpmIdletimeAlarm *alarm_item, GpmIdletimeAlarmType alarm_type) { XSyncAlarmAttributes attr; XSyncValue delta; unsigned int flags; XSyncTestType test; /* just remove it */ if (alarm_type == GPM_IDLETIME_ALARM_TYPE_DISABLED) { if (alarm_item->xalarm) { XSyncDestroyAlarm (idletime->priv->dpy, alarm_item->xalarm); alarm_item->xalarm = None; } return; } /* which way do we do the test? */ if (alarm_type == GPM_IDLETIME_ALARM_TYPE_POSITIVE) test = XSyncPositiveTransition; else test = XSyncNegativeTransition; XSyncIntToValue (&delta, 0); attr.trigger.counter = idletime->priv->idle_counter; attr.trigger.value_type = XSyncAbsolute; attr.trigger.test_type = test; attr.trigger.wait_value = alarm_item->timeout; attr.delta = delta; flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | XSyncCAValue | XSyncCADelta; if (alarm_item->xalarm) { XSyncChangeAlarm (idletime->priv->dpy, alarm_item->xalarm, flags, &attr); } else { alarm_item->xalarm = XSyncCreateAlarm (idletime->priv->dpy, flags, &attr); } } void gpm_idletime_alarm_reset_all (GpmIdletime *idletime) { guint i; GpmIdletimeAlarm *alarm_item; g_return_if_fail (GPM_IS_IDLETIME (idletime)); if (!idletime->priv->reset_set) return; /* reset all the alarms (except the reset alarm) to their timeouts */ for (i=1; i < idletime->priv->array->len; i++) { alarm_item = g_ptr_array_index (idletime->priv->array, i); gpm_idletime_xsync_alarm_set (idletime, alarm_item, GPM_IDLETIME_ALARM_TYPE_POSITIVE); } /* set the reset alarm to be disabled */ alarm_item = g_ptr_array_index (idletime->priv->array, 0); gpm_idletime_xsync_alarm_set (idletime, alarm_item, GPM_IDLETIME_ALARM_TYPE_DISABLED); /* emit signal so say we've reset all timers */ g_signal_emit (idletime, signals [SIGNAL_RESET], 0); /* we need to be reset again on the next event */ idletime->priv->reset_set = FALSE; } static GpmIdletimeAlarm * gpm_idletime_alarm_find_id (GpmIdletime *idletime, guint id) { guint i; GpmIdletimeAlarm *alarm_item; for (i = 0; i < idletime->priv->array->len; i++) { alarm_item = g_ptr_array_index (idletime->priv->array, i); if (alarm_item->id == id) return alarm_item; } return NULL; } static void gpm_idletime_set_reset_alarm (GpmIdletime *idletime, XSyncAlarmNotifyEvent *alarm_event) { GpmIdletimeAlarm *alarm_item; int overflow; XSyncValue add; gint64 current, reset_threshold; alarm_item = gpm_idletime_alarm_find_id (idletime, 0); if (!idletime->priv->reset_set) { /* don't match on the current value because * XSyncNegativeComparison means less or equal. */ XSyncIntToValue (&add, -1); XSyncValueAdd (&alarm_item->timeout, alarm_event->counter_value, add, &overflow); /* set the reset alarm to fire the next time * idletime->priv->idle_counter < the current counter value */ gpm_idletime_xsync_alarm_set (idletime, alarm_item, GPM_IDLETIME_ALARM_TYPE_NEGATIVE); /* don't try to set this again if multiple timers are * going off in sequence */ idletime->priv->reset_set = TRUE; current = gpm_idletime_get_time (idletime); reset_threshold = gpm_idletime_xsyncvalue_to_int64 (alarm_item->timeout); if (current < reset_threshold) { /* We've missed the alarm already */ gpm_idletime_alarm_reset_all (idletime); } } } static GpmIdletimeAlarm * gpm_idletime_alarm_find_event (GpmIdletime *idletime, XSyncAlarmNotifyEvent *alarm_event) { guint i; GpmIdletimeAlarm *alarm_item; for (i = 0; i < idletime->priv->array->len; i++) { alarm_item = g_ptr_array_index (idletime->priv->array, i); if (alarm_event->alarm == alarm_item->xalarm) return alarm_item; } return NULL; } static GdkFilterReturn gpm_idletime_event_filter_cb (GdkXEvent *gdkxevent, GdkEvent *event, gpointer data) { GpmIdletimeAlarm *alarm_item; XEvent *xevent = (XEvent *) gdkxevent; GpmIdletime *idletime = (GpmIdletime *) data; XSyncAlarmNotifyEvent *alarm_event; /* no point continuing */ if (xevent->type != idletime->priv->sync_event + XSyncAlarmNotify) return GDK_FILTER_CONTINUE; alarm_event = (XSyncAlarmNotifyEvent *) xevent; /* did we match one of our alarms? */ alarm_item = gpm_idletime_alarm_find_event (idletime, alarm_event); if (alarm_item == NULL) return GDK_FILTER_CONTINUE; /* are we the reset alarm? */ if (alarm_item->id == 0) { gpm_idletime_alarm_reset_all (idletime); goto out; } /* emit */ g_signal_emit (alarm_item->idletime, signals[SIGNAL_ALARM_EXPIRED], 0, alarm_item->id); /* we need the first alarm to go off to set the reset alarm */ gpm_idletime_set_reset_alarm (idletime, alarm_event); out: /* don't propagate */ return GDK_FILTER_REMOVE; } static GpmIdletimeAlarm * gpm_idletime_alarm_new (GpmIdletime *idletime, guint id) { GpmIdletimeAlarm *alarm_item; /* create a new alarm */ alarm_item = g_new0 (GpmIdletimeAlarm, 1); /* set the default values */ alarm_item->id = id; alarm_item->xalarm = None; alarm_item->idletime = g_object_ref (idletime); return alarm_item; } gboolean gpm_idletime_alarm_set (GpmIdletime *idletime, guint id, guint timeout) { GpmIdletimeAlarm *alarm_item; g_return_val_if_fail (GPM_IS_IDLETIME (idletime), FALSE); g_return_val_if_fail (id != 0, FALSE); if (timeout == 0) { gpm_idletime_alarm_remove (idletime, id); return FALSE; } /* see if we already created an alarm with this ID */ alarm_item = gpm_idletime_alarm_find_id (idletime, id); if (alarm_item == NULL) { /* create a new alarm */ alarm_item = gpm_idletime_alarm_new (idletime, id); g_ptr_array_add (idletime->priv->array, alarm_item); } /* set the timeout */ XSyncIntToValue (&alarm_item->timeout, (gint)timeout); /* set, and start the timer */ gpm_idletime_xsync_alarm_set (idletime, alarm_item, GPM_IDLETIME_ALARM_TYPE_POSITIVE); return TRUE; } static gboolean gpm_idletime_alarm_free (GpmIdletime *idletime, GpmIdletimeAlarm *alarm_item) { g_return_val_if_fail (GPM_IS_IDLETIME (idletime), FALSE); g_return_val_if_fail (alarm_item != NULL, FALSE); if (alarm_item->xalarm) { XSyncDestroyAlarm (idletime->priv->dpy, alarm_item->xalarm); } g_object_unref (alarm_item->idletime); g_free (alarm_item); g_ptr_array_remove (idletime->priv->array, alarm_item); return TRUE; } gboolean gpm_idletime_alarm_remove (GpmIdletime *idletime, guint id) { GpmIdletimeAlarm *alarm_item; g_return_val_if_fail (GPM_IS_IDLETIME (idletime), FALSE); alarm_item = gpm_idletime_alarm_find_id (idletime, id); if (alarm_item == NULL) return FALSE; gpm_idletime_alarm_free (idletime, alarm_item); return TRUE; } static void gpm_idletime_class_init (GpmIdletimeClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gpm_idletime_finalize; g_type_class_add_private (klass, sizeof (GpmIdletimePrivate)); signals [SIGNAL_ALARM_EXPIRED] = g_signal_new ("alarm-expired", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmIdletimeClass, alarm_expired), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [SIGNAL_RESET] = g_signal_new ("reset", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmIdletimeClass, reset), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void gpm_idletime_init (GpmIdletime *idletime) { int sync_error; int ncounters; XSyncSystemCounter *counters; GpmIdletimeAlarm *alarm_item; gint major, minor; guint i; idletime->priv = GPM_IDLETIME_GET_PRIVATE (idletime); idletime->priv->array = g_ptr_array_new (); idletime->priv->reset_set = FALSE; idletime->priv->idle_counter = None; idletime->priv->sync_event = 0; idletime->priv->dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default()); /* get the sync event */ if (!XSyncQueryExtension (idletime->priv->dpy, &idletime->priv->sync_event, &sync_error)) { g_warning ("No Sync extension."); return; } /* check XSync is compatible with the server version */ if (!XSyncInitialize (idletime->priv->dpy, &major, &minor)) { g_warning ("Sync extension not compatible."); return; } counters = XSyncListSystemCounters (idletime->priv->dpy, &ncounters); for (i = 0; i < ncounters && !idletime->priv->idle_counter; i++) { if (strcmp(counters[i].name, "IDLETIME") == 0) idletime->priv->idle_counter = counters[i].counter; } XSyncFreeSystemCounterList (counters); /* arh. we don't have IDLETIME support */ if (!idletime->priv->idle_counter) { g_warning ("No idle counter"); return; } /* catch the timer alarm */ gdk_window_add_filter (NULL, gpm_idletime_event_filter_cb, idletime); /* create a reset alarm */ alarm_item = gpm_idletime_alarm_new (idletime, 0); g_ptr_array_add (idletime->priv->array, alarm_item); } static void gpm_idletime_finalize (GObject *object) { guint i; GpmIdletime *idletime; GpmIdletimeAlarm *alarm_item; g_return_if_fail (object != NULL); g_return_if_fail (GPM_IS_IDLETIME (object)); idletime = GPM_IDLETIME (object); idletime->priv = GPM_IDLETIME_GET_PRIVATE (idletime); /* remove filter */ gdk_window_remove_filter (NULL, gpm_idletime_event_filter_cb, idletime); /* free all counters, including reset counter */ for (i = 0; i < idletime->priv->array->len; i++) { alarm_item = g_ptr_array_index (idletime->priv->array, i); gpm_idletime_alarm_free (idletime, alarm_item); } g_ptr_array_free (idletime->priv->array, TRUE); G_OBJECT_CLASS (gpm_idletime_parent_class)->finalize (object); } GpmIdletime * gpm_idletime_new (void) { return g_object_new (GPM_IDLETIME_TYPE, NULL); } cinnamon-settings-daemon-2.8.3/plugins/power/csd-power-manager.c0000664000175000017500000055641512625665665023710 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * Copyright (C) 2011 Richard Hughes * Copyright (C) 2011 Ritesh Khadgaray * * 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 #define GNOME_DESKTOP_USE_UNSTABLE_API #include #include "gpm-common.h" #include "gpm-phone.h" #include "gpm-idletime.h" #include "cinnamon-settings-profile.h" #include "cinnamon-settings-session.h" #include "csd-enums.h" #include "csd-power-manager.h" #include "csd-power-helper.h" #define GNOME_SESSION_DBUS_NAME "org.gnome.SessionManager" #define GNOME_SESSION_DBUS_PATH "/org/gnome/SessionManager" #define GNOME_SESSION_DBUS_PATH_PRESENCE "/org/gnome/SessionManager/Presence" #define GNOME_SESSION_DBUS_INTERFACE "org.gnome.SessionManager" #define GNOME_SESSION_DBUS_INTERFACE_PRESENCE "org.gnome.SessionManager.Presence" #define UPOWER_DBUS_NAME "org.freedesktop.UPower" #define UPOWER_DBUS_PATH "/org/freedesktop/UPower" #define UPOWER_DBUS_PATH_KBDBACKLIGHT "/org/freedesktop/UPower/KbdBacklight" #define UPOWER_DBUS_INTERFACE "org.freedesktop.UPower" #define UPOWER_DBUS_INTERFACE_KBDBACKLIGHT "org.freedesktop.UPower.KbdBacklight" #define CSD_POWER_SETTINGS_SCHEMA "org.cinnamon.settings-daemon.plugins.power" #define CSD_XRANDR_SETTINGS_SCHEMA "org.cinnamon.settings-daemon.plugins.xrandr" #define CSD_SESSION_SETTINGS_SCHEMA "org.cinnamon.desktop.session" #define CSD_DBUS_SERVICE "org.cinnamon.SettingsDaemon" #define CSD_DBUS_PATH "/org/cinnamon/SettingsDaemon" #define CSD_POWER_DBUS_PATH CSD_DBUS_PATH "/Power" #define CSD_POWER_DBUS_INTERFACE "org.cinnamon.SettingsDaemon.Power" #define CSD_POWER_DBUS_INTERFACE_SCREEN "org.cinnamon.SettingsDaemon.Power.Screen" #define CSD_POWER_DBUS_INTERFACE_KEYBOARD "org.cinnamon.SettingsDaemon.Power.Keyboard" #define GS_DBUS_NAME "org.cinnamon.ScreenSaver" #define GS_DBUS_PATH "/org/cinnamon/ScreenSaver" #define GS_DBUS_INTERFACE "org.cinnamon.ScreenSaver" #define CSD_POWER_MANAGER_NOTIFY_TIMEOUT_NEVER 0 /* ms */ #define CSD_POWER_MANAGER_NOTIFY_TIMEOUT_SHORT 10 * 1000 /* ms */ #define CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG 30 * 1000 /* ms */ #define CSD_POWER_MANAGER_CRITICAL_ALERT_TIMEOUT 5 /* seconds */ #define CSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT 30 /* seconds */ #define LOGIND_DBUS_NAME "org.freedesktop.login1" #define LOGIND_DBUS_PATH "/org/freedesktop/login1" #define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager" /* Keep this in sync with gnome-shell */ #define SCREENSAVER_FADE_TIME 10 /* seconds */ #define XSCREENSAVER_WATCHDOG_TIMEOUT 120 /* seconds */ enum { CSD_POWER_IDLETIME_NULL_ID, CSD_POWER_IDLETIME_DIM_ID, CSD_POWER_IDLETIME_BLANK_ID, CSD_POWER_IDLETIME_SLEEP_ID }; static const gchar introspection_xml[] = "" "" "" "" "" "" "" "" "" "" "" "" "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; /* on ACPI machines we have 4-16 levels, on others it's ~150 */ #define BRIGHTNESS_STEP_AMOUNT(max) ((max) < 20 ? 1 : (max) / 20) /* take a discrete value with offset and convert to percentage */ static int abs_to_percentage (int min, int max, int value) { g_return_val_if_fail (max > min, -1); g_return_val_if_fail (value >= min, -1); g_return_val_if_fail (value <= max, -1); return (((value - min) * 100) / (max - min)); } #define ABS_TO_PERCENTAGE(min, max, value) abs_to_percentage(min, max, value) #define PERCENTAGE_TO_ABS(min, max, value) (min + (((max - min) * value) / 100)) #define CSD_POWER_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_POWER_MANAGER, CsdPowerManagerPrivate)) typedef enum { CSD_POWER_IDLE_MODE_NORMAL, CSD_POWER_IDLE_MODE_DIM, CSD_POWER_IDLE_MODE_BLANK, CSD_POWER_IDLE_MODE_SLEEP } CsdPowerIdleMode; struct CsdPowerManagerPrivate { CinnamonSettingsSession *session; gboolean lid_is_closed; GSettings *settings; GSettings *settings_screensaver; GSettings *settings_xrandr; GSettings *settings_session; gboolean use_logind; UpClient *up_client; GDBusNodeInfo *introspection_data; GDBusConnection *connection; GCancellable *bus_cancellable; GDBusProxy *upower_proxy; GDBusProxy *upower_kdb_proxy; gboolean backlight_helper_force; gchar* backlight_helper_preference_args; gint kbd_brightness_now; gint kbd_brightness_max; gint kbd_brightness_old; gint kbd_brightness_pre_dim; GnomeRRScreen *x11_screen; gboolean use_time_primary; gchar *previous_summary; GIcon *previous_icon; GpmPhone *phone; GPtrArray *devices_array; guint action_percentage; guint action_time; guint critical_percentage; guint critical_time; guint low_percentage; guint low_time; gint pre_dim_brightness; /* level, not percentage */ UpDevice *device_composite; NotifyNotification *notification_discharging; NotifyNotification *notification_low; ca_context *canberra_context; ca_proplist *critical_alert_loop_props; guint32 critical_alert_timeout_id; GDBusProxy *screensaver_proxy; GDBusProxy *session_proxy; GDBusProxy *session_presence_proxy; GpmIdletime *idletime; CsdPowerIdleMode current_idle_mode; guint lid_close_safety_timer_id; GtkStatusIcon *status_icon; guint xscreensaver_watchdog_timer_id; gboolean is_virtual_machine; /* logind stuff */ GDBusProxy *logind_proxy; gint inhibit_lid_switch_fd; gboolean inhibit_lid_switch_taken; gint inhibit_suspend_fd; gboolean inhibit_suspend_taken; guint inhibit_lid_switch_timer_id; }; enum { PROP_0, }; static void csd_power_manager_class_init (CsdPowerManagerClass *klass); static void csd_power_manager_init (CsdPowerManager *power_manager); static void csd_power_manager_finalize (GObject *object); static UpDevice *engine_get_composite_device (CsdPowerManager *manager, UpDevice *original_device); static UpDevice *engine_update_composite_device (CsdPowerManager *manager, UpDevice *original_device); static GIcon *engine_get_icon (CsdPowerManager *manager); static gchar *engine_get_summary (CsdPowerManager *manager); static gboolean external_monitor_is_connected (GnomeRRScreen *screen); static void do_power_action_type (CsdPowerManager *manager, CsdPowerActionType action_type); static void do_lid_closed_action (CsdPowerManager *manager); static void inhibit_lid_switch (CsdPowerManager *manager); static void uninhibit_lid_switch (CsdPowerManager *manager); static void lock_screensaver (CsdPowerManager *manager); static void kill_lid_close_safety_timer (CsdPowerManager *manager); #if UP_CHECK_VERSION(0,99,0) static void device_properties_changed_cb (UpDevice *device, GParamSpec *pspec, CsdPowerManager *manager); #endif G_DEFINE_TYPE (CsdPowerManager, csd_power_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; GQuark csd_power_manager_error_quark (void) { static GQuark quark = 0; if (!quark) quark = g_quark_from_static_string ("csd_power_manager_error"); return quark; } static gboolean play_loop_timeout_cb (CsdPowerManager *manager) { ca_context *context; context = ca_gtk_context_get_for_screen (gdk_screen_get_default ()); ca_context_play_full (context, 0, manager->priv->critical_alert_loop_props, NULL, NULL); return TRUE; } static gboolean play_loop_stop (CsdPowerManager *manager) { if (manager->priv->critical_alert_timeout_id == 0) { g_warning ("no sound loop present to stop"); return FALSE; } if (manager->priv->critical_alert_timeout_id) { g_source_remove (manager->priv->critical_alert_timeout_id); manager->priv->critical_alert_timeout_id = 0; } ca_proplist_destroy (manager->priv->critical_alert_loop_props); manager->priv->critical_alert_loop_props = NULL; manager->priv->critical_alert_timeout_id = 0; return TRUE; } static gboolean play_loop_start (CsdPowerManager *manager, const gchar *id, const gchar *desc, gboolean force, guint timeout) { ca_context *context; if (timeout == 0) { g_warning ("received invalid timeout"); return FALSE; } /* if a sound loop is already running, stop the existing loop */ if (manager->priv->critical_alert_timeout_id != 0) { g_warning ("was instructed to play a sound loop with one already playing"); play_loop_stop (manager); } ca_proplist_create (&(manager->priv->critical_alert_loop_props)); ca_proplist_sets (manager->priv->critical_alert_loop_props, CA_PROP_EVENT_ID, id); ca_proplist_sets (manager->priv->critical_alert_loop_props, CA_PROP_EVENT_DESCRIPTION, desc); manager->priv->critical_alert_timeout_id = g_timeout_add_seconds (timeout, (GSourceFunc) play_loop_timeout_cb, manager); g_source_set_name_by_id (manager->priv->critical_alert_timeout_id, "[CsdPowerManager] play-loop"); /* play the sound, using sounds from the naming spec */ context = ca_gtk_context_get_for_screen (gdk_screen_get_default ()); ca_context_play (context, 0, CA_PROP_EVENT_ID, id, CA_PROP_EVENT_DESCRIPTION, desc, NULL); return TRUE; } static void notify_close_if_showing (NotifyNotification *notification) { gboolean ret; GError *error = NULL; if (notification == NULL) return; ret = notify_notification_close (notification, &error); if (!ret) { g_warning ("failed to close notification: %s", error->message); g_error_free (error); } } static const gchar * get_first_themed_icon_name (GIcon *icon) { const gchar* const *icon_names; const gchar *icon_name = NULL; /* no icon */ if (icon == NULL) goto out; /* just use the first icon */ icon_names = g_themed_icon_get_names (G_THEMED_ICON (icon)); if (icon_names != NULL) icon_name = icon_names[0]; out: return icon_name; } typedef enum { WARNING_NONE = 0, WARNING_DISCHARGING = 1, WARNING_LOW = 2, WARNING_CRITICAL = 3, WARNING_ACTION = 4 } CsdPowerManagerWarning; static GVariant * engine_get_icon_property_variant (CsdPowerManager *manager) { GIcon *icon; GVariant *retval; icon = engine_get_icon (manager); if (icon != NULL) { char *str; str = g_icon_to_string (icon); g_object_unref (icon); retval = g_variant_new_string (str); g_free (str); } else { retval = g_variant_new_string (""); } return retval; } static GVariant * engine_get_tooltip_property_variant (CsdPowerManager *manager) { char *tooltip; GVariant *retval; tooltip = engine_get_summary (manager); retval = g_variant_new_string (tooltip != NULL ? tooltip : ""); g_free (tooltip); return retval; } static void engine_emit_changed (CsdPowerManager *manager, gboolean icon_changed, gboolean state_changed) { GVariantBuilder props_builder; GVariant *props_changed = NULL; GError *error = NULL; /* not yet connected to the bus */ if (manager->priv->connection == NULL) return; g_variant_builder_init (&props_builder, G_VARIANT_TYPE ("a{sv}")); if (icon_changed) g_variant_builder_add (&props_builder, "{sv}", "Icon", engine_get_icon_property_variant (manager)); if (state_changed) g_variant_builder_add (&props_builder, "{sv}", "Tooltip", engine_get_tooltip_property_variant (manager)); props_changed = g_variant_new ("(s@a{sv}@as)", CSD_POWER_DBUS_INTERFACE, g_variant_builder_end (&props_builder), g_variant_new_strv (NULL, 0)); g_variant_ref_sink (props_changed); if (!g_dbus_connection_emit_signal (manager->priv->connection, NULL, CSD_POWER_DBUS_PATH, "org.freedesktop.DBus.Properties", "PropertiesChanged", props_changed, &error)) goto out; out: if (error) { g_warning ("%s", error->message); g_clear_error (&error); } if (props_changed) g_variant_unref (props_changed); } static CsdPowerManagerWarning engine_get_warning_csr (CsdPowerManager *manager, UpDevice *device) { gdouble percentage; /* get device properties */ g_object_get (device, "percentage", &percentage, NULL); if (percentage < 26.0f) return WARNING_LOW; else if (percentage < 13.0f) return WARNING_CRITICAL; return WARNING_NONE; } static CsdPowerManagerWarning engine_get_warning_percentage (CsdPowerManager *manager, UpDevice *device) { gdouble percentage; /* get device properties */ g_object_get (device, "percentage", &percentage, NULL); if (percentage <= manager->priv->action_percentage) return WARNING_ACTION; if (percentage <= manager->priv->critical_percentage) return WARNING_CRITICAL; if (percentage <= manager->priv->low_percentage) return WARNING_LOW; return WARNING_NONE; } static CsdPowerManagerWarning engine_get_warning_time (CsdPowerManager *manager, UpDevice *device) { UpDeviceKind kind; gint64 time_to_empty; /* get device properties */ g_object_get (device, "kind", &kind, "time-to-empty", &time_to_empty, NULL); /* this is probably an error condition */ if (time_to_empty == 0) { g_debug ("time zero, falling back to percentage for %s", up_device_kind_to_string (kind)); return engine_get_warning_percentage (manager, device); } if (time_to_empty <= manager->priv->action_time) return WARNING_ACTION; if (time_to_empty <= manager->priv->critical_time) return WARNING_CRITICAL; if (time_to_empty <= manager->priv->low_time) return WARNING_LOW; return WARNING_NONE; } /** * This gets the possible engine state for the device according to the * policy, which could be per-percent, or per-time. **/ static CsdPowerManagerWarning engine_get_warning (CsdPowerManager *manager, UpDevice *device) { UpDeviceKind kind; UpDeviceState state; CsdPowerManagerWarning warning_type; /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, NULL); /* default to no engine */ warning_type = WARNING_NONE; /* if the device in question is on ac, don't give a warning */ if (state == UP_DEVICE_STATE_CHARGING) goto out; if (kind == UP_DEVICE_KIND_MOUSE || kind == UP_DEVICE_KIND_KEYBOARD) { warning_type = engine_get_warning_csr (manager, device); } else if (kind == UP_DEVICE_KIND_UPS || kind == UP_DEVICE_KIND_MEDIA_PLAYER || kind == UP_DEVICE_KIND_TABLET || kind == UP_DEVICE_KIND_COMPUTER || kind == UP_DEVICE_KIND_PDA) { warning_type = engine_get_warning_percentage (manager, device); } else if (kind == UP_DEVICE_KIND_PHONE) { warning_type = engine_get_warning_percentage (manager, device); } else if (kind == UP_DEVICE_KIND_BATTERY) { /* only use the time when it is accurate, and settings is not disabled */ if (manager->priv->use_time_primary) warning_type = engine_get_warning_time (manager, device); else warning_type = engine_get_warning_percentage (manager, device); } /* If we have no important engines, we should test for discharging */ if (warning_type == WARNING_NONE) { if (state == UP_DEVICE_STATE_DISCHARGING) warning_type = WARNING_DISCHARGING; } out: return warning_type; } static gchar * engine_get_summary (CsdPowerManager *manager) { guint i; GPtrArray *array; UpDevice *device; UpDeviceState state; GString *tooltip = NULL; gchar *part; gboolean is_present; /* need to get AC state */ tooltip = g_string_new (""); /* do we have specific device types? */ array = manager->priv->devices_array; for (i=0;ilen;i++) { device = g_ptr_array_index (array, i); g_object_get (device, "is-present", &is_present, "state", &state, NULL); if (!is_present) continue; if (state == UP_DEVICE_STATE_EMPTY) continue; part = gpm_upower_get_device_summary (device); if (part != NULL) g_string_append_printf (tooltip, "%s\n", part); g_free (part); } /* remove the last \n */ g_string_truncate (tooltip, tooltip->len-1); g_debug ("tooltip: %s", tooltip->str); return g_string_free (tooltip, FALSE); } static GIcon * engine_get_icon_priv (CsdPowerManager *manager, UpDeviceKind device_kind, CsdPowerManagerWarning warning, gboolean use_state) { guint i; GPtrArray *array; UpDevice *device; CsdPowerManagerWarning warning_temp; UpDeviceKind kind; UpDeviceState state; gboolean is_present; /* do we have specific device types? */ array = manager->priv->devices_array; for (i=0;ilen;i++) { device = g_ptr_array_index (array, i); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "is-present", &is_present, NULL); /* if battery then use composite device to cope with multiple batteries */ if (kind == UP_DEVICE_KIND_BATTERY) device = engine_get_composite_device (manager, device); warning_temp = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(device), "engine-warning-old")); if (kind == device_kind && is_present) { if (warning != WARNING_NONE) { if (warning_temp == warning) return gpm_upower_get_device_icon (device, TRUE); continue; } if (use_state) { if (state == UP_DEVICE_STATE_CHARGING || state == UP_DEVICE_STATE_DISCHARGING) return gpm_upower_get_device_icon (device, TRUE); continue; } return gpm_upower_get_device_icon (device, TRUE); } } return NULL; } static GIcon * engine_get_icon (CsdPowerManager *manager) { GIcon *icon = NULL; /* we try CRITICAL: BATTERY, UPS, MOUSE, KEYBOARD */ icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_CRITICAL, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_CRITICAL, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_MOUSE, WARNING_CRITICAL, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_KEYBOARD, WARNING_CRITICAL, FALSE); if (icon != NULL) return icon; /* we try CRITICAL: BATTERY, UPS, MOUSE, KEYBOARD */ icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_LOW, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_LOW, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_MOUSE, WARNING_LOW, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_KEYBOARD, WARNING_LOW, FALSE); if (icon != NULL) return icon; /* we try (DIS)CHARGING: BATTERY, UPS */ icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_NONE, TRUE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_NONE, TRUE); if (icon != NULL) return icon; /* we try PRESENT: BATTERY, UPS */ icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_BATTERY, WARNING_NONE, FALSE); if (icon != NULL) return icon; icon = engine_get_icon_priv (manager, UP_DEVICE_KIND_UPS, WARNING_NONE, FALSE); if (icon != NULL) return icon; /* do not show an icon */ return NULL; } static gboolean engine_recalculate_state_icon (CsdPowerManager *manager) { GIcon *icon; /* show a different icon if we are disconnected */ icon = engine_get_icon (manager); gtk_status_icon_set_visible (manager->priv->status_icon, FALSE); if (icon == NULL) { /* none before, now none */ if (manager->priv->previous_icon == NULL) return FALSE; g_object_unref (manager->priv->previous_icon); manager->priv->previous_icon = NULL; return TRUE; } /* no icon before, now icon */ if (manager->priv->previous_icon == NULL) { /* set fallback icon */ gtk_status_icon_set_visible (manager->priv->status_icon, FALSE); gtk_status_icon_set_from_gicon (manager->priv->status_icon, icon); manager->priv->previous_icon = icon; return TRUE; } /* icon before, now different */ if (!g_icon_equal (manager->priv->previous_icon, icon)) { /* set fallback icon */ gtk_status_icon_set_from_gicon (manager->priv->status_icon, icon); g_object_unref (manager->priv->previous_icon); manager->priv->previous_icon = icon; return TRUE; } g_debug ("no change"); /* nothing to do */ g_object_unref (icon); return FALSE; } static gboolean engine_recalculate_state_summary (CsdPowerManager *manager) { gchar *summary; summary = engine_get_summary (manager); if (manager->priv->previous_summary == NULL) { manager->priv->previous_summary = summary; /* set fallback tooltip */ gtk_status_icon_set_tooltip_text (manager->priv->status_icon, summary); return TRUE; } if (strcmp (manager->priv->previous_summary, summary) != 0) { g_free (manager->priv->previous_summary); manager->priv->previous_summary = summary; /* set fallback tooltip */ gtk_status_icon_set_tooltip_text (manager->priv->status_icon, summary); return TRUE; } g_debug ("no change"); /* nothing to do */ g_free (summary); return FALSE; } static void engine_recalculate_state (CsdPowerManager *manager) { gboolean icon_changed = FALSE; gboolean state_changed = FALSE; icon_changed = engine_recalculate_state_icon (manager); state_changed = engine_recalculate_state_summary (manager); /* only emit if the icon or summary has changed */ if (icon_changed || state_changed) engine_emit_changed (manager, icon_changed, state_changed); } static UpDevice * engine_get_composite_device (CsdPowerManager *manager, UpDevice *original_device) { guint battery_devices = 0; GPtrArray *array; UpDevice *device; UpDeviceKind kind; UpDeviceKind original_kind; guint i; /* get the type of the original device */ g_object_get (original_device, "kind", &original_kind, NULL); /* find out how many batteries in the system */ array = manager->priv->devices_array; for (i=0;ilen;i++) { device = g_ptr_array_index (array, i); g_object_get (device, "kind", &kind, NULL); if (kind == original_kind) battery_devices++; } /* just use the original device if only one primary battery */ if (battery_devices <= 1) { g_debug ("using original device as only one primary battery"); device = original_device; goto out; } /* use the composite device */ device = manager->priv->device_composite; out: /* return composite device or original device */ return device; } static UpDevice * engine_update_composite_device (CsdPowerManager *manager, UpDevice *original_device) { guint i; gdouble percentage = 0.0; gdouble energy = 0.0; gdouble energy_full = 0.0; gdouble energy_rate = 0.0; gdouble energy_total = 0.0; gdouble energy_full_total = 0.0; gdouble energy_rate_total = 0.0; gint64 time_to_empty = 0; gint64 time_to_full = 0; guint battery_devices = 0; gboolean is_charging = FALSE; gboolean is_discharging = FALSE; gboolean is_fully_charged = TRUE; GPtrArray *array; UpDevice *device; UpDeviceState state; UpDeviceKind kind; UpDeviceKind original_kind; /* get the type of the original device */ g_object_get (original_device, "kind", &original_kind, NULL); /* update the composite device */ array = manager->priv->devices_array; for (i=0;ilen;i++) { device = g_ptr_array_index (array, i); g_object_get (device, "kind", &kind, "state", &state, "energy", &energy, "energy-full", &energy_full, "energy-rate", &energy_rate, NULL); if (kind != original_kind) continue; /* one of these will be charging or discharging */ if (state == UP_DEVICE_STATE_CHARGING) is_charging = TRUE; if (state == UP_DEVICE_STATE_DISCHARGING) is_discharging = TRUE; if (state != UP_DEVICE_STATE_FULLY_CHARGED) is_fully_charged = FALSE; /* sum up composite */ energy_total += energy; energy_full_total += energy_full; energy_rate_total += energy_rate; battery_devices++; } /* just use the original device if only one primary battery */ if (battery_devices == 1) { g_debug ("using original device as only one primary battery"); device = original_device; goto out; } /* use percentage weighted for each battery capacity */ if (energy_full_total > 0.0) percentage = 100.0 * energy_total / energy_full_total; /* set composite state */ if (is_charging) state = UP_DEVICE_STATE_CHARGING; else if (is_discharging) state = UP_DEVICE_STATE_DISCHARGING; else if (is_fully_charged) state = UP_DEVICE_STATE_FULLY_CHARGED; else state = UP_DEVICE_STATE_UNKNOWN; /* calculate a quick and dirty time remaining value */ if (energy_rate_total > 0) { if (state == UP_DEVICE_STATE_DISCHARGING) time_to_empty = 3600 * (energy_total / energy_rate_total); else if (state == UP_DEVICE_STATE_CHARGING) time_to_full = 3600 * ((energy_full_total - energy_total) / energy_rate_total); } /* okay, we can use the composite device */ device = manager->priv->device_composite; g_debug ("printing composite device"); g_object_set (device, "energy", energy, "energy-full", energy_full, "energy-rate", energy_rate, "time-to-empty", time_to_empty, "time-to-full", time_to_full, "percentage", percentage, "state", state, NULL); /* force update of icon */ if (engine_recalculate_state_icon (manager)) engine_emit_changed (manager, TRUE, FALSE); out: /* return composite device or original device */ return device; } static void engine_device_add (CsdPowerManager *manager, UpDevice *device) { CsdPowerManagerWarning warning; UpDeviceState state; UpDeviceKind kind; UpDevice *composite; /* assign warning */ warning = engine_get_warning (manager, device); g_object_set_data (G_OBJECT(device), "engine-warning-old", GUINT_TO_POINTER(warning)); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, NULL); /* add old state for transitions */ g_debug ("adding %s with state %s", up_device_get_object_path (device), up_device_state_to_string (state)); g_object_set_data (G_OBJECT(device), "engine-state-old", GUINT_TO_POINTER(state)); if (kind == UP_DEVICE_KIND_BATTERY) { g_debug ("updating because we added a device"); composite = engine_update_composite_device (manager, device); /* get the same values for the composite device */ warning = engine_get_warning (manager, composite); g_object_set_data (G_OBJECT(composite), "engine-warning-old", GUINT_TO_POINTER(warning)); g_object_get (composite, "state", &state, NULL); g_object_set_data (G_OBJECT(composite), "engine-state-old", GUINT_TO_POINTER(state)); } #if UP_CHECK_VERSION(0,99,0) g_ptr_array_add (manager->priv->devices_array, g_object_ref(device)); g_signal_connect (device, "notify::state", G_CALLBACK (device_properties_changed_cb), manager); g_signal_connect (device, "notify::warning-level", G_CALLBACK (device_properties_changed_cb), manager); #endif } static gboolean engine_coldplug (CsdPowerManager *manager) { guint i; GPtrArray *array = NULL; UpDevice *device; #if ! UP_CHECK_VERSION(0,99,0) gboolean ret; GError *error = NULL; /* get devices from UPower */ ret = up_client_enumerate_devices_sync (manager->priv->up_client, NULL, &error); if (!ret) { g_warning ("failed to get device list: %s", error->message); g_error_free (error); goto out; } #endif /* connected mobile phones */ gpm_phone_coldplug (manager->priv->phone); engine_recalculate_state (manager); /* add to database */ array = up_client_get_devices (manager->priv->up_client); for (i = 0; array != NULL && i < array->len; i++) { device = g_ptr_array_index (array, i); engine_device_add (manager, device); } #if ! UP_CHECK_VERSION(0,99,0) out: #endif if (array != NULL) g_ptr_array_unref (array); /* never repeat */ return FALSE; } static void engine_device_added_cb (UpClient *client, UpDevice *device, CsdPowerManager *manager) { /* add to list */ g_ptr_array_add (manager->priv->devices_array, g_object_ref (device)); engine_recalculate_state (manager); } static void #if UP_CHECK_VERSION(0,99,0) engine_device_removed_cb (UpClient *client, const char *object_path, CsdPowerManager *manager) { guint i; for (i = 0; i < manager->priv->devices_array->len; i++) { UpDevice *device = g_ptr_array_index (manager->priv->devices_array, i); if (g_strcmp0 (object_path, up_device_get_object_path (device)) == 0) { g_ptr_array_remove_index (manager->priv->devices_array, i); break; } } #else engine_device_removed_cb (UpClient *client, UpDevice *device, CsdPowerManager *manager) { gboolean ret; ret = g_ptr_array_remove (manager->priv->devices_array, device); if (!ret) return; engine_recalculate_state (manager); #endif } static void on_notification_closed (NotifyNotification *notification, gpointer data) { g_object_unref (notification); } static void create_notification (const char *summary, const char *body, const char *icon, NotifyNotification **weak_pointer_location) { NotifyNotification *notification; notification = notify_notification_new (summary, body, icon); *weak_pointer_location = notification; g_object_add_weak_pointer (G_OBJECT (notification), (gpointer *) weak_pointer_location); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); } static void engine_ups_discharging (CsdPowerManager *manager, UpDevice *device) { const gchar *title; gboolean ret; gchar *remaining_text = NULL; gdouble percentage; GError *error = NULL; GIcon *icon = NULL; gint64 time_to_empty; GString *message; UpDeviceKind kind; /* get device properties */ g_object_get (device, "kind", &kind, "percentage", &percentage, "time-to-empty", &time_to_empty, NULL); if (kind != UP_DEVICE_KIND_UPS) return; /* only show text if there is a valid time */ if (time_to_empty > 0) remaining_text = gpm_get_timestring (time_to_empty); /* TRANSLATORS: UPS is now discharging */ title = _("UPS Discharging"); message = g_string_new (""); if (remaining_text != NULL) { /* TRANSLATORS: tell the user how much time they have got */ g_string_append_printf (message, _("%s of UPS backup power remaining"), remaining_text); } else { g_string_append (message, gpm_device_to_localised_string (device)); } g_string_append_printf (message, " (%.0f%%)", percentage); icon = gpm_upower_get_device_icon (device, TRUE); /* close any existing notification of this class */ notify_close_if_showing (manager->priv->notification_discharging); /* create a new notification */ create_notification (title, message->str, get_first_themed_icon_name (icon), &manager->priv->notification_discharging); notify_notification_set_timeout (manager->priv->notification_discharging, CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG); notify_notification_set_urgency (manager->priv->notification_discharging, NOTIFY_URGENCY_NORMAL); /* TRANSLATORS: this is the notification application name */ notify_notification_set_app_name (manager->priv->notification_discharging, _("Power")); notify_notification_set_hint (manager->priv->notification_discharging, "transient", g_variant_new_boolean (TRUE)); /* try to show */ ret = notify_notification_show (manager->priv->notification_discharging, &error); if (!ret) { g_warning ("failed to show notification: %s", error->message); g_error_free (error); g_object_unref (manager->priv->notification_discharging); } g_string_free (message, TRUE); if (icon != NULL) g_object_unref (icon); g_free (remaining_text); } static CsdPowerActionType manager_critical_action_get (CsdPowerManager *manager, gboolean is_ups) { CsdPowerActionType policy; policy = g_settings_get_enum (manager->priv->settings, "critical-battery-action"); if (policy == CSD_POWER_ACTION_SUSPEND) { if (is_ups == FALSE #if ! UP_CHECK_VERSION(0,99,0) && up_client_get_can_suspend (manager->priv->up_client) #endif ) return policy; return CSD_POWER_ACTION_SHUTDOWN; } else if (policy == CSD_POWER_ACTION_HIBERNATE) { #if ! UP_CHECK_VERSION(0,99,0) if (up_client_get_can_hibernate (manager->priv->up_client)) #endif return policy; return CSD_POWER_ACTION_SHUTDOWN; } return policy; } static gboolean manager_critical_action_do (CsdPowerManager *manager, gboolean is_ups) { CsdPowerActionType action_type; /* stop playing the alert as it's too late to do anything now */ if (manager->priv->critical_alert_timeout_id > 0) play_loop_stop (manager); action_type = manager_critical_action_get (manager, is_ups); do_power_action_type (manager, action_type); return FALSE; } static gboolean manager_critical_action_do_cb (CsdPowerManager *manager) { manager_critical_action_do (manager, FALSE); return FALSE; } static gboolean manager_critical_ups_action_do_cb (CsdPowerManager *manager) { manager_critical_action_do (manager, TRUE); return FALSE; } static gboolean engine_just_laptop_battery (CsdPowerManager *manager) { UpDevice *device; UpDeviceKind kind; GPtrArray *array; gboolean ret = TRUE; guint i; /* find if there are any other device types that mean we have to * be more specific in our wording */ array = manager->priv->devices_array; for (i=0; ilen; i++) { device = g_ptr_array_index (array, i); g_object_get (device, "kind", &kind, NULL); if (kind != UP_DEVICE_KIND_BATTERY) { ret = FALSE; break; } } return ret; } static void engine_charge_low (CsdPowerManager *manager, UpDevice *device) { const gchar *title = NULL; gboolean ret; gchar *message = NULL; gchar *tmp; gchar *remaining_text; gdouble percentage; GIcon *icon = NULL; gint64 time_to_empty; UpDeviceKind kind; GError *error = NULL; /* get device properties */ g_object_get (device, "kind", &kind, "percentage", &percentage, "time-to-empty", &time_to_empty, NULL); /* check to see if the batteries have not noticed we are on AC */ if (kind == UP_DEVICE_KIND_BATTERY) { if (!up_client_get_on_battery (manager->priv->up_client)) { g_warning ("ignoring low message as we are not on battery power"); goto out; } } if (kind == UP_DEVICE_KIND_BATTERY) { /* if the user has no other batteries, drop the "Laptop" wording */ ret = engine_just_laptop_battery (manager); if (ret) { /* TRANSLATORS: laptop battery low, and we only have one battery */ title = _("Battery low"); } else { /* TRANSLATORS: laptop battery low, and we have more than one kind of battery */ title = _("Laptop battery low"); } tmp = gpm_get_timestring (time_to_empty); remaining_text = g_strconcat ("", tmp, "", NULL); g_free (tmp); /* TRANSLATORS: tell the user how much time they have got */ message = g_strdup_printf (_("Approximately %s remaining (%.0f%%)"), remaining_text, percentage); g_free (remaining_text); } else if (kind == UP_DEVICE_KIND_UPS) { /* TRANSLATORS: UPS is starting to get a little low */ title = _("UPS low"); tmp = gpm_get_timestring (time_to_empty); remaining_text = g_strconcat ("", tmp, "", NULL); g_free (tmp); /* TRANSLATORS: tell the user how much time they have got */ message = g_strdup_printf (_("Approximately %s of remaining UPS backup power (%.0f%%)"), remaining_text, percentage); g_free (remaining_text); } else if (kind == UP_DEVICE_KIND_MOUSE) { /* TRANSLATORS: mouse is getting a little low */ title = _("Mouse battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Wireless mouse is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_KEYBOARD) { /* TRANSLATORS: keyboard is getting a little low */ title = _("Keyboard battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Wireless keyboard is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_PDA) { /* TRANSLATORS: PDA is getting a little low */ title = _("PDA battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("PDA is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_PHONE) { /* TRANSLATORS: cell phone (mobile) is getting a little low */ title = _("Cell phone battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Cell phone is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_MEDIA_PLAYER) { /* TRANSLATORS: media player, e.g. mp3 is getting a little low */ title = _("Media player battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Media player is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_TABLET) { /* TRANSLATORS: graphics tablet, e.g. wacom is getting a little low */ title = _("Tablet battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Tablet is low in power (%.0f%%)"), percentage); } else if (kind == UP_DEVICE_KIND_COMPUTER) { /* TRANSLATORS: computer, e.g. ipad is getting a little low */ title = _("Attached computer battery low"); /* TRANSLATORS: tell user more details */ message = g_strdup_printf (_("Attached computer is low in power (%.0f%%)"), percentage); } /* get correct icon */ icon = gpm_upower_get_device_icon (device, TRUE); /* close any existing notification of this class */ notify_close_if_showing (manager->priv->notification_low); /* create a new notification */ create_notification (title, message, get_first_themed_icon_name (icon), &manager->priv->notification_low); notify_notification_set_timeout (manager->priv->notification_low, CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG); notify_notification_set_urgency (manager->priv->notification_low, NOTIFY_URGENCY_NORMAL); notify_notification_set_app_name (manager->priv->notification_low, _("Power")); notify_notification_set_hint (manager->priv->notification_low, "transient", g_variant_new_boolean (TRUE)); /* try to show */ ret = notify_notification_show (manager->priv->notification_low, &error); if (!ret) { g_warning ("failed to show notification: %s", error->message); g_error_free (error); g_object_unref (manager->priv->notification_low); } /* play the sound, using sounds from the naming spec */ ca_context_play (manager->priv->canberra_context, 0, CA_PROP_EVENT_ID, "battery-low", /* TRANSLATORS: this is the sound description */ CA_PROP_EVENT_DESCRIPTION, _("Battery is low"), NULL); out: if (icon != NULL) g_object_unref (icon); g_free (message); } static void engine_charge_critical (CsdPowerManager *manager, UpDevice *device) { const gchar *title = NULL; gboolean ret; gchar *message = NULL; gdouble percentage; GIcon *icon = NULL; gint64 time_to_empty; CsdPowerActionType policy; UpDeviceKind kind; GError *error = NULL; /* get device properties */ g_object_get (device, "kind", &kind, "percentage", &percentage, "time-to-empty", &time_to_empty, NULL); /* check to see if the batteries have not noticed we are on AC */ if (kind == UP_DEVICE_KIND_BATTERY) { if (!up_client_get_on_battery (manager->priv->up_client)) { g_warning ("ignoring critically low message as we are not on battery power"); goto out; } } if (kind == UP_DEVICE_KIND_BATTERY) { /* if the user has no other batteries, drop the "Laptop" wording */ ret = engine_just_laptop_battery (manager); if (ret) { /* TRANSLATORS: laptop battery critically low, and only have one kind of battery */ title = _("Battery critically low"); } else { /* TRANSLATORS: laptop battery critically low, and we have more than one type of battery */ title = _("Laptop battery critically low"); } /* we have to do different warnings depending on the policy */ policy = manager_critical_action_get (manager, FALSE); /* use different text for different actions */ if (policy == CSD_POWER_ACTION_NOTHING) { /* TRANSLATORS: tell the use to insert the plug, as we're not going to do anything */ message = g_strdup (_("Plug in your AC adapter to avoid losing data.")); } else if (policy == CSD_POWER_ACTION_SUSPEND) { /* TRANSLATORS: give the user a ultimatum */ message = g_strdup_printf (_("Computer will suspend very soon unless it is plugged in.")); } else if (policy == CSD_POWER_ACTION_HIBERNATE) { /* TRANSLATORS: give the user a ultimatum */ message = g_strdup_printf (_("Computer will hibernate very soon unless it is plugged in.")); } else if (policy == CSD_POWER_ACTION_SHUTDOWN) { /* TRANSLATORS: give the user a ultimatum */ message = g_strdup_printf (_("Computer will shutdown very soon unless it is plugged in.")); } } else if (kind == UP_DEVICE_KIND_UPS) { gchar *remaining_text; gchar *tmp; /* TRANSLATORS: the UPS is very low */ title = _("UPS critically low"); tmp = gpm_get_timestring (time_to_empty); remaining_text = g_strconcat ("", tmp, "", NULL); g_free (tmp); /* TRANSLATORS: give the user a ultimatum */ message = g_strdup_printf (_("Approximately %s of remaining UPS power (%.0f%%). " "Restore AC power to your computer to avoid losing data."), remaining_text, percentage); g_free (remaining_text); } else if (kind == UP_DEVICE_KIND_MOUSE) { /* TRANSLATORS: the mouse battery is very low */ title = _("Mouse battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Wireless mouse is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_KEYBOARD) { /* TRANSLATORS: the keyboard battery is very low */ title = _("Keyboard battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Wireless keyboard is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_PDA) { /* TRANSLATORS: the PDA battery is very low */ title = _("PDA battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("PDA is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_PHONE) { /* TRANSLATORS: the cell battery is very low */ title = _("Cell phone battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Cell phone is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_MEDIA_PLAYER) { /* TRANSLATORS: the cell battery is very low */ title = _("Cell phone battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Media player is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_TABLET) { /* TRANSLATORS: the cell battery is very low */ title = _("Tablet battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Tablet is very low in power (%.0f%%). " "This device will soon stop functioning if not charged."), percentage); } else if (kind == UP_DEVICE_KIND_COMPUTER) { /* TRANSLATORS: the cell battery is very low */ title = _("Attached computer battery low"); /* TRANSLATORS: the device is just going to stop working */ message = g_strdup_printf (_("Attached computer is very low in power (%.0f%%). " "The device will soon shutdown if not charged."), percentage); } /* get correct icon */ icon = gpm_upower_get_device_icon (device, TRUE); /* close any existing notification of this class */ notify_close_if_showing (manager->priv->notification_low); /* create a new notification */ create_notification (title, message, get_first_themed_icon_name (icon), &manager->priv->notification_low); notify_notification_set_timeout (manager->priv->notification_low, CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG); notify_notification_set_urgency (manager->priv->notification_low, NOTIFY_URGENCY_CRITICAL); notify_notification_set_app_name (manager->priv->notification_low, _("Power")); /* try to show */ ret = notify_notification_show (manager->priv->notification_low, &error); if (!ret) { g_warning ("failed to show notification: %s", error->message); g_error_free (error); g_object_unref (manager->priv->notification_low); } switch (kind) { case UP_DEVICE_KIND_BATTERY: case UP_DEVICE_KIND_UPS: g_debug ("critical charge level reached, starting sound loop"); play_loop_start (manager, "battery-caution", _("Battery is critically low"), TRUE, CSD_POWER_MANAGER_CRITICAL_ALERT_TIMEOUT); break; default: /* play the sound, using sounds from the naming spec */ ca_context_play (manager->priv->canberra_context, 0, CA_PROP_EVENT_ID, "battery-caution", /* TRANSLATORS: this is the sound description */ CA_PROP_EVENT_DESCRIPTION, _("Battery is critically low"), NULL); break; } out: if (icon != NULL) g_object_unref (icon); g_free (message); } static void engine_charge_action (CsdPowerManager *manager, UpDevice *device) { const gchar *title = NULL; gboolean ret; gchar *message = NULL; GError *error = NULL; GIcon *icon = NULL; CsdPowerActionType policy; guint timer_id; UpDeviceKind kind; /* get device properties */ g_object_get (device, "kind", &kind, NULL); /* check to see if the batteries have not noticed we are on AC */ if (kind == UP_DEVICE_KIND_BATTERY) { if (!up_client_get_on_battery (manager->priv->up_client)) { g_warning ("ignoring critically low message as we are not on battery power"); goto out; } } if (kind == UP_DEVICE_KIND_BATTERY) { /* TRANSLATORS: laptop battery is really, really, low */ title = _("Laptop battery critically low"); /* we have to do different warnings depending on the policy */ policy = manager_critical_action_get (manager, FALSE); /* use different text for different actions */ if (policy == CSD_POWER_ACTION_NOTHING) { /* TRANSLATORS: computer will shutdown without saving data */ message = g_strdup (_("The battery is below the critical level and " "this computer will power-off when the " "battery becomes completely empty.")); } else if (policy == CSD_POWER_ACTION_SUSPEND) { /* TRANSLATORS: computer will suspend */ message = g_strdup (_("The battery is below the critical level and " "this computer is about to suspend.\n" "NOTE: A small amount of power is required " "to keep your computer in a suspended state.")); } else if (policy == CSD_POWER_ACTION_HIBERNATE) { /* TRANSLATORS: computer will hibernate */ message = g_strdup (_("The battery is below the critical level and " "this computer is about to hibernate.")); } else if (policy == CSD_POWER_ACTION_SHUTDOWN) { /* TRANSLATORS: computer will just shutdown */ message = g_strdup (_("The battery is below the critical level and " "this computer is about to shutdown.")); } /* wait 20 seconds for user-panic */ timer_id = g_timeout_add_seconds (20, (GSourceFunc) manager_critical_action_do_cb, manager); g_source_set_name_by_id (timer_id, "[CsdPowerManager] battery critical-action"); } else if (kind == UP_DEVICE_KIND_UPS) { /* TRANSLATORS: UPS is really, really, low */ title = _("UPS critically low"); /* we have to do different warnings depending on the policy */ policy = manager_critical_action_get (manager, TRUE); /* use different text for different actions */ if (policy == CSD_POWER_ACTION_NOTHING) { /* TRANSLATORS: computer will shutdown without saving data */ message = g_strdup (_("UPS is below the critical level and " "this computer will power-off when the " "UPS becomes completely empty.")); } else if (policy == CSD_POWER_ACTION_HIBERNATE) { /* TRANSLATORS: computer will hibernate */ message = g_strdup (_("UPS is below the critical level and " "this computer is about to hibernate.")); } else if (policy == CSD_POWER_ACTION_SHUTDOWN) { /* TRANSLATORS: computer will just shutdown */ message = g_strdup (_("UPS is below the critical level and " "this computer is about to shutdown.")); } /* wait 20 seconds for user-panic */ timer_id = g_timeout_add_seconds (20, (GSourceFunc) manager_critical_ups_action_do_cb, manager); g_source_set_name_by_id (timer_id, "[CsdPowerManager] ups critical-action"); } /* not all types have actions */ if (title == NULL) { g_free (message); return; } /* get correct icon */ icon = gpm_upower_get_device_icon (device, TRUE); /* close any existing notification of this class */ notify_close_if_showing (manager->priv->notification_low); /* create a new notification */ create_notification (title, message, get_first_themed_icon_name (icon), &manager->priv->notification_low); notify_notification_set_timeout (manager->priv->notification_low, CSD_POWER_MANAGER_NOTIFY_TIMEOUT_LONG); notify_notification_set_urgency (manager->priv->notification_low, NOTIFY_URGENCY_CRITICAL); notify_notification_set_app_name (manager->priv->notification_low, _("Power")); /* try to show */ ret = notify_notification_show (manager->priv->notification_low, &error); if (!ret) { g_warning ("failed to show notification: %s", error->message); g_error_free (error); g_object_unref (manager->priv->notification_low); } /* play the sound, using sounds from the naming spec */ ca_context_play (manager->priv->canberra_context, 0, CA_PROP_EVENT_ID, "battery-caution", /* TRANSLATORS: this is the sound description */ CA_PROP_EVENT_DESCRIPTION, _("Battery is critically low"), NULL); out: if (icon != NULL) g_object_unref (icon); g_free (message); } static void #if UP_CHECK_VERSION(0,99,0) device_properties_changed_cb (UpDevice *device, GParamSpec *pspec, CsdPowerManager *manager) #else engine_device_changed_cb (UpClient *client, UpDevice *device, CsdPowerManager *manager) #endif { UpDeviceKind kind; UpDeviceState state; UpDeviceState state_old; CsdPowerManagerWarning warning_old; CsdPowerManagerWarning warning; /* get device properties */ g_object_get (device, "kind", &kind, NULL); /* if battery then use composite device to cope with multiple batteries */ if (kind == UP_DEVICE_KIND_BATTERY) { g_debug ("updating because %s changed", up_device_get_object_path (device)); device = engine_update_composite_device (manager, device); } /* get device properties (may be composite) */ g_object_get (device, "state", &state, NULL); g_debug ("%s state is now %s", up_device_get_object_path (device), up_device_state_to_string (state)); /* see if any interesting state changes have happened */ state_old = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(device), "engine-state-old")); if (state_old != state) { if (state == UP_DEVICE_STATE_DISCHARGING) { g_debug ("discharging"); engine_ups_discharging (manager, device); } else if (state == UP_DEVICE_STATE_FULLY_CHARGED || state == UP_DEVICE_STATE_CHARGING) { g_debug ("fully charged or charging, hiding notifications if any"); notify_close_if_showing (manager->priv->notification_low); notify_close_if_showing (manager->priv->notification_discharging); } /* save new state */ g_object_set_data (G_OBJECT(device), "engine-state-old", GUINT_TO_POINTER(state)); } /* check the warning state has not changed */ warning_old = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(device), "engine-warning-old")); warning = engine_get_warning (manager, device); if (warning != warning_old) { if (warning == WARNING_LOW) { g_debug ("** EMIT: charge-low"); engine_charge_low (manager, device); } else if (warning == WARNING_CRITICAL) { g_debug ("** EMIT: charge-critical"); engine_charge_critical (manager, device); } else if (warning == WARNING_ACTION) { g_debug ("charge-action"); engine_charge_action (manager, device); } /* save new state */ g_object_set_data (G_OBJECT(device), "engine-warning-old", GUINT_TO_POINTER(warning)); } engine_recalculate_state (manager); } static UpDevice * engine_get_primary_device (CsdPowerManager *manager) { guint i; UpDevice *device = NULL; UpDevice *device_tmp; UpDeviceKind kind; UpDeviceState state; gboolean is_present; for (i=0; ipriv->devices_array->len; i++) { device_tmp = g_ptr_array_index (manager->priv->devices_array, i); /* get device properties */ g_object_get (device_tmp, "kind", &kind, "state", &state, "is-present", &is_present, NULL); /* not present */ if (!is_present) continue; /* not discharging */ if (state != UP_DEVICE_STATE_DISCHARGING) continue; /* not battery */ if (kind != UP_DEVICE_KIND_BATTERY) continue; /* use composite device to cope with multiple batteries */ device = g_object_ref (engine_get_composite_device (manager, device_tmp)); break; } return device; } static void phone_device_added_cb (GpmPhone *phone, guint idx, CsdPowerManager *manager) { UpDevice *device; device = up_device_new (); g_debug ("phone added %i", idx); /* get device properties */ g_object_set (device, "kind", UP_DEVICE_KIND_PHONE, "is-rechargeable", TRUE, "native-path", g_strdup_printf ("dummy:phone_%i", idx), "is-present", TRUE, NULL); /* state changed */ engine_device_add (manager, device); g_ptr_array_add (manager->priv->devices_array, g_object_ref (device)); engine_recalculate_state (manager); } static void phone_device_removed_cb (GpmPhone *phone, guint idx, CsdPowerManager *manager) { guint i; UpDevice *device; UpDeviceKind kind; g_debug ("phone removed %i", idx); for (i=0; ipriv->devices_array->len; i++) { device = g_ptr_array_index (manager->priv->devices_array, i); /* get device properties */ g_object_get (device, "kind", &kind, NULL); if (kind == UP_DEVICE_KIND_PHONE) { g_ptr_array_remove_index (manager->priv->devices_array, i); break; } } /* state changed */ engine_recalculate_state (manager); } static void phone_device_refresh_cb (GpmPhone *phone, guint idx, CsdPowerManager *manager) { guint i; UpDevice *device; UpDeviceKind kind; UpDeviceState state; gboolean is_present; gdouble percentage; g_debug ("phone refresh %i", idx); for (i=0; ipriv->devices_array->len; i++) { device = g_ptr_array_index (manager->priv->devices_array, i); /* get device properties */ g_object_get (device, "kind", &kind, "state", &state, "percentage", &percentage, "is-present", &is_present, NULL); if (kind == UP_DEVICE_KIND_PHONE) { is_present = gpm_phone_get_present (phone, idx); state = gpm_phone_get_on_ac (phone, idx) ? UP_DEVICE_STATE_CHARGING : UP_DEVICE_STATE_DISCHARGING; percentage = gpm_phone_get_percentage (phone, idx); break; } } /* state changed */ engine_recalculate_state (manager); } static void cinnamon_session_shutdown_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 shutdown using cinnamon-session: %s", error->message); g_error_free (error); } else { g_variant_unref (result); } } static void cinnamon_session_shutdown (void) { GError *error = NULL; GDBusProxy *proxy; /* ask cinnamon-session to show the shutdown dialog with a timeout */ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_PATH, GNOME_SESSION_DBUS_INTERFACE, NULL, &error); if (proxy == NULL) { g_warning ("cannot connect to cinnamon-session: %s", error->message); g_error_free (error); return; } g_dbus_proxy_call (proxy, "Shutdown", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, cinnamon_session_shutdown_cb, NULL); g_object_unref (proxy); } static void do_power_action_type (CsdPowerManager *manager, CsdPowerActionType action_type) { gboolean ret; GError *error = NULL; switch (action_type) { case CSD_POWER_ACTION_SUSPEND: csd_power_suspend (manager->priv->use_logind, manager->priv->upower_proxy); break; case CSD_POWER_ACTION_INTERACTIVE: cinnamon_session_shutdown (); break; case CSD_POWER_ACTION_HIBERNATE: csd_power_hibernate (manager->priv->use_logind, manager->priv->upower_proxy); break; case CSD_POWER_ACTION_SHUTDOWN: /* this is only used on critically low battery where * hibernate is not available and is marginally better * than just powering down the computer mid-write */ csd_power_poweroff (manager->priv->use_logind); break; case CSD_POWER_ACTION_BLANK: ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_OFF, &error); if (!ret) { g_warning ("failed to turn the panel off for policy action: %s", error->message); g_error_free (error); } break; case CSD_POWER_ACTION_NOTHING: break; } } static gboolean upower_kbd_get_percentage (CsdPowerManager *manager, GError **error) { GVariant *k_now = NULL; k_now = g_dbus_proxy_call_sync (manager->priv->upower_kdb_proxy, "GetBrightness", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (k_now != NULL) { g_variant_get (k_now, "(i)", &manager->priv->kbd_brightness_now); g_variant_unref (k_now); return TRUE; } return FALSE; } static void upower_kbd_emit_changed (CsdPowerManager *manager) { gboolean ret; GError *error = NULL; /* not yet connected to the bus */ if (manager->priv->connection == NULL) return; ret = g_dbus_connection_emit_signal (manager->priv->connection, CSD_DBUS_SERVICE, CSD_POWER_DBUS_PATH, CSD_POWER_DBUS_INTERFACE_KEYBOARD, "Changed", NULL, &error); if (!ret) { g_warning ("failed to emit Changed: %s", error->message); g_error_free (error); } } static gboolean upower_kbd_set_brightness (CsdPowerManager *manager, guint value, GError **error) { GVariant *retval; /* same as before */ if (manager->priv->kbd_brightness_now == value) return TRUE; /* update h/w value */ retval = g_dbus_proxy_call_sync (manager->priv->upower_kdb_proxy, "SetBrightness", g_variant_new ("(i)", (gint) value), G_DBUS_CALL_FLAGS_NONE, -1, NULL, error); if (retval == NULL) return FALSE; /* save new value */ manager->priv->kbd_brightness_now = value; g_variant_unref (retval); upower_kbd_emit_changed(manager); return TRUE; } static gboolean upower_kbd_toggle (CsdPowerManager *manager, GError **error) { gboolean ret; if (manager->priv->kbd_brightness_old >= 0) { g_debug ("keyboard toggle off"); ret = upower_kbd_set_brightness (manager, manager->priv->kbd_brightness_old, error); if (ret) { /* succeeded, set to -1 since now no old value */ manager->priv->kbd_brightness_old = -1; } } else { g_debug ("keyboard toggle on"); /* save the current value to restore later when untoggling */ manager->priv->kbd_brightness_old = manager->priv->kbd_brightness_now; ret = upower_kbd_set_brightness (manager, 0, error); if (!ret) { /* failed, reset back to -1 */ manager->priv->kbd_brightness_old = -1; } } upower_kbd_emit_changed(manager); return ret; } static void upower_kbd_handle_changed (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); g_debug("keyboard changed signal"); g_variant_get (parameters, "(i)", &manager->priv->kbd_brightness_now); g_variant_unref (parameters); upower_kbd_emit_changed(manager); } static gboolean suspend_on_lid_close (CsdPowerManager *manager) { CsdXrandrBootBehaviour val; if (!external_monitor_is_connected (manager->priv->x11_screen)) return TRUE; val = g_settings_get_enum (manager->priv->settings_xrandr, "default-monitors-setup"); return val == CSD_XRANDR_BOOT_BEHAVIOUR_DO_NOTHING; } static gboolean inhibit_lid_switch_timer_cb (CsdPowerManager *manager) { if (suspend_on_lid_close (manager)) { g_debug ("no external monitors for a while; uninhibiting lid close"); uninhibit_lid_switch (manager); manager->priv->inhibit_lid_switch_timer_id = 0; return G_SOURCE_REMOVE; } g_debug ("external monitor still there; trying again later"); return G_SOURCE_CONTINUE; } /* Sets up a timer to be triggered some seconds after closing the laptop lid * when the laptop is *not* suspended for some reason. We'll check conditions * again in the timeout handler to see if we can suspend then. */ static void setup_inhibit_lid_switch_timer (CsdPowerManager *manager) { if (manager->priv->inhibit_lid_switch_timer_id != 0) { g_debug ("lid close safety timer already set up"); return; } g_debug ("setting up lid close safety timer"); manager->priv->inhibit_lid_switch_timer_id = g_timeout_add_seconds (CSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT, (GSourceFunc) inhibit_lid_switch_timer_cb, manager); g_source_set_name_by_id (manager->priv->inhibit_lid_switch_timer_id, "[CsdPowerManager] lid close safety timer"); } static void restart_inhibit_lid_switch_timer (CsdPowerManager *manager) { if (manager->priv->inhibit_lid_switch_timer_id != 0) { g_debug ("restarting lid close safety timer"); g_source_remove (manager->priv->inhibit_lid_switch_timer_id); manager->priv->inhibit_lid_switch_timer_id = 0; setup_inhibit_lid_switch_timer (manager); } } static gboolean randr_output_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 gboolean external_monitor_is_connected (GnomeRRScreen *screen) { GnomeRROutput **outputs; guint i; /* see if we have more than one screen plugged in */ outputs = gnome_rr_screen_list_outputs (screen); for (i = 0; outputs[i] != NULL; i++) { if (randr_output_is_on (outputs[i]) && !gnome_rr_output_is_laptop (outputs[i])) return TRUE; } return FALSE; } static void on_randr_event (GnomeRRScreen *screen, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); if (suspend_on_lid_close (manager)) { restart_inhibit_lid_switch_timer (manager); return; } /* when a second monitor is plugged in, we take the * handle-lid-switch inhibitor lock of logind to prevent * it from suspending. * * Uninhibiting is done in the inhibit_lid_switch_timer, * since we want to give users a few seconds when unplugging * and replugging an external monitor, not suspend right away. */ inhibit_lid_switch (manager); setup_inhibit_lid_switch_timer (manager); } static void do_lid_open_action (CsdPowerManager *manager) { gboolean ret; GError *error = NULL; /* play a sound, using sounds from the naming spec */ ca_context_play (manager->priv->canberra_context, 0, CA_PROP_EVENT_ID, "lid-open", /* TRANSLATORS: this is the sound description */ CA_PROP_EVENT_DESCRIPTION, _("Lid has been opened"), NULL); /* ensure we turn the panel back on after lid open */ ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_ON, &error); if (!ret) { g_warning ("failed to turn the panel on after lid open: %s", error->message); g_clear_error (&error); } /* only toggle keyboard if present and already toggled off */ if (manager->priv->upower_kdb_proxy != NULL && manager->priv->kbd_brightness_old != -1) { ret = upower_kbd_toggle (manager, &error); if (!ret) { g_warning ("failed to turn the kbd backlight on: %s", error->message); g_error_free (error); } } kill_lid_close_safety_timer (manager); } 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 gboolean non_laptop_outputs_are_all_off (GnomeRRScreen *screen) { GnomeRROutput **outputs; int i; outputs = gnome_rr_screen_list_outputs (screen); for (i = 0; outputs[i] != NULL; i++) { if (gnome_rr_output_is_laptop (outputs[i])) continue; if (is_on (outputs[i])) return FALSE; } return TRUE; } /* Timeout callback used to check conditions when the laptop's lid is closed but * the machine is not suspended yet. We try to suspend again, so that the laptop * won't overheat if placed in a backpack. */ static gboolean lid_close_safety_timer_cb (CsdPowerManager *manager) { manager->priv->lid_close_safety_timer_id = 0; g_debug ("lid has been closed for a while; trying to suspend again"); do_lid_closed_action (manager); return FALSE; } /* Sets up a timer to be triggered some seconds after closing the laptop lid * when the laptop is *not* suspended for some reason. We'll check conditions * again in the timeout handler to see if we can suspend then. */ static void setup_lid_close_safety_timer (CsdPowerManager *manager) { if (manager->priv->lid_close_safety_timer_id != 0) return; manager->priv->lid_close_safety_timer_id = g_timeout_add_seconds (CSD_POWER_MANAGER_LID_CLOSE_SAFETY_TIMEOUT, (GSourceFunc) lid_close_safety_timer_cb, manager); g_source_set_name_by_id (manager->priv->lid_close_safety_timer_id, "[CsdPowerManager] lid close safety timer"); } static void kill_lid_close_safety_timer (CsdPowerManager *manager) { if (manager->priv->lid_close_safety_timer_id != 0) { g_source_remove (manager->priv->lid_close_safety_timer_id); manager->priv->lid_close_safety_timer_id = 0; } } static void suspend_with_lid_closed (CsdPowerManager *manager) { gboolean ret; GError *error = NULL; CsdPowerActionType action_type; /* we have different settings depending on AC state */ if (up_client_get_on_battery (manager->priv->up_client)) { action_type = g_settings_get_enum (manager->priv->settings, "lid-close-battery-action"); } else { action_type = g_settings_get_enum (manager->priv->settings, "lid-close-ac-action"); } /* check we won't melt when the lid is closed */ if (action_type != CSD_POWER_ACTION_SUSPEND && action_type != CSD_POWER_ACTION_HIBERNATE) { #if ! UP_CHECK_VERSION(0,99,0) if (up_client_get_lid_force_sleep (manager->priv->up_client)) { g_warning ("to prevent damage, now forcing suspend"); do_power_action_type (manager, CSD_POWER_ACTION_SUSPEND); return; } else { /* maybe lock the screen if the lid is closed */ lock_screensaver (manager); } #else lock_screensaver (manager); #endif } /* ensure we turn the panel back on after resume */ ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_OFF, &error); if (!ret) { g_warning ("failed to turn the panel off after lid close: %s", error->message); g_clear_error (&error); } /* only toggle keyboard if present and not already toggled */ if (manager->priv->upower_kdb_proxy && manager->priv->kbd_brightness_old == -1) { ret = upower_kbd_toggle (manager, &error); if (!ret) { g_warning ("failed to turn the kbd backlight off: %s", error->message); g_error_free (error); } } do_power_action_type (manager, action_type); } static void do_lid_closed_action (CsdPowerManager *manager) { /* play a sound, using sounds from the naming spec */ ca_context_play (manager->priv->canberra_context, 0, CA_PROP_EVENT_ID, "lid-close", /* TRANSLATORS: this is the sound description */ CA_PROP_EVENT_DESCRIPTION, _("Lid has been closed"), NULL); /* refresh RANDR so we get an accurate view of what monitors are plugged in when the lid is closed */ gnome_rr_screen_refresh (manager->priv->x11_screen, NULL); /* NULL-GError */ /* perform policy action */ if (g_settings_get_boolean (manager->priv->settings, "lid-close-suspend-with-external-monitor") || non_laptop_outputs_are_all_off (manager->priv->x11_screen)) { g_debug ("lid is closed; suspending or hibernating"); suspend_with_lid_closed (manager); } else { g_debug ("lid is closed; not suspending nor hibernating since some external monitor outputs are still active"); setup_lid_close_safety_timer (manager); } } static void #if UP_CHECK_VERSION(0,99,0) lid_state_changed_cb (UpClient *client, GParamSpec *pspec, CsdPowerManager *manager) #else up_client_changed_cb (UpClient *client, CsdPowerManager *manager) #endif { gboolean tmp; if (!up_client_get_on_battery (client)) { /* if we are playing a critical charge sound loop on AC, stop it */ if (manager->priv->critical_alert_timeout_id > 0) { g_debug ("stopping alert loop due to ac being present"); play_loop_stop (manager); } notify_close_if_showing (manager->priv->notification_low); } /* same state */ tmp = up_client_get_lid_is_closed (manager->priv->up_client); if (manager->priv->lid_is_closed == tmp) return; manager->priv->lid_is_closed = tmp; /* fake a keypress */ if (tmp) do_lid_closed_action (manager); else do_lid_open_action (manager); } typedef enum { SESSION_STATUS_CODE_AVAILABLE = 0, SESSION_STATUS_CODE_INVISIBLE, SESSION_STATUS_CODE_BUSY, SESSION_STATUS_CODE_IDLE, SESSION_STATUS_CODE_UNKNOWN } SessionStatusCode; typedef enum { SESSION_INHIBIT_MASK_LOGOUT = 1, SESSION_INHIBIT_MASK_SWITCH = 2, SESSION_INHIBIT_MASK_SUSPEND = 4, SESSION_INHIBIT_MASK_IDLE = 8 } SessionInhibitMask; static const gchar * idle_mode_to_string (CsdPowerIdleMode mode) { if (mode == CSD_POWER_IDLE_MODE_NORMAL) return "normal"; if (mode == CSD_POWER_IDLE_MODE_DIM) return "dim"; if (mode == CSD_POWER_IDLE_MODE_BLANK) return "blank"; if (mode == CSD_POWER_IDLE_MODE_SLEEP) return "sleep"; return "unknown"; } static GnomeRROutput * get_primary_output (CsdPowerManager *manager) { GnomeRROutput *output = NULL; GnomeRROutput **outputs; guint i; /* search all X11 outputs for the device id */ outputs = gnome_rr_screen_list_outputs (manager->priv->x11_screen); if (outputs == NULL) goto out; for (i = 0; outputs[i] != NULL; i++) { if (gnome_rr_output_is_connected (outputs[i]) && gnome_rr_output_is_laptop (outputs[i]) && gnome_rr_output_get_backlight_min (outputs[i]) >= 0 && gnome_rr_output_get_backlight_max (outputs[i]) > 0) { output = outputs[i]; break; } } out: return output; } static void backlight_override_settings_refresh (CsdPowerManager *manager) { int i = 0; /* update all the stored backlight override properties * this is called on startup and by engine_settings_key_changed_cb */ manager->priv->backlight_helper_force = g_settings_get_boolean (manager->priv->settings, "backlight-helper-force"); /* concatenate all the search preferences into a single argument string */ gchar** backlight_preference_order = g_settings_get_strv (manager->priv->settings, "backlight-helper-preference-order"); gchar* tmp1 = NULL; gchar* tmp2 = NULL; if (backlight_preference_order[0] != NULL) { tmp1 = g_strdup_printf("-b %s", backlight_preference_order[0]); } for (i=1; backlight_preference_order[i] != NULL; i++ ) { tmp2 = tmp1; tmp1 = g_strdup_printf("%s -b %s", tmp2, backlight_preference_order[i]); g_free(tmp2); } tmp2 = manager->priv->backlight_helper_preference_args; manager->priv->backlight_helper_preference_args = tmp1; g_free(tmp2); tmp2 = NULL; g_free(backlight_preference_order); backlight_preference_order = NULL; } /** * backlight_helper_get_value: * * Gets a brightness value from the PolicyKit helper. * * Return value: the signed integer value from the helper, or -1 * for failure. If -1 then @error is set. **/ static gint64 backlight_helper_get_value (const gchar *argument, CsdPowerManager* manager, GError **error) { gboolean ret; gchar *stdout_data = NULL; gint exit_status = 0; gint64 value = -1; gchar *command = NULL; gchar *endptr = NULL; #ifndef __linux__ /* non-Linux platforms won't have /sys/class/backlight */ g_set_error_literal (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "The sysfs backlight helper is only for Linux"); goto out; #endif /* get the data */ command = g_strdup_printf (LIBEXECDIR "/csd-backlight-helper --%s %s", argument, manager->priv->backlight_helper_preference_args); ret = g_spawn_command_line_sync (command, &stdout_data, NULL, &exit_status, error); g_debug ("executed %s retval: %i", command, exit_status); if (!ret) goto out; if (WEXITSTATUS (exit_status) != 0) { g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "csd-backlight-helper failed: %s", stdout_data ? stdout_data : "No reason"); goto out; } /* parse */ value = g_ascii_strtoll (stdout_data, &endptr, 10); /* parsing error */ if (endptr == stdout_data) { value = -1; g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "failed to parse value: %s", stdout_data); goto out; } /* out of range */ if (value > G_MAXINT) { value = -1; g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "value out of range: %s", stdout_data); goto out; } /* Fetching the value failed, for some other reason */ if (value < 0) { g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "value negative, but helper did not fail: %s", stdout_data); goto out; } out: g_free (command); g_free (stdout_data); return value; } /** * backlight_helper_set_value: * * Sets a brightness value using the PolicyKit helper. * * Return value: Success. If FALSE then @error is set. **/ static gboolean backlight_helper_set_value (const gchar *argument, gint value, CsdPowerManager* manager, GError **error) { gboolean ret; gint exit_status = 0; gchar *command = NULL; #ifndef __linux__ /* non-Linux platforms won't have /sys/class/backlight */ g_set_error_literal (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "The sysfs backlight helper is only for Linux"); goto out; #endif /* get the data */ command = g_strdup_printf ("pkexec " LIBEXECDIR "/csd-backlight-helper --%s %i %s", argument, value, manager->priv->backlight_helper_preference_args); ret = g_spawn_command_line_sync (command, NULL, NULL, &exit_status, error); g_debug ("executed %s retval: %i", command, exit_status); if (!ret || WEXITSTATUS (exit_status) != 0) goto out; out: g_free (command); return ret; } static gint backlight_get_abs (CsdPowerManager *manager, GError **error) { GnomeRROutput *output; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { return gnome_rr_output_get_backlight (output, error); } } /* fall back to the polkit helper */ return backlight_helper_get_value ("get-brightness", manager, error); } static gint backlight_get_percentage (CsdPowerManager *manager, GError **error) { GnomeRROutput *output; gint now; gint value = -1; gint min = 0; gint max; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { min = gnome_rr_output_get_backlight_min (output); max = gnome_rr_output_get_backlight_max (output); now = gnome_rr_output_get_backlight (output, error); if (now < 0) goto out; value = ABS_TO_PERCENTAGE (min, max, now); goto out; } } /* fall back to the polkit helper */ max = backlight_helper_get_value ("get-max-brightness", manager, error); if (max < 0) goto out; now = backlight_helper_get_value ("get-brightness", manager, error); if (now < 0) goto out; value = ABS_TO_PERCENTAGE (min, max, now); out: return value; } static gint backlight_get_min (CsdPowerManager *manager) { /* if we have no xbacklight device, then hardcode zero as sysfs * offsets everything to 0 as min */ /* user override means we will be using sysfs */ if (manager->priv->backlight_helper_force) return 0; GnomeRROutput *output; output = get_primary_output (manager); if (output == NULL) return 0; /* get xbacklight value, which maybe non-zero */ return gnome_rr_output_get_backlight_min (output); } static gint backlight_get_max (CsdPowerManager *manager, GError **error) { gint value; GnomeRROutput *output; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { value = gnome_rr_output_get_backlight_max (output); if (value < 0) { g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "failed to get backlight max"); } return value; } } /* fall back to the polkit helper */ return backlight_helper_get_value ("get-max-brightness", manager, error); } static void backlight_emit_changed (CsdPowerManager *manager) { gboolean ret; GError *error = NULL; /* not yet connected to the bus */ if (manager->priv->connection == NULL) return; ret = g_dbus_connection_emit_signal (manager->priv->connection, CSD_DBUS_SERVICE, CSD_POWER_DBUS_PATH, CSD_POWER_DBUS_INTERFACE_SCREEN, "Changed", NULL, &error); if (!ret) { g_warning ("failed to emit Changed: %s", error->message); g_error_free (error); } } static gboolean backlight_set_percentage (CsdPowerManager *manager, guint value, gboolean emit_changed, GError **error) { GnomeRROutput *output; gboolean ret = FALSE; gint min = 0; gint max; guint discrete; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { min = gnome_rr_output_get_backlight_min (output); max = gnome_rr_output_get_backlight_max (output); if (min < 0 || max < 0) { g_warning ("no xrandr backlight capability"); goto out; } discrete = PERCENTAGE_TO_ABS (min, max, value); ret = gnome_rr_output_set_backlight (output, discrete, error); goto out; } } /* fall back to the polkit helper */ max = backlight_helper_get_value ("get-max-brightness", manager, error); if (max < 0) goto out; discrete = PERCENTAGE_TO_ABS (min, max, value); ret = backlight_helper_set_value ("set-brightness", discrete, manager, error); out: if (ret && emit_changed) backlight_emit_changed (manager); return ret; } static gint backlight_step_up (CsdPowerManager *manager, GError **error) { GnomeRROutput *output; gboolean ret = FALSE; gint percentage_value = -1; gint min = 0; gint max; gint now; gint step; guint discrete; GnomeRRCrtc *crtc; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { crtc = gnome_rr_output_get_crtc (output); if (crtc == NULL) { g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "no crtc for %s", gnome_rr_output_get_name (output)); goto out; } min = gnome_rr_output_get_backlight_min (output); max = gnome_rr_output_get_backlight_max (output); now = gnome_rr_output_get_backlight (output, error); if (now < 0) goto out; step = BRIGHTNESS_STEP_AMOUNT (max - min + 1); discrete = MIN (now + step, max); ret = gnome_rr_output_set_backlight (output, discrete, error); if (ret) percentage_value = ABS_TO_PERCENTAGE (min, max, discrete); goto out; } } /* fall back to the polkit helper */ now = backlight_helper_get_value ("get-brightness", manager, error); if (now < 0) goto out; max = backlight_helper_get_value ("get-max-brightness", manager, error); if (max < 0) goto out; step = BRIGHTNESS_STEP_AMOUNT (max - min + 1); discrete = MIN (now + step, max); ret = backlight_helper_set_value ("set-brightness", discrete, manager, error); if (ret) percentage_value = ABS_TO_PERCENTAGE (min, max, discrete); out: if (ret) backlight_emit_changed (manager); return percentage_value; } static gint backlight_step_down (CsdPowerManager *manager, GError **error) { GnomeRROutput *output; gboolean ret = FALSE; gint percentage_value = -1; gint min = 0; gint max; gint now; gint step; guint discrete; GnomeRRCrtc *crtc; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { crtc = gnome_rr_output_get_crtc (output); if (crtc == NULL) { g_set_error (error, CSD_POWER_MANAGER_ERROR, CSD_POWER_MANAGER_ERROR_FAILED, "no crtc for %s", gnome_rr_output_get_name (output)); goto out; } min = gnome_rr_output_get_backlight_min (output); max = gnome_rr_output_get_backlight_max (output); now = gnome_rr_output_get_backlight (output, error); if (now < 0) goto out; step = BRIGHTNESS_STEP_AMOUNT (max - min + 1); discrete = MAX (now - step, 0); ret = gnome_rr_output_set_backlight (output, discrete, error); if (ret) percentage_value = ABS_TO_PERCENTAGE (min, max, discrete); goto out; } } /* fall back to the polkit helper */ now = backlight_helper_get_value ("get-brightness", manager, error); if (now < 0) goto out; max = backlight_helper_get_value ("get-max-brightness", manager, error); if (max < 0) goto out; step = BRIGHTNESS_STEP_AMOUNT (max - min + 1); discrete = MAX (now - step, 0); ret = backlight_helper_set_value ("set-brightness", discrete, manager, error); if (ret) percentage_value = ABS_TO_PERCENTAGE (min, max, discrete); out: if (ret) backlight_emit_changed (manager); return percentage_value; } static gint backlight_set_abs (CsdPowerManager *manager, guint value, gboolean emit_changed, GError **error) { GnomeRROutput *output; gboolean ret = FALSE; /* prioritize user override settings */ if (!manager->priv->backlight_helper_force) { /* prefer xbacklight */ output = get_primary_output (manager); if (output != NULL) { ret = gnome_rr_output_set_backlight (output, value, error); goto out; } } /* fall back to the polkit helper */ ret = backlight_helper_set_value ("set-brightness", value, manager, error); out: if (ret && emit_changed) backlight_emit_changed (manager); return ret; } static gboolean display_backlight_dim (CsdPowerManager *manager, gint idle_percentage, GError **error) { gint min; gint max; gint now; gint idle; gboolean ret = FALSE; now = backlight_get_abs (manager, error); if (now < 0) { goto out; } /* is the dim brightness actually *dimmer* than the * brightness we have now? */ min = backlight_get_min (manager); max = backlight_get_max (manager, error); if (max < 0) { goto out; } idle = PERCENTAGE_TO_ABS (min, max, idle_percentage); if (idle > now) { g_debug ("brightness already now %i/%i, so " "ignoring dim to %i/%i", now, max, idle, max); ret = TRUE; goto out; } ret = backlight_set_abs (manager, idle, FALSE, error); if (!ret) { goto out; } /* save for undim */ manager->priv->pre_dim_brightness = now; out: return ret; } static gboolean kbd_backlight_dim (CsdPowerManager *manager, gint idle_percentage, GError **error) { gboolean ret; gint idle; gint max; gint now; if (manager->priv->upower_kdb_proxy == NULL) return TRUE; now = manager->priv->kbd_brightness_now; max = manager->priv->kbd_brightness_max; idle = PERCENTAGE_TO_ABS (0, max, idle_percentage); if (idle > now) { g_debug ("kbd brightness already now %i/%i, so " "ignoring dim to %i/%i", now, max, idle, max); return TRUE; } ret = upower_kbd_set_brightness (manager, idle, error); if (!ret) return FALSE; /* save for undim */ manager->priv->kbd_brightness_pre_dim = now; return TRUE; } static void idle_set_mode (CsdPowerManager *manager, CsdPowerIdleMode mode) { gboolean ret = FALSE; GError *error = NULL; gint idle_percentage; CsdPowerActionType action_type; CinnamonSettingsSessionState state; if (mode == manager->priv->current_idle_mode) return; /* Ignore attempts to set "less idle" modes */ if (mode < manager->priv->current_idle_mode && mode != CSD_POWER_IDLE_MODE_NORMAL) return; /* ensure we're still on an active console */ state = cinnamon_settings_session_get_state (manager->priv->session); if (state == CINNAMON_SETTINGS_SESSION_STATE_INACTIVE) { g_debug ("ignoring state transition to %s as inactive", idle_mode_to_string (mode)); return; } manager->priv->current_idle_mode = mode; g_debug ("Doing a state transition: %s", idle_mode_to_string (mode)); /* don't do any power saving if we're a VM */ if (manager->priv->is_virtual_machine) { g_debug ("ignoring state transition to %s as virtual machine", idle_mode_to_string (mode)); return; } /* save current brightness, and set dim level */ if (mode == CSD_POWER_IDLE_MODE_DIM) { /* have we disabled the action */ if (up_client_get_on_battery (manager->priv->up_client)) { ret = g_settings_get_boolean (manager->priv->settings, "idle-dim-battery"); } else { ret = g_settings_get_boolean (manager->priv->settings, "idle-dim-ac"); } if (!ret) { g_debug ("not dimming due to policy"); return; } /* display backlight */ idle_percentage = g_settings_get_int (manager->priv->settings, "idle-brightness"); ret = display_backlight_dim (manager, idle_percentage, &error); if (!ret) { g_warning ("failed to set dim backlight to %i%%: %s", idle_percentage, error->message); g_clear_error (&error); } /* keyboard backlight */ ret = kbd_backlight_dim (manager, idle_percentage, &error); if (!ret) { g_warning ("failed to set dim kbd backlight to %i%%: %s", idle_percentage, error->message); g_clear_error (&error); } /* turn off screen and kbd */ } else if (mode == CSD_POWER_IDLE_MODE_BLANK) { ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_OFF, &error); if (!ret) { g_warning ("failed to turn the panel off: %s", error->message); g_clear_error (&error); } /* only toggle keyboard if present and not already toggled */ if (manager->priv->upower_kdb_proxy && manager->priv->kbd_brightness_old == -1) { ret = upower_kbd_toggle (manager, &error); if (!ret) { g_warning ("failed to turn the kbd backlight off: %s", error->message); g_error_free (error); } } /* sleep */ } else if (mode == CSD_POWER_IDLE_MODE_SLEEP) { if (up_client_get_on_battery (manager->priv->up_client)) { action_type = g_settings_get_enum (manager->priv->settings, "sleep-inactive-battery-type"); } else { action_type = g_settings_get_enum (manager->priv->settings, "sleep-inactive-ac-type"); } do_power_action_type (manager, action_type); /* turn on screen and restore user-selected brightness level */ } else if (mode == CSD_POWER_IDLE_MODE_NORMAL) { ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_ON, &error); if (!ret) { g_warning ("failed to turn the panel on: %s", error->message); g_clear_error (&error); } /* reset brightness if we dimmed */ if (manager->priv->pre_dim_brightness >= 0) { ret = backlight_set_abs (manager, manager->priv->pre_dim_brightness, FALSE, &error); if (!ret) { g_warning ("failed to restore backlight to %i: %s", manager->priv->pre_dim_brightness, error->message); g_clear_error (&error); } else { manager->priv->pre_dim_brightness = -1; } } /* only toggle keyboard if present and already toggled off */ if (manager->priv->upower_kdb_proxy && manager->priv->kbd_brightness_old != -1) { ret = upower_kbd_toggle (manager, &error); if (!ret) { g_warning ("failed to turn the kbd backlight on: %s", error->message); g_clear_error (&error); } } /* reset kbd brightness if we dimmed */ if (manager->priv->kbd_brightness_pre_dim >= 0) { ret = upower_kbd_set_brightness (manager, manager->priv->kbd_brightness_pre_dim, &error); if (!ret) { g_warning ("failed to restore kbd backlight to %i: %s", manager->priv->kbd_brightness_pre_dim, error->message); g_error_free (error); } manager->priv->kbd_brightness_pre_dim = -1; } } } static gboolean idle_is_session_inhibited (CsdPowerManager *manager, guint mask) { gboolean ret; GVariant *retval = NULL; GError *error = NULL; /* not yet connected to cinnamon-session */ if (manager->priv->session_proxy == NULL) { g_warning ("session inhibition not available, cinnamon-session is not available"); return FALSE; } retval = g_dbus_proxy_call_sync (manager->priv->session_proxy, "IsInhibited", g_variant_new ("(u)", mask), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (retval == NULL) { /* abort as the DBUS method failed */ g_warning ("IsInhibited failed: %s", error->message); g_error_free (error); return FALSE; } g_variant_get (retval, "(b)", &ret); g_variant_unref (retval); return ret; } /** * idle_adjust_timeout: * @idle_time: Current idle time, in seconds. * @timeout: The new timeout we want to set, in seconds. * * On slow machines, or machines that have lots to load duing login, * the current idle time could be bigger than the requested timeout. * In this case the scheduled idle timeout will never fire, unless * some user activity (keyboard, mouse) resets the current idle time. * Instead of relying on user activity to correct this issue, we need * to adjust timeout, as related to current idle time, so the idle * timeout will fire as designed. * * Return value: timeout to set, adjusted acccording to current idle time. **/ static guint idle_adjust_timeout (guint idle_time, guint timeout) { /* allow 2 sec margin for messaging delay. */ idle_time += 2; /* Double timeout until it's larger than current idle time. * Give up for ultra slow machines. (86400 sec = 24 hours) */ while (timeout < idle_time && timeout < 86400 && timeout > 0) { timeout *= 2; } return timeout; } /** * @timeout: The new timeout we want to set, in seconds **/ static void idle_set_timeout_dim (CsdPowerManager *manager, guint timeout) { guint idle_time; gboolean is_idle_inhibited; /* are we inhibited from going idle */ is_idle_inhibited = idle_is_session_inhibited (manager, SESSION_INHIBIT_MASK_IDLE); if (is_idle_inhibited) { g_debug ("inhibited, so using normal state"); idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL); gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_DIM_ID); return; } idle_time = gpm_idletime_get_time (manager->priv->idletime) / 1000; g_debug ("Setting dim idle timeout: %ds", timeout); if (timeout > 0) { gpm_idletime_alarm_set (manager->priv->idletime, CSD_POWER_IDLETIME_DIM_ID, idle_adjust_timeout (idle_time, timeout) * 1000); } else { gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_DIM_ID); } return; } static void refresh_idle_dim_settings (CsdPowerManager *manager) { gint timeout_dim; timeout_dim = g_settings_get_int (manager->priv->settings, "idle-dim-time"); g_debug ("idle dim set with timeout %i", timeout_dim); idle_set_timeout_dim (manager, timeout_dim); } /** * idle_adjust_timeout_blank: * @idle_time: current idle time, in seconds. * @timeout: the new timeout we want to set, in seconds. * * Same as idle_adjust_timeout(), but also accounts for the duration * of the fading animation in the screensaver (so that blanking happens * exactly at the end of it, if configured with the same timeouts) */ static guint idle_adjust_timeout_blank (guint idle_time, guint timeout) { return idle_adjust_timeout (idle_time, timeout + SCREENSAVER_FADE_TIME); } static void idle_configure (CsdPowerManager *manager) { gboolean is_idle_inhibited; guint current_idle_time; guint timeout_blank; guint timeout_sleep; gboolean on_battery; /* are we inhibited from going idle */ is_idle_inhibited = idle_is_session_inhibited (manager, SESSION_INHIBIT_MASK_IDLE); if (is_idle_inhibited) { g_debug ("inhibited, so using normal state"); idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL); gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_BLANK_ID); gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_SLEEP_ID); refresh_idle_dim_settings (manager); return; } current_idle_time = gpm_idletime_get_time (manager->priv->idletime) / 1000; /* set up blank callback even when session is not idle, * but only if we actually want to blank. */ on_battery = up_client_get_on_battery (manager->priv->up_client); if (on_battery) { timeout_blank = g_settings_get_int (manager->priv->settings, "sleep-display-battery"); } else { timeout_blank = g_settings_get_int (manager->priv->settings, "sleep-display-ac"); } if (timeout_blank != 0) { g_debug ("setting up blank callback for %is", timeout_blank); gpm_idletime_alarm_set (manager->priv->idletime, CSD_POWER_IDLETIME_BLANK_ID, idle_adjust_timeout_blank (current_idle_time, timeout_blank) * 1000); } else { gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_BLANK_ID); } /* only do the sleep timeout when the session is idle * and we aren't inhibited from sleeping */ if (on_battery) { timeout_sleep = g_settings_get_int (manager->priv->settings, "sleep-inactive-battery-timeout"); } else { timeout_sleep = g_settings_get_int (manager->priv->settings, "sleep-inactive-ac-timeout"); } if (timeout_sleep != 0) { g_debug ("setting up sleep callback %is", timeout_sleep); gpm_idletime_alarm_set (manager->priv->idletime, CSD_POWER_IDLETIME_SLEEP_ID, idle_adjust_timeout (current_idle_time, timeout_sleep) * 1000); } else { gpm_idletime_alarm_remove (manager->priv->idletime, CSD_POWER_IDLETIME_SLEEP_ID); } refresh_idle_dim_settings (manager); } static void csd_power_manager_class_init (CsdPowerManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csd_power_manager_finalize; g_type_class_add_private (klass, sizeof (CsdPowerManagerPrivate)); } static void sleep_cb_screensaver_proxy_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); manager->priv->screensaver_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (manager->priv->screensaver_proxy == NULL) { g_warning ("Could not connect to cinnamon-screensaver: %s", error->message); g_error_free (error); return; } /* Finish the upower_notify_sleep_cb() call by locking the screen */ g_debug ("cinnamon-screensaver activated, doing cinnamon-screensaver lock"); g_dbus_proxy_call (manager->priv->screensaver_proxy, "Lock", g_variant_new("(s)", ""), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); } static void idle_dbus_signal_cb (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); if (g_strcmp0 (signal_name, "InhibitorAdded") == 0 || g_strcmp0 (signal_name, "InhibitorRemoved") == 0) { g_debug ("Received gnome session inhibitor change"); idle_configure (manager); } if (g_strcmp0 (signal_name, "StatusChanged") == 0) { guint status; g_variant_get (parameters, "(u)", &status); g_dbus_proxy_set_cached_property (proxy, "status", g_variant_new ("u", status)); g_debug ("Received gnome session status change"); idle_configure (manager); } } static void session_proxy_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); manager->priv->session_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (manager->priv->session_proxy == NULL) { g_warning ("Could not connect to cinnamon-session: %s", error->message); g_error_free (error); } else { g_signal_connect (manager->priv->session_proxy, "g-signal", G_CALLBACK (idle_dbus_signal_cb), manager); } idle_configure (manager); } static void session_presence_proxy_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); manager->priv->session_presence_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (manager->priv->session_presence_proxy == NULL) { g_warning ("Could not connect to gnome-sesson: %s", error->message); g_error_free (error); return; } g_signal_connect (manager->priv->session_presence_proxy, "g-signal", G_CALLBACK (idle_dbus_signal_cb), manager); } static void power_proxy_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GError *error = NULL; CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); manager->priv->upower_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (manager->priv->upower_proxy == NULL) { g_warning ("Could not connect to UPower: %s", error->message); g_error_free (error); } } static void power_keyboard_proxy_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GVariant *k_now = NULL; GVariant *k_max = NULL; GError *error = NULL; CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); manager->priv->upower_kdb_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); if (manager->priv->upower_kdb_proxy == NULL) { g_warning ("Could not connect to UPower: %s", error->message); g_error_free (error); goto out; } k_now = g_dbus_proxy_call_sync (manager->priv->upower_kdb_proxy, "GetBrightness", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (k_now == NULL) { if (error->domain != G_DBUS_ERROR || error->code != G_DBUS_ERROR_UNKNOWN_METHOD) { g_warning ("Failed to get brightness: %s", error->message); } g_error_free (error); goto out; } k_max = g_dbus_proxy_call_sync (manager->priv->upower_kdb_proxy, "GetMaxBrightness", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (k_max == NULL) { g_warning ("Failed to get max brightness: %s", error->message); g_error_free (error); goto out; } g_signal_connect (manager->priv->upower_kdb_proxy, "g-signal", G_CALLBACK(upower_kbd_handle_changed), manager); g_variant_get (k_now, "(i)", &manager->priv->kbd_brightness_now); g_variant_get (k_max, "(i)", &manager->priv->kbd_brightness_max); /* Set keyboard brightness to zero if the current value is out of valid range. Unlike display brightness, keyboard backlight brightness should be dim by default.*/ if ((manager->priv->kbd_brightness_now < 0) || (manager->priv->kbd_brightness_now > manager->priv->kbd_brightness_max)) { gboolean ret; ret = upower_kbd_set_brightness (manager, 0, &error); if (!ret) { g_warning ("failed to initialize kbd backlight to %i: %s", 0, error->message); g_error_free (error); } } out: if (k_now != NULL) g_variant_unref (k_now); if (k_max != NULL) g_variant_unref (k_max); } static void lock_screensaver (CsdPowerManager *manager) { gboolean do_lock; do_lock = g_settings_get_boolean (manager->priv->settings_screensaver, "lock-enabled"); if (!do_lock) return; /* connect to the screensaver first */ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, GS_DBUS_NAME, GS_DBUS_PATH, GS_DBUS_INTERFACE, NULL, sleep_cb_screensaver_proxy_ready_cb, manager); } static void idle_idletime_alarm_expired_cb (GpmIdletime *idletime, guint alarm_id, CsdPowerManager *manager) { g_debug ("idletime alarm: %i", alarm_id); switch (alarm_id) { case CSD_POWER_IDLETIME_DIM_ID: idle_set_mode (manager, CSD_POWER_IDLE_MODE_DIM); break; case CSD_POWER_IDLETIME_BLANK_ID: idle_set_mode (manager, CSD_POWER_IDLE_MODE_BLANK); break; case CSD_POWER_IDLETIME_SLEEP_ID: idle_set_mode (manager, CSD_POWER_IDLE_MODE_SLEEP); break; } } static void idle_idletime_reset_cb (GpmIdletime *idletime, CsdPowerManager *manager) { g_debug ("idletime reset"); idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL); } static void engine_settings_key_changed_cb (GSettings *settings, const gchar *key, CsdPowerManager *manager) { /* note: you *have* to check if your key was changed here before * doing anything here. this gets invoked on module stop, and * will crash c-s-d if you don't. */ if (g_strcmp0 (key, "use-time-for-policy") == 0) { manager->priv->use_time_primary = g_settings_get_boolean (settings, key); return; } if (g_strcmp0 (key, "idle-dim-time") == 0) { refresh_idle_dim_settings (manager); return; } if (g_str_has_prefix (key, "sleep-inactive") || g_str_has_prefix (key, "sleep-display")) { idle_configure (manager); return; } if (g_str_has_prefix (key, "backlight-helper")) { backlight_override_settings_refresh (manager); return; } } static void engine_session_active_changed_cb (CinnamonSettingsSession *session, GParamSpec *pspec, CsdPowerManager *manager) { /* when doing the fast-user-switch into a new account, * ensure the new account is undimmed and with the backlight on */ idle_set_mode (manager, CSD_POWER_IDLE_MODE_NORMAL); } /* This timer goes off every few minutes, whether the user is idle or not, to try and clean up anything that has gone wrong. It calls disable_builtin_screensaver() so that if xset has been used, or some other program (like xlock) has messed with the XSetScreenSaver() settings, they will be set back to sensible values (if a server extension is in use, messing with xlock can cause the screensaver to never get a wakeup event, and could cause monitor power-saving to occur, and all manner of heinousness.) This code was originally part of cinnamon-screensaver, see http://git.gnome.org/browse/cinnamon-screensaver/tree/src/gs-watcher-x11.c?id=fec00b12ec46c86334cfd36b37771cc4632f0d4d#n530 */ static gboolean disable_builtin_screensaver (gpointer unused) { int current_server_timeout, current_server_interval; int current_prefer_blank, current_allow_exp; int desired_server_timeout, desired_server_interval; int desired_prefer_blank, desired_allow_exp; XGetScreenSaver (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), ¤t_server_timeout, ¤t_server_interval, ¤t_prefer_blank, ¤t_allow_exp); desired_server_timeout = current_server_timeout; desired_server_interval = current_server_interval; desired_prefer_blank = current_prefer_blank; desired_allow_exp = current_allow_exp; desired_server_interval = 0; /* I suspect (but am not sure) that DontAllowExposures might have something to do with powering off the monitor as well, at least on some systems that don't support XDPMS? Who know... */ desired_allow_exp = AllowExposures; /* When we're not using an extension, set the server-side timeout to 0, so that the server never gets involved with screen blanking, and we do it all ourselves. (However, when we *are* using an extension, we tell the server when to notify us, and rather than blanking the screen, the server will send us an X event telling us to blank.) */ desired_server_timeout = 0; if (desired_server_timeout != current_server_timeout || desired_server_interval != current_server_interval || desired_prefer_blank != current_prefer_blank || desired_allow_exp != current_allow_exp) { g_debug ("disabling server builtin screensaver:" " (xset s %d %d; xset s %s; xset s %s)", desired_server_timeout, desired_server_interval, (desired_prefer_blank ? "blank" : "noblank"), (desired_allow_exp ? "expose" : "noexpose")); XSetScreenSaver (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), desired_server_timeout, desired_server_interval, desired_prefer_blank, desired_allow_exp); XSync (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), FALSE); } return TRUE; } static void inhibit_lid_switch_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); GError *error = NULL; GVariant *res; GUnixFDList *fd_list = NULL; gint idx; res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error); if (res == NULL) { g_warning ("Unable to inhibit lid switch: %s", error->message); g_error_free (error); } else { g_variant_get (res, "(h)", &idx); manager->priv->inhibit_lid_switch_fd = g_unix_fd_list_get (fd_list, idx, &error); if (manager->priv->inhibit_lid_switch_fd == -1) { g_warning ("Failed to receive system inhibitor fd: %s", error->message); g_error_free (error); } g_debug ("System inhibitor fd is %d", manager->priv->inhibit_lid_switch_fd); g_object_unref (fd_list); g_variant_unref (res); } } static void inhibit_lid_switch (CsdPowerManager *manager) { GVariant *params; if (manager->priv->inhibit_lid_switch_taken) { g_debug ("already inhibited lid-switch"); return; } g_debug ("Adding lid switch system inhibitor"); manager->priv->inhibit_lid_switch_taken = TRUE; params = g_variant_new ("(ssss)", "handle-lid-switch", g_get_user_name (), "Multiple displays attached", "block"); g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy, "Inhibit", params, 0, G_MAXINT, NULL, NULL, inhibit_lid_switch_done, manager); } static void uninhibit_lid_switch (CsdPowerManager *manager) { if (manager->priv->inhibit_lid_switch_fd == -1) { g_debug ("no lid-switch inhibitor"); return; } g_debug ("Removing lid switch system inhibitor"); close (manager->priv->inhibit_lid_switch_fd); manager->priv->inhibit_lid_switch_fd = -1; manager->priv->inhibit_lid_switch_taken = FALSE; } static void inhibit_suspend_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); GError *error = NULL; GVariant *res; GUnixFDList *fd_list = NULL; gint idx; res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error); if (res == NULL) { g_warning ("Unable to inhibit suspend: %s", error->message); g_error_free (error); } else { g_variant_get (res, "(h)", &idx); manager->priv->inhibit_suspend_fd = g_unix_fd_list_get (fd_list, idx, &error); if (manager->priv->inhibit_suspend_fd == -1) { g_warning ("Failed to receive system inhibitor fd: %s", error->message); g_error_free (error); } g_debug ("System inhibitor fd is %d", manager->priv->inhibit_suspend_fd); g_object_unref (fd_list); g_variant_unref (res); } } /* We take a delay inhibitor here, which causes logind to send a * PrepareToSleep signal, which gives us a chance to lock the screen * and do some other preparations. */ static void inhibit_suspend (CsdPowerManager *manager) { if (manager->priv->inhibit_suspend_taken) { g_debug ("already inhibited lid-switch"); return; } g_debug ("Adding suspend delay inhibitor"); manager->priv->inhibit_suspend_taken = TRUE; g_dbus_proxy_call_with_unix_fd_list (manager->priv->logind_proxy, "Inhibit", g_variant_new ("(ssss)", "sleep", g_get_user_name (), "Cinnamon needs to lock the screen", "delay"), 0, G_MAXINT, NULL, NULL, inhibit_suspend_done, manager); } static void uninhibit_suspend (CsdPowerManager *manager) { if (manager->priv->inhibit_suspend_fd == -1) { g_debug ("no suspend delay inhibitor"); return; } g_debug ("Removing suspend delay inhibitor"); close (manager->priv->inhibit_suspend_fd); manager->priv->inhibit_suspend_fd = -1; manager->priv->inhibit_suspend_taken = FALSE; } static void handle_suspend_actions (CsdPowerManager *manager) { gboolean do_lock; do_lock = g_settings_get_boolean (manager->priv->settings, "lock-on-suspend"); if (do_lock) g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, GS_DBUS_NAME, GS_DBUS_PATH, GS_DBUS_INTERFACE, NULL, sleep_cb_screensaver_proxy_ready_cb, manager); /* lift the delay inhibit, so logind can proceed */ uninhibit_suspend (manager); } static void handle_resume_actions (CsdPowerManager *manager) { gboolean ret; GError *error = NULL; /* this displays the unlock dialogue so the user doesn't have * to move the mouse or press any key before the window comes up */ g_dbus_connection_call (manager->priv->connection, GS_DBUS_NAME, GS_DBUS_PATH, GS_DBUS_INTERFACE, "SimulateUserActivity", NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); /* close existing notifications on resume, the system power * state is probably different now */ notify_close_if_showing (manager->priv->notification_low); notify_close_if_showing (manager->priv->notification_discharging); /* ensure we turn the panel back on after resume */ ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_ON, &error); if (!ret) { g_warning ("failed to turn the panel on after resume: %s", error->message); g_error_free (error); } /* set up the delay again */ inhibit_suspend (manager); } #if ! UP_CHECK_VERSION(0,99,0) static void upower_notify_sleep_cb (UpClient *client, UpSleepKind sleep_kind, CsdPowerManager *manager) { handle_suspend_actions (manager); } static void upower_notify_resume_cb (UpClient *client, UpSleepKind sleep_kind, CsdPowerManager *manager) { handle_resume_actions (manager); } #endif static void logind_proxy_signal_cb (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); gboolean is_about_to_suspend; if (g_strcmp0 (signal_name, "PrepareForSleep") != 0) return; g_variant_get (parameters, "(b)", &is_about_to_suspend); if (is_about_to_suspend) { handle_suspend_actions (manager); } else { handle_resume_actions (manager); } } static gboolean is_hardware_a_virtual_machine (void) { const gchar *str; gboolean ret = FALSE; GError *error = NULL; GVariant *inner; GVariant *variant = NULL; GDBusConnection *connection; connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (connection == NULL) { g_warning ("system bus not available: %s", error->message); g_error_free (error); goto out; } variant = g_dbus_connection_call_sync (connection, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.DBus.Properties", "Get", g_variant_new ("(ss)", "org.freedesktop.systemd1.Manager", "Virtualization"), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (variant == NULL) { g_debug ("Failed to get property '%s': %s", "Virtualization", error->message); g_error_free (error); goto out; } /* on bare-metal hardware this is the empty string, * otherwise an identifier such as "kvm", "vmware", etc. */ g_variant_get (variant, "(v)", &inner); str = g_variant_get_string (inner, NULL); if (str != NULL && str[0] != '\0') ret = TRUE; out: if (connection != NULL) g_object_unref (connection); if (variant != NULL) g_variant_unref (variant); return ret; } gboolean csd_power_manager_start (CsdPowerManager *manager, GError **error) { gboolean ret; g_debug ("Starting power manager"); cinnamon_settings_profile_start (NULL); /* coldplug the list of screens */ manager->priv->x11_screen = gnome_rr_screen_new (gdk_screen_get_default (), error); if (manager->priv->x11_screen == NULL) return FALSE; /* Set up the logind proxy */ manager->priv->logind_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL, LOGIND_DBUS_NAME, LOGIND_DBUS_PATH, LOGIND_DBUS_INTERFACE, NULL, error); g_signal_connect (manager->priv->logind_proxy, "g-signal", G_CALLBACK (logind_proxy_signal_cb), manager); /* Set up a delay inhibitor to be informed about suspend attempts */ inhibit_suspend (manager); /* Disable logind's lid handling while g-s-d is active */ inhibit_lid_switch (manager); /* track the active session */ manager->priv->session = cinnamon_settings_session_new (); g_signal_connect (manager->priv->session, "notify::state", G_CALLBACK (engine_session_active_changed_cb), manager); manager->priv->kbd_brightness_old = -1; manager->priv->kbd_brightness_pre_dim = -1; manager->priv->pre_dim_brightness = -1; manager->priv->settings = g_settings_new (CSD_POWER_SETTINGS_SCHEMA); g_signal_connect (manager->priv->settings, "changed", G_CALLBACK (engine_settings_key_changed_cb), manager); manager->priv->settings_screensaver = g_settings_new ("org.cinnamon.desktop.screensaver"); manager->priv->settings_xrandr = g_settings_new (CSD_XRANDR_SETTINGS_SCHEMA); manager->priv->settings_session = g_settings_new (CSD_SESSION_SETTINGS_SCHEMA); manager->priv->use_logind = g_settings_get_boolean (manager->priv->settings_session, "settings-daemon-uses-logind"); manager->priv->up_client = up_client_new (); #if ! UP_CHECK_VERSION(0,99,0) g_signal_connect (manager->priv->up_client, "notify-sleep", G_CALLBACK (upower_notify_sleep_cb), manager); g_signal_connect (manager->priv->up_client, "notify-resume", G_CALLBACK (upower_notify_resume_cb), manager); #endif manager->priv->lid_is_closed = up_client_get_lid_is_closed (manager->priv->up_client); g_signal_connect (manager->priv->up_client, "device-added", G_CALLBACK (engine_device_added_cb), manager); g_signal_connect (manager->priv->up_client, "device-removed", G_CALLBACK (engine_device_removed_cb), manager); #if UP_CHECK_VERSION(0,99,0) g_signal_connect_after (manager->priv->up_client, "notify::lid-is-closed", G_CALLBACK (lid_state_changed_cb), manager); #else g_signal_connect (manager->priv->up_client, "device-changed", G_CALLBACK (engine_device_changed_cb), manager); g_signal_connect_after (manager->priv->up_client, "changed", G_CALLBACK (up_client_changed_cb), manager); #endif /* use the fallback name from gnome-power-manager so the shell * blocks this, and uses the power extension instead */ manager->priv->status_icon = gtk_status_icon_new (); gtk_status_icon_set_name (manager->priv->status_icon, "gnome-power-manager"); /* TRANSLATORS: this is the title of the power manager status icon * that is only shown in fallback mode */ gtk_status_icon_set_title (manager->priv->status_icon, _("Power Manager")); gtk_status_icon_set_visible (manager->priv->status_icon, FALSE); /* connect to UPower for async power operations */ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, UPOWER_DBUS_NAME, UPOWER_DBUS_PATH, UPOWER_DBUS_INTERFACE, NULL, power_proxy_ready_cb, manager); /* connect to UPower for keyboard backlight control */ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, UPOWER_DBUS_NAME, UPOWER_DBUS_PATH_KBDBACKLIGHT, UPOWER_DBUS_INTERFACE_KBDBACKLIGHT, NULL, power_keyboard_proxy_ready_cb, manager); /* connect to the session */ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_PATH, GNOME_SESSION_DBUS_INTERFACE, NULL, session_proxy_ready_cb, manager); g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, 0, NULL, GNOME_SESSION_DBUS_NAME, GNOME_SESSION_DBUS_PATH_PRESENCE, GNOME_SESSION_DBUS_INTERFACE_PRESENCE, NULL, session_presence_proxy_ready_cb, manager); manager->priv->devices_array = g_ptr_array_new_with_free_func (g_object_unref); manager->priv->canberra_context = ca_gtk_context_get_for_screen (gdk_screen_get_default ()); manager->priv->phone = gpm_phone_new (); g_signal_connect (manager->priv->phone, "device-added", G_CALLBACK (phone_device_added_cb), manager); g_signal_connect (manager->priv->phone, "device-removed", G_CALLBACK (phone_device_removed_cb), manager); g_signal_connect (manager->priv->phone, "device-refresh", G_CALLBACK (phone_device_refresh_cb), manager); /* create a fake virtual composite battery */ manager->priv->device_composite = up_device_new (); g_object_set (manager->priv->device_composite, "kind", UP_DEVICE_KIND_BATTERY, "is-rechargeable", TRUE, "native-path", "dummy:composite_battery", "power-supply", TRUE, "is-present", TRUE, NULL); /* get backlight setting overrides */ manager->priv->backlight_helper_preference_args = NULL; backlight_override_settings_refresh (manager); /* get percentage policy */ manager->priv->low_percentage = g_settings_get_int (manager->priv->settings, "percentage-low"); manager->priv->critical_percentage = g_settings_get_int (manager->priv->settings, "percentage-critical"); manager->priv->action_percentage = g_settings_get_int (manager->priv->settings, "percentage-action"); /* get time policy */ manager->priv->low_time = g_settings_get_int (manager->priv->settings, "time-low"); manager->priv->critical_time = g_settings_get_int (manager->priv->settings, "time-critical"); manager->priv->action_time = g_settings_get_int (manager->priv->settings, "time-action"); /* we can disable this if the time remaining is inaccurate or just plain wrong */ manager->priv->use_time_primary = g_settings_get_boolean (manager->priv->settings, "use-time-for-policy"); /* create IDLETIME watcher */ manager->priv->idletime = gpm_idletime_new (); g_signal_connect (manager->priv->idletime, "reset", G_CALLBACK (idle_idletime_reset_cb), manager); g_signal_connect (manager->priv->idletime, "alarm-expired", G_CALLBACK (idle_idletime_alarm_expired_cb), manager); /* set up the screens */ g_signal_connect (manager->priv->x11_screen, "changed", G_CALLBACK (on_randr_event), manager); on_randr_event (manager->priv->x11_screen, manager); /* ensure the default dpms timeouts are cleared */ ret = gnome_rr_screen_set_dpms_mode (manager->priv->x11_screen, GNOME_RR_DPMS_ON, error); if (!ret) { g_warning ("Failed set DPMS mode: %s", (*error)->message); g_clear_error (error); } /* coldplug the engine */ engine_coldplug (manager); /* Make sure that Xorg's DPMS extension never gets in our way. The defaults seem to have changed in Xorg 1.14 * being "0" by default to being "600" by default * https://bugzilla.gnome.org/show_bug.cgi?id=709114 */ gdk_error_trap_push (); int dummy; if (DPMSQueryExtension(GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &dummy, &dummy)) { DPMSSetTimeouts (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), 0, 0, 0); } gdk_error_trap_pop_ignored (); manager->priv->xscreensaver_watchdog_timer_id = g_timeout_add_seconds (XSCREENSAVER_WATCHDOG_TIMEOUT, disable_builtin_screensaver, NULL); /* don't blank inside a VM */ manager->priv->is_virtual_machine = is_hardware_a_virtual_machine (); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_power_manager_stop (CsdPowerManager *manager) { g_debug ("Stopping power manager"); 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->introspection_data) { g_dbus_node_info_unref (manager->priv->introspection_data); manager->priv->introspection_data = NULL; } kill_lid_close_safety_timer (manager); g_signal_handlers_disconnect_by_data (manager->priv->up_client, manager); if (manager->priv->connection != NULL) { g_object_unref (manager->priv->connection); manager->priv->connection = NULL; } if (manager->priv->session != NULL) { g_object_unref (manager->priv->session); manager->priv->session = NULL; } if (manager->priv->settings != NULL) { g_object_unref (manager->priv->settings); manager->priv->settings = NULL; } if (manager->priv->settings_screensaver != NULL) { g_object_unref (manager->priv->settings_screensaver); manager->priv->settings_screensaver = NULL; } if (manager->priv->settings_xrandr != NULL) { g_object_unref (manager->priv->settings_xrandr); manager->priv->settings_xrandr = NULL; } if (manager->priv->settings_session != NULL) { g_object_unref (manager->priv->settings_session); manager->priv->settings_session = NULL; } if (manager->priv->up_client != NULL) { g_object_unref (manager->priv->up_client); manager->priv->up_client = NULL; } if (manager->priv->inhibit_lid_switch_fd != -1) { close (manager->priv->inhibit_lid_switch_fd); manager->priv->inhibit_lid_switch_fd = -1; manager->priv->inhibit_lid_switch_taken = FALSE; } if (manager->priv->inhibit_suspend_fd != -1) { close (manager->priv->inhibit_suspend_fd); manager->priv->inhibit_suspend_fd = -1; manager->priv->inhibit_suspend_taken = FALSE; } if (manager->priv->logind_proxy != NULL) { g_object_unref (manager->priv->logind_proxy); manager->priv->logind_proxy = NULL; } g_free (manager->priv->backlight_helper_preference_args); manager->priv->backlight_helper_preference_args = NULL; if (manager->priv->x11_screen != NULL) { g_object_unref (manager->priv->x11_screen); manager->priv->x11_screen = NULL; } g_ptr_array_unref (manager->priv->devices_array); manager->priv->devices_array = NULL; if (manager->priv->phone != NULL) { g_object_unref (manager->priv->phone); manager->priv->phone = NULL; } if (manager->priv->device_composite != NULL) { g_object_unref (manager->priv->device_composite); manager->priv->device_composite = NULL; } if (manager->priv->previous_icon != NULL) { g_object_unref (manager->priv->previous_icon); manager->priv->previous_icon = NULL; } g_free (manager->priv->previous_summary); manager->priv->previous_summary = NULL; if (manager->priv->upower_proxy != NULL) { g_object_unref (manager->priv->upower_proxy); manager->priv->upower_proxy = NULL; } if (manager->priv->session_proxy != NULL) { g_object_unref (manager->priv->session_proxy); manager->priv->session_proxy = NULL; } if (manager->priv->session_presence_proxy != NULL) { g_object_unref (manager->priv->session_presence_proxy); manager->priv->session_presence_proxy = NULL; } if (manager->priv->critical_alert_timeout_id > 0) { g_source_remove (manager->priv->critical_alert_timeout_id); manager->priv->critical_alert_timeout_id = 0; } g_signal_handlers_disconnect_by_func (manager->priv->idletime, idle_idletime_reset_cb, manager); g_signal_handlers_disconnect_by_func (manager->priv->idletime, idle_idletime_alarm_expired_cb, manager); if (manager->priv->idletime != NULL) { g_object_unref (manager->priv->idletime); manager->priv->idletime = NULL; } if (manager->priv->status_icon != NULL) { g_object_unref (manager->priv->status_icon); manager->priv->status_icon = NULL; } if (manager->priv->xscreensaver_watchdog_timer_id > 0) { g_source_remove (manager->priv->xscreensaver_watchdog_timer_id); manager->priv->xscreensaver_watchdog_timer_id = 0; } } static void csd_power_manager_init (CsdPowerManager *manager) { manager->priv = CSD_POWER_MANAGER_GET_PRIVATE (manager); manager->priv->inhibit_lid_switch_fd = -1; manager->priv->inhibit_suspend_fd = -1; } static void csd_power_manager_finalize (GObject *object) { CsdPowerManager *manager; manager = CSD_POWER_MANAGER (object); g_return_if_fail (manager->priv != NULL); G_OBJECT_CLASS (csd_power_manager_parent_class)->finalize (object); } /* returns new level */ static void handle_method_call_keyboard (CsdPowerManager *manager, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation) { gint step; gint value = -1; gboolean ret; guint percentage; GError *error = NULL; if (g_strcmp0 (method_name, "GetPercentage") == 0) { g_debug ("keyboard get percentage"); ret = upower_kbd_get_percentage (manager, &error); value = manager->priv->kbd_brightness_now; } else if (g_strcmp0 (method_name, "SetPercentage") == 0) { g_debug ("keyboard set percentage"); guint value_tmp; g_variant_get (parameters, "(u)", &value_tmp); ret = upower_kbd_set_brightness (manager, PERCENTAGE_TO_ABS(0, manager->priv->kbd_brightness_max, value_tmp), &error); if (ret) value = value_tmp; } else if (g_strcmp0 (method_name, "StepUp") == 0) { g_debug ("keyboard step up"); step = BRIGHTNESS_STEP_AMOUNT (manager->priv->kbd_brightness_max); value = MIN (manager->priv->kbd_brightness_now + step, manager->priv->kbd_brightness_max); ret = upower_kbd_set_brightness (manager, value, &error); } else if (g_strcmp0 (method_name, "StepDown") == 0) { g_debug ("keyboard step down"); step = BRIGHTNESS_STEP_AMOUNT (manager->priv->kbd_brightness_max); value = MAX (manager->priv->kbd_brightness_now - step, 0); ret = upower_kbd_set_brightness (manager, value, &error); } else if (g_strcmp0 (method_name, "Toggle") == 0) { ret = upower_kbd_toggle (manager, &error); } else { g_assert_not_reached (); } /* return value */ if (!ret) { g_dbus_method_invocation_return_gerror (invocation, error); g_error_free (error); } else { percentage = ABS_TO_PERCENTAGE (0, manager->priv->kbd_brightness_max, value); g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", percentage)); } } static void handle_method_call_screen (CsdPowerManager *manager, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation) { gboolean ret = FALSE; gint value = -1; guint value_tmp; GError *error = NULL; if (g_strcmp0 (method_name, "GetPercentage") == 0) { g_debug ("screen get percentage"); value = backlight_get_percentage (manager, &error); } else if (g_strcmp0 (method_name, "SetPercentage") == 0) { g_debug ("screen set percentage"); g_variant_get (parameters, "(u)", &value_tmp); ret = backlight_set_percentage (manager, value_tmp, TRUE, &error); if (ret) value = value_tmp; } else if (g_strcmp0 (method_name, "StepUp") == 0) { g_debug ("screen step up"); value = backlight_step_up (manager, &error); } else if (g_strcmp0 (method_name, "StepDown") == 0) { g_debug ("screen step down"); value = backlight_step_down (manager, &error); } else { g_assert_not_reached (); } /* return value */ if (value < 0) { g_dbus_method_invocation_return_gerror (invocation, error); g_error_free (error); } else { g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", value)); } } static GVariant * device_to_variant_blob (UpDevice *device) { const gchar *object_path, *vendor, *model; gchar *device_icon; gdouble percentage; GIcon *icon; guint64 time_empty, time_full; guint64 time_state = 0; GVariant *value; UpDeviceKind kind; UpDeviceState state; icon = gpm_upower_get_device_icon (device, TRUE); device_icon = g_icon_to_string (icon); g_object_get (device, "vendor", &vendor, "model", &model, "kind", &kind, "percentage", &percentage, "state", &state, "time-to-empty", &time_empty, "time-to-full", &time_full, NULL); /* only return time for these simple states */ if (state == UP_DEVICE_STATE_DISCHARGING) time_state = time_empty; else if (state == UP_DEVICE_STATE_CHARGING) time_state = time_full; /* get an object path, even for the composite device */ object_path = up_device_get_object_path (device); if (object_path == NULL) object_path = CSD_DBUS_PATH; /* format complex object */ value = g_variant_new ("(sssusdut)", object_path, vendor, model, kind, device_icon, percentage, state, time_state); g_free (device_icon); g_object_unref (icon); return value; } static void handle_method_call_main (CsdPowerManager *manager, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation) { GPtrArray *array; guint i; GVariantBuilder *builder; GVariant *tuple = NULL; GVariant *value = NULL; UpDevice *device; /* return object */ if (g_strcmp0 (method_name, "GetPrimaryDevice") == 0) { /* get the virtual device */ device = engine_get_primary_device (manager); if (device == NULL) { g_dbus_method_invocation_return_dbus_error (invocation, "org.cinnamon.SettingsDaemon.Power.Failed", "There is no primary device."); return; } /* return the value */ value = device_to_variant_blob (device); tuple = g_variant_new_tuple (&value, 1); g_dbus_method_invocation_return_value (invocation, tuple); g_object_unref (device); return; } /* return array */ if (g_strcmp0 (method_name, "GetDevices") == 0) { /* create builder */ builder = g_variant_builder_new (G_VARIANT_TYPE("a(sssusdut)")); /* add each tuple to the array */ array = manager->priv->devices_array; for (i=0; ilen; i++) { device = g_ptr_array_index (array, i); value = device_to_variant_blob (device); g_variant_builder_add_value (builder, value); } /* return the value */ value = g_variant_builder_end (builder); tuple = g_variant_new_tuple (&value, 1); g_dbus_method_invocation_return_value (invocation, tuple); g_variant_builder_unref (builder); return; } g_assert_not_reached (); } 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) { CsdPowerManager *manager = CSD_POWER_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 Power", interface_name, method_name); if (g_strcmp0 (interface_name, CSD_POWER_DBUS_INTERFACE) == 0) { handle_method_call_main (manager, method_name, parameters, invocation); } else if (g_strcmp0 (interface_name, CSD_POWER_DBUS_INTERFACE_SCREEN) == 0) { handle_method_call_screen (manager, method_name, parameters, invocation); } else if (g_strcmp0 (interface_name, CSD_POWER_DBUS_INTERFACE_KEYBOARD) == 0) { handle_method_call_keyboard (manager, method_name, parameters, invocation); } else { g_warning ("not recognised interface: %s", interface_name); } } static GVariant * handle_get_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data) { CsdPowerManager *manager = CSD_POWER_MANAGER (user_data); GVariant *retval = NULL; /* Check session pointer as a proxy for whether the manager is in the start or stop state */ if (manager->priv->session == NULL) { return NULL; } if (g_strcmp0 (property_name, "Icon") == 0) { retval = engine_get_icon_property_variant (manager); } else if (g_strcmp0 (property_name, "Tooltip") == 0) { retval = engine_get_tooltip_property_variant (manager); } return retval; } static const GDBusInterfaceVTable interface_vtable = { handle_method_call, handle_get_property, NULL, /* SetProperty */ }; static void on_bus_gotten (GObject *source_object, GAsyncResult *res, CsdPowerManager *manager) { GDBusConnection *connection; GDBusInterfaceInfo **infos; GError *error = NULL; guint i; 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; for (i = 0; infos[i] != NULL; i++) { g_dbus_connection_register_object (connection, CSD_POWER_DBUS_PATH, infos[i], &interface_vtable, manager, NULL, NULL); } } static void register_manager_dbus (CsdPowerManager *manager) { manager->priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); manager->priv->bus_cancellable = g_cancellable_new (); g_assert (manager->priv->introspection_data != NULL); g_bus_get (G_BUS_TYPE_SESSION, manager->priv->bus_cancellable, (GAsyncReadyCallback) on_bus_gotten, manager); } CsdPowerManager * csd_power_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_POWER_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); register_manager_dbus (manager_object); } return CSD_POWER_MANAGER (manager_object); } cinnamon-settings-daemon-2.8.3/plugins/power/gpm-common.h0000664000175000017500000000371712625665665022443 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2005-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef __GPMCOMMON_H #define __GPMCOMMON_H #include #include G_BEGIN_DECLS gchar *gpm_get_timestring (guint time); const gchar *gpm_device_to_localised_string (UpDevice *device); const gchar *gpm_device_kind_to_localised_string (UpDeviceKind kind, guint number); const gchar *gpm_device_kind_to_icon (UpDeviceKind kind); const gchar *gpm_device_technology_to_localised_string (UpDeviceTechnology technology_enum); const gchar *gpm_device_state_to_localised_string (UpDeviceState state); GIcon *gpm_upower_get_device_icon (UpDevice *device, gboolean use_symbolic); gchar *gpm_upower_get_device_summary (UpDevice *device); gchar *gpm_upower_get_device_description (UpDevice *device); G_END_DECLS #endif /* __GPMCOMMON_H */ cinnamon-settings-daemon-2.8.3/plugins/power/gpm-phone.c0000664000175000017500000002633212625665665022255 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include "gpm-phone.h" static void gpm_phone_finalize (GObject *object); #define GPM_PHONE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_TYPE_PHONE, GpmPhonePrivate)) struct GpmPhonePrivate { GDBusProxy *proxy; GDBusConnection *connection; guint watch_id; gboolean present; guint percentage; gboolean onac; }; enum { DEVICE_ADDED, DEVICE_REMOVED, DEVICE_REFRESH, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0 }; static gpointer gpm_phone_object = NULL; G_DEFINE_TYPE (GpmPhone, gpm_phone, G_TYPE_OBJECT) gboolean gpm_phone_coldplug (GpmPhone *phone) { GError *error = NULL; GVariant *reply; gboolean ret; g_return_val_if_fail (phone != NULL, FALSE); g_return_val_if_fail (GPM_IS_PHONE (phone), FALSE); if (phone->priv->proxy == NULL) return FALSE; reply = g_dbus_proxy_call_sync (phone->priv->proxy, "Coldplug", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (error != NULL) { g_warning ("DEBUG: ERROR: %s", error->message); g_error_free (error); } if (reply != NULL) { ret = TRUE; g_variant_unref (reply); } else ret = FALSE; return ret; } gboolean gpm_phone_get_present (GpmPhone *phone, guint idx) { g_return_val_if_fail (phone != NULL, FALSE); g_return_val_if_fail (GPM_IS_PHONE (phone), FALSE); return phone->priv->present; } guint gpm_phone_get_percentage (GpmPhone *phone, guint idx) { g_return_val_if_fail (phone != NULL, 0); g_return_val_if_fail (GPM_IS_PHONE (phone), 0); return phone->priv->percentage; } gboolean gpm_phone_get_on_ac (GpmPhone *phone, guint idx) { g_return_val_if_fail (phone != NULL, FALSE); g_return_val_if_fail (GPM_IS_PHONE (phone), FALSE); return phone->priv->onac; } guint gpm_phone_get_num_batteries (GpmPhone *phone) { g_return_val_if_fail (phone != NULL, 0); g_return_val_if_fail (GPM_IS_PHONE (phone), 0); if (phone->priv->present) return 1; return 0; } static void gpm_phone_battery_state_changed (GDBusProxy *proxy, guint idx, guint percentage, gboolean on_ac, GpmPhone *phone) { g_return_if_fail (GPM_IS_PHONE (phone)); g_debug ("got BatteryStateChanged %i = %i (%i)", idx, percentage, on_ac); phone->priv->percentage = percentage; phone->priv->onac = on_ac; phone->priv->present = TRUE; g_debug ("emitting device-refresh : (%i)", idx); g_signal_emit (phone, signals [DEVICE_REFRESH], 0, idx); } static void gpm_phone_num_batteries_changed (GDBusProxy *proxy, guint number, GpmPhone *phone) { g_return_if_fail (GPM_IS_PHONE (phone)); g_debug ("got NumberBatteriesChanged %i", number); if (number > 1) { g_warning ("number not 0 or 1, not valid!"); return; } /* are we removed? */ if (number == 0) { phone->priv->present = FALSE; phone->priv->percentage = 0; phone->priv->onac = FALSE; g_debug ("emitting device-removed : (%i)", 0); g_signal_emit (phone, signals [DEVICE_REMOVED], 0, 0); return; } if (phone->priv->present) { g_warning ("duplicate NumberBatteriesChanged with no change"); return; } /* reset to defaults until we get BatteryStateChanged */ phone->priv->present = TRUE; phone->priv->percentage = 0; phone->priv->onac = FALSE; g_debug ("emitting device-added : (%i)", 0); g_signal_emit (phone, signals [DEVICE_ADDED], 0, 0); } static void gpm_phone_generic_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, gpointer user_data) { GpmPhone *self = GPM_PHONE (user_data); if (!g_strcmp0 (signal_name, "BatteryStateChanged")) { guint idx, percentage; gboolean on_ac; g_variant_get (parameters, "(uub)", &idx, &percentage, &on_ac); gpm_phone_battery_state_changed (proxy, idx, percentage, on_ac, self); return; } if (!g_strcmp0 (signal_name, "NumberBatteriesChanged")) { guint number; g_variant_get (parameters, "(u)", &number); gpm_phone_num_batteries_changed (proxy, number, self); return; } /* not a signal we're interested in */ } static void gpm_phone_class_init (GpmPhoneClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gpm_phone_finalize; g_type_class_add_private (klass, sizeof (GpmPhonePrivate)); signals [DEVICE_ADDED] = g_signal_new ("device-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmPhoneClass, device_added), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [DEVICE_REMOVED] = g_signal_new ("device-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmPhoneClass, device_removed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [DEVICE_REFRESH] = g_signal_new ("device-refresh", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GpmPhoneClass, device_refresh), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); } static void gpm_phone_service_appeared_cb (GDBusConnection *connection, const gchar *name, const gchar *name_owner, GpmPhone *phone) { GError *error = NULL; g_return_if_fail (GPM_IS_PHONE (phone)); if (phone->priv->connection == NULL) { g_debug ("get connection"); g_clear_error (&error); phone->priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); if (phone->priv->connection == NULL) { g_warning ("Could not connect to DBUS daemon: %s", error->message); g_error_free (error); phone->priv->connection = NULL; return; } } if (phone->priv->proxy == NULL) { g_debug ("get proxy"); g_clear_error (&error); phone->priv->proxy = g_dbus_proxy_new_sync (phone->priv->connection, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, CINNAMON_PHONE_MANAGER_DBUS_SERVICE, CINNAMON_PHONE_MANAGER_DBUS_PATH, CINNAMON_PHONE_MANAGER_DBUS_INTERFACE, NULL, &error); if (phone->priv->proxy == NULL) { g_warning ("Cannot connect, maybe the daemon is not running: %s", error->message); g_error_free (error); phone->priv->proxy = NULL; return; } g_signal_connect (phone->priv->proxy, "g-signal", G_CALLBACK(gpm_phone_generic_signal_cb), phone); } } static void gpm_phone_service_vanished_cb (GDBusConnection *connection, const gchar *name, GpmPhone *phone) { g_return_if_fail (GPM_IS_PHONE (phone)); if (phone->priv->proxy == NULL) return; g_debug ("removing proxy"); g_object_unref (phone->priv->proxy); phone->priv->proxy = NULL; if (phone->priv->present) { phone->priv->present = FALSE; phone->priv->percentage = 0; g_debug ("emitting device-removed : (%i)", 0); g_signal_emit (phone, signals [DEVICE_REMOVED], 0, 0); } } static void gpm_phone_init (GpmPhone *phone) { phone->priv = GPM_PHONE_GET_PRIVATE (phone); phone->priv->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, CINNAMON_PHONE_MANAGER_DBUS_SERVICE, G_BUS_NAME_WATCHER_FLAGS_NONE, (GBusNameAppearedCallback) gpm_phone_service_appeared_cb, (GBusNameVanishedCallback) gpm_phone_service_vanished_cb, phone, NULL); } static void gpm_phone_finalize (GObject *object) { GpmPhone *phone; g_return_if_fail (GPM_IS_PHONE (object)); phone = GPM_PHONE (object); phone->priv = GPM_PHONE_GET_PRIVATE (phone); if (phone->priv->proxy != NULL) g_object_unref (phone->priv->proxy); g_bus_unwatch_name (phone->priv->watch_id); G_OBJECT_CLASS (gpm_phone_parent_class)->finalize (object); } GpmPhone * gpm_phone_new (void) { if (gpm_phone_object != NULL) { g_object_ref (gpm_phone_object); } else { gpm_phone_object = g_object_new (GPM_TYPE_PHONE, NULL); g_object_add_weak_pointer (gpm_phone_object, &gpm_phone_object); } return GPM_PHONE (gpm_phone_object); } cinnamon-settings-daemon-2.8.3/plugins/power/org.cinnamon.settings-daemon.plugins.power.policy.in.in0000664000175000017500000000223512625665665032751 0ustar fabiofabio Cinnamon Settings Daemon http://git.gnome.org/browse/cinnamon-settings-daemon battery <_description>Modify the laptop brightness <_message>Authentication is required to modify the laptop brightness no no yes @libexecdir@/csd-backlight-helper cinnamon-settings-daemon-2.8.3/plugins/power/csd-backlight-helper.c0000664000175000017500000001622712625665665024341 0ustar fabiofabio/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2010-2011 Richard Hughes * * Licensed under the GNU General Public License Version 2 * * 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, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #define CSD_BACKLIGHT_HELPER_EXIT_CODE_SUCCESS 0 #define CSD_BACKLIGHT_HELPER_EXIT_CODE_FAILED 1 #define CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID 3 #define CSD_BACKLIGHT_HELPER_EXIT_CODE_INVALID_USER 4 #define CSD_BACKLIGHT_HELPER_EXIT_CODE_NO_DEVICES 5 #define CSD_POWER_SETTINGS_SCHEMA "org.cinnamon.settings-daemon.plugins.power" static gchar * csd_backlight_helper_get_type (GList *devices, const gchar *type) { const gchar *type_tmp; GList *d; for (d = devices; d != NULL; d = d->next) { type_tmp = g_udev_device_get_sysfs_attr (d->data, "type"); if (g_strcmp0 (type_tmp, type) == 0) return g_strdup (g_udev_device_get_sysfs_path (d->data)); } return NULL; } static gchar * csd_backlight_helper_get_best_backlight (gchar** preference_list) { gchar *path = NULL; GList *devices; GUdevClient *client; client = g_udev_client_new (NULL); devices = g_udev_client_query_by_subsystem (client, "backlight"); if (devices == NULL) goto out; /* setup our gsettings interface */ if (preference_list[0] == NULL) g_print("%s\n%s\n", "Warning: no backlight sources have been configured.", "Check " CSD_POWER_SETTINGS_SCHEMA " to configure some."); int i = 0; for (i=0; preference_list[i] != NULL; i++) { path = csd_backlight_helper_get_type (devices, preference_list[i]); if (path != NULL) goto out; } out: g_object_unref (client); g_list_foreach (devices, (GFunc) g_object_unref, NULL); g_list_free (devices); return path; } static gboolean csd_backlight_helper_write (const gchar *filename, gint value, GError **error) { gchar *text = NULL; gint retval; gint length; gint fd = -1; gboolean ret = TRUE; fd = open (filename, O_WRONLY); if (fd < 0) { ret = FALSE; g_set_error (error, 1, 0, "failed to open filename: %s", filename); goto out; } /* convert to text */ text = g_strdup_printf ("%i", value); length = strlen (text); /* write to device file */ retval = write (fd, text, length); if (retval != length) { ret = FALSE; g_set_error (error, 1, 0, "writing '%s' to %s failed", text, filename); goto out; } out: if (fd >= 0) close (fd); g_free (text); return ret; } int main (int argc, char *argv[]) { GOptionContext *context; gint uid; gint euid; guint retval = 0; GError *error = NULL; gboolean ret = FALSE; gint set_brightness = -1; gboolean get_brightness = FALSE; gboolean get_max_brightness = FALSE; gchar *filename = NULL; gchar *filename_file = NULL; gchar *contents = NULL; gchar** backlight_preference_order = NULL; const GOptionEntry options[] = { { "set-brightness", '\0', 0, G_OPTION_ARG_INT, &set_brightness, /* command line argument */ "Set the current brightness", NULL }, { "get-brightness", '\0', 0, G_OPTION_ARG_NONE, &get_brightness, /* command line argument */ "Get the current brightness", NULL }, { "get-max-brightness", '\0', 0, G_OPTION_ARG_NONE, &get_max_brightness, /* command line argument */ "Get the number of brightness levels supported", NULL }, { "backlight-preference", 'b', 0, G_OPTION_ARG_STRING_ARRAY, &backlight_preference_order, /* command line argument */ "Set a backlight control search preference", NULL }, { NULL} }; /* setup type system */ g_type_init (); context = g_option_context_new (NULL); g_option_context_set_summary (context, "Cinnamon Settings Daemon Backlight Helper"); g_option_context_add_main_entries (context, options, NULL); g_option_context_parse (context, &argc, &argv, NULL); g_option_context_free (context); #ifndef __linux__ /* the g-s-d plugin should only call this helper on linux */ g_critical ("Attempting to call gsb-backlight-helper on non-Linux"); g_assert_not_reached (); #endif /* no input */ if (set_brightness == -1 && !get_brightness && !get_max_brightness) { g_print ("%s\n", "No valid option was specified"); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID; goto out; } /* find device */ filename = csd_backlight_helper_get_best_backlight (backlight_preference_order); if (filename == NULL) { retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_NO_DEVICES; g_print ("%s: %s\n", "Could not get or set the value of the backlight", "No backlight devices present"); goto out; } /* GetBrightness */ if (get_brightness) { filename_file = g_build_filename (filename, "brightness", NULL); ret = g_file_get_contents (filename_file, &contents, NULL, &error); if (!ret) { g_print ("%s: %s\n", "Could not get the value of the backlight", error->message); g_error_free (error); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID; goto out; } /* just print the contents to stdout */ g_print ("%s", contents); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_SUCCESS; goto out; } /* GetSteps */ if (get_max_brightness) { filename_file = g_build_filename (filename, "max_brightness", NULL); ret = g_file_get_contents (filename_file, &contents, NULL, &error); if (!ret) { g_print ("%s: %s\n", "Could not get the maximum value of the backlight", error->message); g_error_free (error); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID; goto out; } /* just print the contents to stdout */ g_print ("%s", contents); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_SUCCESS; goto out; } /* check calling UID */ uid = getuid (); euid = geteuid (); if (uid != 0 || euid != 0) { g_print ("%s\n", "This program can only be used by the root user"); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID; goto out; } /* SetBrightness */ if (set_brightness != -1) { filename_file = g_build_filename (filename, "brightness", NULL); ret = csd_backlight_helper_write (filename_file, set_brightness, &error); if (!ret) { g_print ("%s: %s\n", "Could not set the value of the backlight", error->message); g_error_free (error); retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_ARGUMENTS_INVALID; goto out; } } /* success */ retval = CSD_BACKLIGHT_HELPER_EXIT_CODE_SUCCESS; out: g_free (filename); g_free (filename_file); g_free (contents); return retval; } cinnamon-settings-daemon-2.8.3/plugins/power/Makefile.am0000664000175000017500000000524712625665665022255 0ustar fabiofabioplugin_name = power plugin_LTLIBRARIES = \ libpower.la libpower_la_SOURCES = \ gpm-common.c \ gpm-common.h \ gpm-phone.c \ gpm-phone.h \ gpm-idletime.c \ gpm-idletime.h \ csd-power-manager.c \ csd-power-manager.h \ csd-power-plugin.c \ csd-power-plugin.h libpower_la_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DSBINDIR=\"$(sbindir)\" \ -DLIBEXECDIR=\"$(libexecdir)\" \ $(AM_CPPFLAGS) libpower_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(POWER_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) libpower_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) libpower_la_LIBADD = \ $(top_builddir)/plugins/common/libcommon.la \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(POWER_LIBS) \ $(SETTINGS_PLUGIN_LIBS) plugin_in_files = \ power.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) org.cinnamon.settings-daemon.plugins.power.policy.in: org.cinnamon.settings-daemon.plugins.power.policy.in.in Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ @INTLTOOL_POLICY_RULE@ polkit_policydir = $(datadir)/polkit-1/actions polkit_policy_in_files = org.cinnamon.settings-daemon.plugins.power.policy.in polkit_policy_DATA = $(polkit_policy_in_files:.policy.in=.policy) # so it always gets included in the tarball csd_backlight_helper_SOURCES = \ csd-backlight-helper.c libexec_PROGRAMS = csd-test-power csd_test_power_SOURCES = \ gpm-common.c \ gpm-common.h \ gpm-phone.c \ gpm-phone.h \ gpm-idletime.c \ gpm-idletime.h \ csd-power-manager.c \ csd-power-manager.h \ test-power.c csd_test_power_CFLAGS = $(libpower_la_CFLAGS) csd_test_power_CPPFLAGS = $(libpower_la_CPPFLAGS) csd_test_power_LDADD = \ -lm \ $(top_builddir)/plugins/common/libcommon.la \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(POWER_LIBS) \ $(SETTINGS_PLUGIN_LIBS) EXTRA_DIST = \ $(plugin_in_files) \ $(csd_backlight_helper_SOURCES) if HAVE_GUDEV libexec_PROGRAMS += \ csd-backlight-helper csd_backlight_helper_LDFLAGS = \ $(BACKLIGHT_HELPER_LIBS) \ -lm csd_backlight_helper_CFLAGS = \ $(BACKLIGHT_HELPER_CFLAGS) EXTRA_DIST += \ org.cinnamon.settings-daemon.plugins.power.policy.in.in endif clean-local: rm -f *~ CLEANFILES = \ $(plugin_DATA) \ org.cinnamon.settings-daemon.plugins.power.policy \ org.cinnamon.settings-daemon.plugins.power.policy.in @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/Makefile.am0000664000175000017500000000140312625665665021107 0ustar fabiofabioNULL = enabled_plugins = \ a11y-keyboard \ a11y-settings \ automount \ background \ clipboard \ color \ cursor \ dummy \ datetime \ power \ housekeeping \ keyboard \ media-keys \ mouse \ screensaver-proxy \ sound \ xrandr \ xsettings \ $(NULL) disabled_plugins = $(NULL) if BUILD_WACOM enabled_plugins += wacom else disabled_plugins += wacom endif if SMARTCARD_SUPPORT enabled_plugins += smartcard else disabled_plugins += smartcard endif if HAVE_GUDEV enabled_plugins += orientation else disabled_plugins += orientation endif if BUILD_PRINT_NOTIFICATIONS enabled_plugins += print-notifications else disabled_plugins += print-notifications endif SUBDIRS = common $(enabled_plugins) DIST_SUBDIRS = $(SUBDIRS) $(disabled_plugins) cinnamon-settings-daemon-2.8.3/plugins/orientation/0000775000175000017500000000000012625665665021410 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/orientation/orientation.cinnamon-settings-plugin.in0000664000175000017500000000024312625665665031225 0ustar fabiofabio[Cinnamon Settings Plugin] Module=orientation IAge=0 _Name=Orientation _Description=Orientation plugin Authors=Peter Hutterer Copyright=Copyright © 2010 Website= cinnamon-settings-daemon-2.8.3/plugins/orientation/csd-orientation-manager.h0000664000175000017500000000472312625665665026301 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-2.8.3/plugins/orientation/csd-orientation-manager.c0000664000175000017500000004656412625665665026305 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 #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 { guint start_idle_id; /* Accelerometer */ char *sysfs_path; OrientationUp prev_orientation; /* DBus */ GDBusNodeInfo *introspection_data; GDBusConnection *connection; GDBusProxy *xrandr_proxy; GCancellable *cancellable; /* Notifications */ GUdevClient *client; GSettings *settings; gboolean orientation_lock; }; #define CONF_SCHEMA "org.cinnamon.settings-daemon.peripherals.touchscreen" #define ORIENTATION_LOCK_KEY "orientation-lock" #define CSD_DBUS_PATH "/org/cinnamon/SettingsDaemon" #define CSD_ORIENTATION_DBUS_PATH CSD_DBUS_PATH "/Orientation" static const gchar introspection_xml[] = "" " " " " " " ""; static void csd_orientation_manager_class_init (CsdOrientationManagerClass *klass); static void csd_orientation_manager_init (CsdOrientationManager *orientation_manager); 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 GObject * csd_orientation_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdOrientationManager *orientation_manager; orientation_manager = CSD_ORIENTATION_MANAGER (G_OBJECT_CLASS (csd_orientation_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (orientation_manager); } static void csd_orientation_manager_dispose (GObject *object) { G_OBJECT_CLASS (csd_orientation_manager_parent_class)->dispose (object); } static void csd_orientation_manager_class_init (CsdOrientationManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_orientation_manager_constructor; object_class->dispose = csd_orientation_manager_dispose; 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 (GUdevDevice *dev) { const char *value; value = g_udev_device_get_property (dev, "ID_INPUT_ACCELEROMETER_ORIENTATION"); if (value == NULL) { g_debug ("Couldn't find orientation for accelerometer %s", g_udev_device_get_sysfs_path (dev)); return ORIENTATION_UNDEFINED; } g_debug ("Found orientation '%s' for accelerometer %s", value, g_udev_device_get_sysfs_path (dev)); return orientation_from_string (value); } 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_object_unref (manager->priv->cancellable); manager->priv->cancellable = NULL; if (error != 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->connection == NULL || 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 client_uevent_cb (GUdevClient *client, gchar *action, GUdevDevice *device, CsdOrientationManager *manager) { const char *sysfs_path; OrientationUp orientation; sysfs_path = g_udev_device_get_sysfs_path (device); g_debug ("Received uevent '%s' from '%s'", action, sysfs_path); if (manager->priv->orientation_lock) return; if (g_str_equal (action, "change") == FALSE) return; if (g_strcmp0 (manager->priv->sysfs_path, sysfs_path) != 0) return; g_debug ("Received an event from the accelerometer"); orientation = get_orientation_from_device (device); if (orientation != manager->priv->prev_orientation) { manager->priv->prev_orientation = orientation; g_debug ("Orientation changed to '%s', switching screen rotation", orientation_to_string (manager->priv->prev_orientation)); do_rotation (manager); } } static void orientation_lock_changed_cb (GSettings *settings, gchar *key, CsdOrientationManager *manager) { gboolean new; new = g_settings_get_boolean (settings, 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 xrandr_ready_cb (GObject *source_object, GAsyncResult *res, CsdOrientationManager *manager) { 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); } } static void on_bus_gotten (GObject *source_object, GAsyncResult *res, CsdOrientationManager *manager) { GDBusConnection *connection; GError *error = NULL; 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, CSD_ORIENTATION_DBUS_PATH, manager->priv->introspection_data->interfaces[0], NULL, NULL, NULL, NULL); g_dbus_proxy_new (manager->priv->connection, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.cinnamon.SettingsDaemon", "/org/cinnamon/SettingsDaemon/XRANDR", "org.cinnamon.SettingsDaemon.XRANDR_2", NULL, (GAsyncReadyCallback) xrandr_ready_cb, manager); } static GUdevDevice * get_accelerometer (GUdevClient *client) { GList *list, *listiio, *l; GUdevDevice *ret, *parent; /* Look for a device with the ID_INPUT_ACCELEROMETER=1 property */ ret = NULL; list = g_udev_client_query_by_subsystem (client, "input"); listiio = g_udev_client_query_by_subsystem (client, "iio"); list = g_list_concat(list, listiio); for (l = list; l != NULL; l = l->next) { GUdevDevice *dev; dev = l->data; if (g_udev_device_get_property_as_boolean (dev, "ID_INPUT_ACCELEROMETER")) { ret = dev; continue; } g_object_unref (dev); } g_list_free (list); if (ret == NULL) return NULL; /* Now walk up to the parent */ parent = g_udev_device_get_parent (ret); if (parent == NULL) return ret; if (g_udev_device_get_property_as_boolean (parent, "ID_INPUT_ACCELEROMETER")) { g_object_unref (ret); ret = parent; } else { g_object_unref (parent); } return ret; } 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 gboolean csd_orientation_manager_idle_cb (CsdOrientationManager *manager) { const char * const subsystems[] = { "input", NULL }; GUdevDevice *dev; cinnamon_settings_profile_start (NULL); manager->priv->settings = g_settings_new (CONF_SCHEMA); manager->priv->orientation_lock = g_settings_get_boolean (manager->priv->settings, ORIENTATION_LOCK_KEY); g_signal_connect (G_OBJECT (manager->priv->settings), "changed::orientation-lock", G_CALLBACK (orientation_lock_changed_cb), manager); manager->priv->client = g_udev_client_new (subsystems); dev = get_accelerometer (manager->priv->client); if (dev == NULL) { g_debug ("Did not find an accelerometer"); cinnamon_settings_profile_end (NULL); return FALSE; } manager->priv->sysfs_path = g_strdup (g_udev_device_get_sysfs_path (dev)); g_debug ("Found accelerometer at sysfs path '%s'", manager->priv->sysfs_path); manager->priv->prev_orientation = get_orientation_from_device (dev); /* Poll the sysfs attributes exposed by MPU6050 as it is not an uevent based input driver */ if (g_strcmp0 (g_udev_device_get_sysfs_attr (dev, "name"), "mpu6050") == 0) { manager->priv->prev_orientation = ORIENTATION_NORMAL; g_timeout_add_seconds(MPU_POLL_INTERVAL, (GSourceFunc) mpu_timer, manager); mpu6050_accel_x = g_build_filename(manager->priv->sysfs_path, "in_accel_x_raw", NULL); mpu6050_accel_y = g_build_filename(manager->priv->sysfs_path, "in_accel_y_raw", NULL); is_mpu6050 = TRUE; } g_object_unref (dev); /* Start process of owning a D-Bus name */ g_bus_get (G_BUS_TYPE_SESSION, NULL, (GAsyncReadyCallback) on_bus_gotten, manager); g_signal_connect (G_OBJECT (manager->priv->client), "uevent", G_CALLBACK (client_uevent_cb), manager); cinnamon_settings_profile_end (NULL); return FALSE; } gboolean csd_orientation_manager_start (CsdOrientationManager *manager, GError **error) { cinnamon_settings_profile_start (NULL); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) csd_orientation_manager_idle_cb, manager); manager->priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); g_assert (manager->priv->introspection_data != 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->settings) { g_object_unref (p->settings); p->settings = NULL; } if (p->sysfs_path) { g_free (p->sysfs_path); p->sysfs_path = NULL; } if (p->introspection_data) { g_dbus_node_info_unref (p->introspection_data); p->introspection_data = NULL; } if (p->client) { g_object_unref (p->client); p->client = NULL; } } 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); if (orientation_manager->priv->start_idle_id != 0) { g_source_remove (orientation_manager->priv->start_idle_id); orientation_manager->priv->start_idle_id = 0; } 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-2.8.3/plugins/orientation/test-orientation.c0000664000175000017500000000034312625665665025064 0ustar fabiofabio#define NEW csd_orientation_manager_new #define START csd_orientation_manager_start #define STOP csd_orientation_manager_stop #define MANAGER CsdOrientationManager #include "csd-orientation-manager.h" #include "test-plugin.h" cinnamon-settings-daemon-2.8.3/plugins/orientation/csd-orientation-plugin.h0000664000175000017500000000447712625665665026173 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, 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_PLUGIN_H__ #define __CSD_ORIENTATION_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_ORIENTATION_PLUGIN (csd_orientation_plugin_get_type ()) #define CSD_ORIENTATION_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_ORIENTATION_PLUGIN, CsdOrientationPlugin)) #define CSD_ORIENTATION_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_ORIENTATION_PLUGIN, CsdOrientationPluginClass)) #define CSD_IS_ORIENTATION_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_ORIENTATION_PLUGIN)) #define CSD_IS_ORIENTATION_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_ORIENTATION_PLUGIN)) #define CSD_ORIENTATION_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_ORIENTATION_PLUGIN, CsdOrientationPluginClass)) typedef struct CsdOrientationPluginPrivate CsdOrientationPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdOrientationPluginPrivate *priv; } CsdOrientationPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdOrientationPluginClass; GType csd_orientation_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_ORIENTATION_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/orientation/Makefile.am0000664000175000017500000000320412625665665023443 0ustar fabiofabioplugin_name = orientation libexec_PROGRAMS = csd-test-orientation csd_test_orientation_SOURCES = \ csd-orientation-manager.h \ csd-orientation-manager.c \ test-orientation.c csd_test_orientation_CFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(ORIENTATION_CFLAGS) \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) csd_test_orientation_LDADD = \ $(top_builddir)/cinnamon-settings-daemon/libcsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(ORIENTATION_LIBS) \ $(SETTINGS_PLUGIN_LIBS) plugin_LTLIBRARIES = liborientation.la liborientation_la_SOURCES = \ csd-orientation-plugin.h \ csd-orientation-plugin.c \ csd-orientation-manager.h \ csd-orientation-manager.c liborientation_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common/ \ -I$(top_srcdir)/data/ \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) liborientation_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(ORIENTATION_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) liborientation_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) liborientation_la_LIBADD = \ $(top_builddir)/plugins/common/libcommon.la \ $(ORIENTATION_LIBS) \ $(SETTINGS_PLUGIN_LIBS) plugin_in_files = orientation.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = $(plugin_in_files) CLEANFILES = $(plugin_DATA) DISTCLEANFILES = $(plugin_DATA) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/orientation/csd-orientation-plugin.c0000664000175000017500000000643212625665665026157 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, 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 "cinnamon-settings-plugin.h" #include "csd-orientation-plugin.h" #include "csd-orientation-manager.h" struct CsdOrientationPluginPrivate { CsdOrientationManager *manager; }; #define CSD_ORIENTATION_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_ORIENTATION_PLUGIN, CsdOrientationPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdOrientationPlugin, csd_orientation_plugin) static void csd_orientation_plugin_init (CsdOrientationPlugin *plugin) { plugin->priv = CSD_ORIENTATION_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdOrientationPlugin initializing"); plugin->priv->manager = csd_orientation_manager_new (); } static void csd_orientation_plugin_finalize (GObject *object) { CsdOrientationPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_ORIENTATION_PLUGIN (object)); g_debug ("CsdOrientationPlugin finalizing"); plugin = CSD_ORIENTATION_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_orientation_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating orientation plugin"); error = NULL; res = csd_orientation_manager_start (CSD_ORIENTATION_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start orientation manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating orientation plugin"); csd_orientation_manager_stop (CSD_ORIENTATION_PLUGIN (plugin)->priv->manager); } static void csd_orientation_plugin_class_init (CsdOrientationPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_orientation_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdOrientationPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/cursor/0000775000175000017500000000000012625665665020372 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/cursor/cursor.cinnamon-settings-plugin.in0000664000175000017500000000031312625665665027167 0ustar fabiofabio[Cinnamon Settings Plugin] Module=cursor IAge=0 _Name=Cursor _Description=Show/hide cursor on tablet devices Authors=Bastien Nocera Copyright=Copyright © 2011 Red Hat, Inc. Website= cinnamon-settings-daemon-2.8.3/plugins/cursor/csd-cursor-manager.c0000664000175000017500000002766212625665665024247 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 #include #include #include #include #include #include #include "cinnamon-settings-profile.h" #include "csd-cursor-manager.h" #include "csd-input-helper.h" #define XFIXES_CURSOR_HIDING_MAJOR 4 #define CSD_CURSOR_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_CURSOR_MANAGER, CsdCursorManagerPrivate)) struct CsdCursorManagerPrivate { guint start_idle_id; guint added_id; guint removed_id; gboolean cursor_shown; }; enum { PROP_0, }; static void csd_cursor_manager_class_init (CsdCursorManagerClass *klass); static void csd_cursor_manager_init (CsdCursorManager *cursor_manager); static void csd_cursor_manager_finalize (GObject *object); G_DEFINE_TYPE (CsdCursorManager, csd_cursor_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static gboolean device_is_xtest (XDevice *xdevice) { Atom realtype, prop; int realformat; unsigned long nitems, bytes_after; unsigned char *data; prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "XTEST Device", False); if (!prop) return FALSE; gdk_error_trap_push (); 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_error_trap_pop_ignored (); XFree (data); return TRUE; } gdk_error_trap_pop_ignored (); return FALSE; } static void set_cursor_visibility (CsdCursorManager *manager, gboolean visible) { Display *xdisplay; GdkDisplay *display; guint n_screens; guint i; g_debug ("Attempting to %s the cursor", visible ? "show" : "hide"); display = gdk_display_get_default (); xdisplay = GDK_DISPLAY_XDISPLAY (display); n_screens = gdk_display_get_n_screens (display); gdk_error_trap_push (); for (i = 0; i < n_screens; i++) { GdkScreen *screen; screen = gdk_display_get_screen (display, i); if (visible) XFixesShowCursor (xdisplay, GDK_WINDOW_XID (gdk_screen_get_root_window (screen))); else XFixesHideCursor (xdisplay, GDK_WINDOW_XID (gdk_screen_get_root_window (screen))); } if (gdk_error_trap_pop ()) { g_warning ("An error occurred trying to %s the cursor", visible ? "show" : "hide"); } manager->priv->cursor_shown = visible; } static gboolean device_info_is_ps2_mouse (XDeviceInfo *info) { return (g_strcmp0 (info->name, "ImPS/2 Generic Wheel Mouse") == 0); } static void update_cursor_for_current (CsdCursorManager *manager) { XDeviceInfo *device_info; guint num_mice; int n_devices; guint i; /* List all the pointer devices * ignore the touchscreens * ignore the XTest devices * see if there's anything left */ device_info = XListInputDevices (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &n_devices); if (device_info == NULL) return; num_mice = 0; for (i = 0; i < n_devices; i++) { XDevice *device; if (device_info[i].use != IsXExtensionPointer) continue; if (device_info_is_touchscreen (&device_info[i])) continue; if (device_info_is_ps2_mouse (&device_info[i])) continue; gdk_error_trap_push (); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), device_info[i].id); if (gdk_error_trap_pop () || (device == NULL)) continue; if (device_is_xtest (device)) { xdevice_close (device); continue; } g_debug ("Counting '%s' as mouse", device_info[i].name); num_mice++; } XFreeDeviceList (device_info); g_debug ("Found %d devices that aren't touchscreens or fake devices", num_mice); if (num_mice > 0) { g_debug ("Mice are present"); if (manager->priv->cursor_shown == FALSE) { set_cursor_visibility (manager, TRUE); } } else { g_debug ("No mice present"); if (manager->priv->cursor_shown != FALSE) { set_cursor_visibility (manager, FALSE); } } } static void devices_added_cb (GdkDeviceManager *device_manager, GdkDevice *device, CsdCursorManager *manager) { update_cursor_for_current (manager); } static void devices_removed_cb (GdkDeviceManager *device_manager, GdkDevice *device, CsdCursorManager *manager) { /* If devices are removed, then it's unlikely * a mouse appeared */ if (manager->priv->cursor_shown == FALSE) return; update_cursor_for_current (manager); } static gboolean supports_xfixes (void) { gint op_code, event, error; return XQueryExtension (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "XFIXES", &op_code, &event, &error); } static gboolean supports_cursor_xfixes (void) { int major = XFIXES_CURSOR_HIDING_MAJOR; int minor = 0; gdk_error_trap_push (); if (!supports_xfixes ()) { gdk_error_trap_pop_ignored (); return FALSE; } if (!XFixesQueryVersion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), &major, &minor)) { gdk_error_trap_pop_ignored (); return FALSE; } gdk_error_trap_pop_ignored (); if (major >= XFIXES_CURSOR_HIDING_MAJOR) return TRUE; return FALSE; } static gboolean csd_cursor_manager_idle_cb (CsdCursorManager *manager) { GdkDeviceManager *device_manager; cinnamon_settings_profile_start (NULL); if (supports_cursor_xfixes () == FALSE) { g_debug ("XFixes cursor extension not available, will not hide the cursor"); return FALSE; } if (supports_xinput_devices () == FALSE) { g_debug ("XInput support not available, will not hide the cursor"); return FALSE; } /* We assume that the touchscreen is builtin and * won't be appearing in the middle of the session... */ if (touchscreen_is_present () == FALSE) { g_debug ("Did not find a touchscreen, will not hide the cursor"); cinnamon_settings_profile_end (NULL); return FALSE; } update_cursor_for_current (manager); device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); manager->priv->added_id = g_signal_connect (G_OBJECT (device_manager), "device-added", G_CALLBACK (devices_added_cb), manager); manager->priv->removed_id = g_signal_connect (G_OBJECT (device_manager), "device-removed", G_CALLBACK (devices_removed_cb), manager); cinnamon_settings_profile_end (NULL); return FALSE; } gboolean csd_cursor_manager_start (CsdCursorManager *manager, GError **error) { g_debug ("Starting cursor manager"); cinnamon_settings_profile_start (NULL); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) csd_cursor_manager_idle_cb, manager); cinnamon_settings_profile_end (NULL); return TRUE; } void csd_cursor_manager_stop (CsdCursorManager *manager) { GdkDeviceManager *device_manager; g_debug ("Stopping cursor manager"); device_manager = gdk_display_get_device_manager (gdk_display_get_default ()); if (manager->priv->added_id > 0) { g_signal_handler_disconnect (G_OBJECT (device_manager), manager->priv->added_id); manager->priv->added_id = 0; } if (manager->priv->removed_id > 0) { g_signal_handler_disconnect (G_OBJECT (device_manager), manager->priv->removed_id); manager->priv->removed_id = 0; } if (manager->priv->cursor_shown == FALSE) { set_cursor_visibility (manager, TRUE); } } static GObject * csd_cursor_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsdCursorManager *cursor_manager; cursor_manager = CSD_CURSOR_MANAGER (G_OBJECT_CLASS (csd_cursor_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (cursor_manager); } static void csd_cursor_manager_class_init (CsdCursorManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = csd_cursor_manager_constructor; object_class->finalize = csd_cursor_manager_finalize; g_type_class_add_private (klass, sizeof (CsdCursorManagerPrivate)); } static void csd_cursor_manager_init (CsdCursorManager *manager) { manager->priv = CSD_CURSOR_MANAGER_GET_PRIVATE (manager); manager->priv->cursor_shown = TRUE; } static void csd_cursor_manager_finalize (GObject *object) { CsdCursorManager *cursor_manager; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_CURSOR_MANAGER (object)); cursor_manager = CSD_CURSOR_MANAGER (object); g_return_if_fail (cursor_manager->priv != NULL); G_OBJECT_CLASS (csd_cursor_manager_parent_class)->finalize (object); } CsdCursorManager * csd_cursor_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (CSD_TYPE_CURSOR_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return CSD_CURSOR_MANAGER (manager_object); } cinnamon-settings-daemon-2.8.3/plugins/cursor/csd-cursor-plugin.h0000664000175000017500000000424312625665665024126 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. * */ #ifndef __CSD_CURSOR_PLUGIN_H__ #define __CSD_CURSOR_PLUGIN_H__ #include #include #include #include "cinnamon-settings-plugin.h" G_BEGIN_DECLS #define CSD_TYPE_CURSOR_PLUGIN (csd_cursor_plugin_get_type ()) #define CSD_CURSOR_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_CURSOR_PLUGIN, CsdCursorPlugin)) #define CSD_CURSOR_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_CURSOR_PLUGIN, CsdCursorPluginClass)) #define CSD_IS_CURSOR_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_CURSOR_PLUGIN)) #define CSD_IS_CURSOR_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_CURSOR_PLUGIN)) #define CSD_CURSOR_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_CURSOR_PLUGIN, CsdCursorPluginClass)) typedef struct CsdCursorPluginPrivate CsdCursorPluginPrivate; typedef struct { CinnamonSettingsPlugin parent; CsdCursorPluginPrivate *priv; } CsdCursorPlugin; typedef struct { CinnamonSettingsPluginClass parent_class; } CsdCursorPluginClass; GType csd_cursor_plugin_get_type (void) G_GNUC_CONST; /* All the plugins must implement this function */ G_MODULE_EXPORT GType register_cinnamon_settings_plugin (GTypeModule *module); G_END_DECLS #endif /* __CSD_CURSOR_PLUGIN_H__ */ cinnamon-settings-daemon-2.8.3/plugins/cursor/csd-cursor-plugin.c0000664000175000017500000000613312625665665024121 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 "cinnamon-settings-plugin.h" #include "csd-cursor-plugin.h" #include "csd-cursor-manager.h" struct CsdCursorPluginPrivate { CsdCursorManager *manager; }; #define CSD_CURSOR_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSD_TYPE_CURSOR_PLUGIN, CsdCursorPluginPrivate)) CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdCursorPlugin, csd_cursor_plugin) static void csd_cursor_plugin_init (CsdCursorPlugin *plugin) { plugin->priv = CSD_CURSOR_PLUGIN_GET_PRIVATE (plugin); g_debug ("CsdCursorPlugin initializing"); plugin->priv->manager = csd_cursor_manager_new (); } static void csd_cursor_plugin_finalize (GObject *object) { CsdCursorPlugin *plugin; g_return_if_fail (object != NULL); g_return_if_fail (CSD_IS_CURSOR_PLUGIN (object)); g_debug ("CsdCursorPlugin finalizing"); plugin = CSD_CURSOR_PLUGIN (object); g_return_if_fail (plugin->priv != NULL); if (plugin->priv->manager != NULL) { g_object_unref (plugin->priv->manager); } G_OBJECT_CLASS (csd_cursor_plugin_parent_class)->finalize (object); } static void impl_activate (CinnamonSettingsPlugin *plugin) { gboolean res; GError *error; g_debug ("Activating cursor plugin"); error = NULL; res = csd_cursor_manager_start (CSD_CURSOR_PLUGIN (plugin)->priv->manager, &error); if (! res) { g_warning ("Unable to start cursor manager: %s", error->message); g_error_free (error); } } static void impl_deactivate (CinnamonSettingsPlugin *plugin) { g_debug ("Deactivating cursor plugin"); csd_cursor_manager_stop (CSD_CURSOR_PLUGIN (plugin)->priv->manager); } static void csd_cursor_plugin_class_init (CsdCursorPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CinnamonSettingsPluginClass *plugin_class = CINNAMON_SETTINGS_PLUGIN_CLASS (klass); object_class->finalize = csd_cursor_plugin_finalize; plugin_class->activate = impl_activate; plugin_class->deactivate = impl_deactivate; g_type_class_add_private (klass, sizeof (CsdCursorPluginPrivate)); } cinnamon-settings-daemon-2.8.3/plugins/cursor/csd-cursor-manager.h0000664000175000017500000000443112625665665024241 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_CURSOR_MANAGER_H #define __CSD_CURSOR_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_CURSOR_MANAGER (csd_cursor_manager_get_type ()) #define CSD_CURSOR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_CURSOR_MANAGER, CsdCursorManager)) #define CSD_CURSOR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_CURSOR_MANAGER, CsdCursorManagerClass)) #define CSD_IS_CURSOR_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_CURSOR_MANAGER)) #define CSD_IS_CURSOR_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_CURSOR_MANAGER)) #define CSD_CURSOR_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_CURSOR_MANAGER, CsdCursorManagerClass)) typedef struct CsdCursorManagerPrivate CsdCursorManagerPrivate; typedef struct { GObject parent; CsdCursorManagerPrivate *priv; } CsdCursorManager; typedef struct { GObjectClass parent_class; } CsdCursorManagerClass; GType csd_cursor_manager_get_type (void); CsdCursorManager * csd_cursor_manager_new (void); gboolean csd_cursor_manager_start (CsdCursorManager *manager, GError **error); void csd_cursor_manager_stop (CsdCursorManager *manager); G_END_DECLS #endif /* __CSD_CURSOR_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/cursor/Makefile.am0000664000175000017500000000164612625665665022435 0ustar fabiofabioplugin_name = cursor plugin_LTLIBRARIES = \ libcursor.la libcursor_la_SOURCES = \ csd-cursor-manager.c \ csd-cursor-manager.h \ csd-cursor-plugin.c \ csd-cursor-plugin.h libcursor_la_CPPFLAGS = \ -I$(top_srcdir)/cinnamon-settings-daemon \ -I$(top_srcdir)/plugins/common/ \ -DCINNAMON_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libcursor_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(CURSOR_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) libcursor_la_LDFLAGS = \ $(CSD_PLUGIN_LDFLAGS) libcursor_la_LIBADD = \ $(top_builddir)/plugins/common/libcommon.la \ $(CURSOR_LIBS) \ $(SETTINGS_PLUGIN_LIBS) plugin_in_files = \ cursor.cinnamon-settings-plugin.in plugin_DATA = $(plugin_in_files:.cinnamon-settings-plugin.in=.cinnamon-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) CLEANFILES = \ $(plugin_DATA) DISTCLEANFILES = \ $(plugin_DATA) @CSD_INTLTOOL_PLUGIN_RULE@ cinnamon-settings-daemon-2.8.3/plugins/wacom/0000775000175000017500000000000012625665665020163 5ustar fabiofabiocinnamon-settings-daemon-2.8.3/plugins/wacom/csd-wacom-device.c0000664000175000017500000017117112625665665023451 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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_error_trap_push (); device = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), dev->id); if (gdk_error_trap_pop () || (device == NULL)) return ret; gdk_error_trap_push (); 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_error_trap_pop () || 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_assert (device->priv->styli); 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_error_trap_push (); xdevice = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id); if (gdk_error_trap_pop () || (device == NULL)) return NULL; gdk_error_trap_push (); rc = XGetDeviceProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice, area, 0, 4, False, XA_INTEGER, &realtype, &realformat, &nitems, &bytes_after, &data); if (gdk_error_trap_pop () || 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-2.8.3/plugins/wacom/csd-wacom-plugin.c0000664000175000017500000000207312625665665023502 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include #include #include "cinnamon-settings-plugin.h" #include "csd-wacom-manager.h" NEW_CINNAMON_SETTINGS_PLUGIN_REGISTER (CsdWacom, csd_wacom) cinnamon-settings-daemon-2.8.3/plugins/wacom/csd-wacom-osd-window.h0000664000175000017500000000636012625665665024306 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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-2.8.3/plugins/wacom/org.cinnamon.settings-daemon.plugins.wacom.policy.in.in0000664000175000017500000000216612625665665032700 0ustar fabiofabio CINNAMON Settings Daemon http://git.gnome.org/browse/gnome-settings-daemon input-tablet <_description>Modify the lit LED for a Wacom tablet <_message>Authentication is required to modify the lit LED for a Wacom tablet no no yes @libexecdir@/csd-wacom-led-helper cinnamon-settings-daemon-2.8.3/plugins/wacom/csd-wacom-manager.c0000664000175000017500000013255612625665665023630 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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" /* 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_error_trap_push (); xdev = XOpenDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), id); if (gdk_error_trap_pop () || (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); /* Compute rotation to apply relative to the output */ settings = csd_wacom_device_get_settings (device); device_rotation = g_settings_get_enum (settings, KEY_ROTATION); output_rotation = csd_wacom_device_get_display_rotation (device); /* Apply display rotation to 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_error_trap_push (); XSetDeviceMode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev, is_absolute ? Absolute : Relative); if (gdk_error_trap_pop ()) 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_error_trap_push (); /* 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_error_trap_pop () && 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); } static void set_led (CsdWacomDevice *device, CsdWacomTabletButton *button, int index) { GError *error = NULL; const char *path; char *command; gint status_led; gboolean ret; #ifndef HAVE_GUDEV /* Not implemented on non-Linux systems */ return; #endif g_return_if_fail (index >= 1); path = csd_wacom_device_get_path (device); status_led = button->status_led; if (status_led == CSD_WACOM_NO_LED) { g_debug ("Ignoring unhandled group ID %d for device %s", button->group_id, csd_wacom_device_get_name (device)); return; } g_debug ("Switching group ID %d to index %d for device %s", button->group_id, index, path); command = g_strdup_printf ("pkexec " LIBEXECDIR "/csd-wacom-led-helper --path %s --group %d --led %d", path, status_led, index - 1); ret = g_spawn_command_line_sync (command, NULL, NULL, NULL, &error); if (ret == FALSE) { g_debug ("Failed to launch '%s': %s", command, error->message); g_error_free (error); } g_free (command); } 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_error_trap_push (); 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_error_trap_pop () && 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_error_trap_push (); reset_touch_buttons (xdev, def_touchrings_buttons, "Wacom Wheel Buttons"); reset_touch_buttons (xdev, def_touchstrip_buttons, "Wacom Strip Buttons"); gdk_error_trap_pop_ignored (); 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; if (button->type == WACOM_TABLET_BUTTON_TYPE_HARDCODED && button->status_led != CSD_WACOM_NO_LED) { set_led (device, button, 1); } } 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_error_trap_push (); 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_error_trap_pop ()) 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 dont; 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); } set_led (device, wbutton, new_mode); 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-2.8.3/plugins/wacom/csd-wacom-manager.h0000664000175000017500000000443412625665665023626 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __CSD_WACOM_MANAGER_H #define __CSD_WACOM_MANAGER_H #include G_BEGIN_DECLS #define CSD_TYPE_WACOM_MANAGER (csd_wacom_manager_get_type ()) #define CSD_WACOM_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSD_TYPE_WACOM_MANAGER, CsdWacomManager)) #define CSD_WACOM_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSD_TYPE_WACOM_MANAGER, CsdWacomManagerClass)) #define CSD_IS_WACOM_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSD_TYPE_WACOM_MANAGER)) #define CSD_IS_WACOM_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSD_TYPE_WACOM_MANAGER)) #define CSD_WACOM_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSD_TYPE_WACOM_MANAGER, CsdWacomManagerClass)) typedef struct CsdWacomManagerPrivate CsdWacomManagerPrivate; typedef struct { GObject parent; CsdWacomManagerPrivate *priv; } CsdWacomManager; typedef struct { GObjectClass parent_class; } CsdWacomManagerClass; GType csd_wacom_manager_get_type (void); CsdWacomManager * csd_wacom_manager_new (void); gboolean csd_wacom_manager_start (CsdWacomManager *manager, GError **error); void csd_wacom_manager_stop (CsdWacomManager *manager); G_END_DECLS #endif /* __CSD_WACOM_MANAGER_H */ cinnamon-settings-daemon-2.8.3/plugins/wacom/csd-wacom-device.h0000664000175000017500000002041212625665665023445 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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-2.8.3/plugins/wacom/README.config-storage0000664000175000017500000000326212625665665023754 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//