unity-settings-daemon-14.04.0+14.04.20150825/0000755000015300001610000000000012567032025020467 5ustar pbuserpbgroup00000000000000unity-settings-daemon-14.04.0+14.04.20150825/Makefile.am0000644000015300001610000000044312567031542022527 0ustar pbuserpbgroup00000000000000NULL = SUBDIRS = \ gnome-settings-daemon \ plugins \ data \ po \ tests \ $(NULL) if ENABLE_MAN SUBDIRS += man endif # Honor aclocal flags ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} EXTRA_DIST = \ MAINTAINERS \ ChangeLog \ README \ $(NULL) DISTCLEANFILES = \ $(NULL) unity-settings-daemon-14.04.0+14.04.20150825/COPYING.LIB0000644000015300001610000006350412567031542022142 0ustar pbuserpbgroup00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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 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.1 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, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! unity-settings-daemon-14.04.0+14.04.20150825/plugins/0000755000015300001610000000000012567032025022150 5ustar pbuserpbgroup00000000000000unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/0000755000015300001610000000000012567032025023615 5ustar pbuserpbgroup00000000000000unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/Makefile.am0000644000015300001610000000220512567031542025653 0ustar pbuserpbgroup00000000000000plugin_name = updates plugin_LTLIBRARIES = \ libupdates.la libupdates_la_SOURCES = \ gsd-updates-common.h \ gsd-updates-plugin.c \ gsd-updates-refresh.h \ gsd-updates-refresh.c \ gsd-updates-firmware.h \ gsd-updates-firmware.c \ gsd-updates-manager.h \ gsd-updates-manager.c libupdates_la_CPPFLAGS = \ -I$(top_srcdir)/gnome-settings-daemon \ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libupdates_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(GUDEV_CFLAGS) \ -DG_UDEV_API_IS_SUBJECT_TO_CHANGE \ $(PACKAGEKIT_CFLAGS) \ -DI_KNOW_THE_PACKAGEKIT_GLIB2_API_IS_SUBJECT_TO_CHANGE \ -DDATADIR=\"$(datadir)\" \ -DBINDIR=\"$(bindir)\" \ -DLIBEXECDIR=\"$(libexecdir)\" \ -I$(top_srcdir)/data \ $(AM_CFLAGS) libupdates_la_LDFLAGS = \ $(GSD_PLUGIN_LDFLAGS) libupdates_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) \ $(PACKAGEKIT_LIBS) plugin_in_files = \ updates.gnome-settings-plugin.in plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.in=.gnome-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) CLEANFILES = \ $(plugin_DATA) DISTCLEANFILES = \ $(plugin_DATA) @GSD_INTLTOOL_PLUGIN_RULE@ unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/gsd-updates-manager.c0000644000015300001610000016146712567031542027633 0ustar pbuserpbgroup00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include "gsd-enums.h" #include "gsd-updates-manager.h" #include "gsd-updates-firmware.h" #include "gsd-updates-refresh.h" #include "gsd-updates-common.h" #include "gnome-settings-profile.h" #include "gnome-settings-session.h" #define GSD_UPDATES_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_UPDATES_MANAGER, GsdUpdatesManagerPrivate)) #define MAX_FAILED_GET_UPDATES 10 /* the maximum number of tries */ #define GSD_UPDATES_ICON_NORMAL "software-update-available-symbolic" #define GSD_UPDATES_ICON_URGENT "software-update-urgent-symbolic" #define GSD_UPDATES_CHECK_OFFLINE_TIMEOUT 30 /* time in seconds */ struct GsdUpdatesManagerPrivate { GCancellable *cancellable; GsdUpdatesRefresh *refresh; GsdUpdatesFirmware *firmware; GSettings *settings_proxy; GSettings *settings_ftp; GSettings *settings_gsd; GSettings *settings_http; guint number_updates_critical_last_shown; guint offline_update_id; PkError *offline_update_error; NotifyNotification *notification_updates; PkControl *control; PkTask *task; guint inhibit_cookie; GDBusProxy *proxy_session; guint update_viewer_watcher_id; GVolumeMonitor *volume_monitor; guint failed_get_updates_count; GPtrArray *update_packages; }; static void gsd_updates_manager_class_init (GsdUpdatesManagerClass *klass); static void gsd_updates_manager_init (GsdUpdatesManager *updates_manager); G_DEFINE_TYPE (GsdUpdatesManager, gsd_updates_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static void child_exit_cb (GPid pid, gint status, gpointer user_data) { g_spawn_close_pid (pid); } static void clear_offline_updates_message (void) { gboolean ret; GError *error = NULL; gchar *argv[3]; GPid pid; argv[0] = "pkexec"; argv[1] = LIBEXECDIR "/pk-clear-offline-update"; argv[2] = NULL; ret = g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL, NULL, &pid, &error); if (!ret) { g_warning ("Failure clearing offline update message: %s", error->message); g_error_free (error); return; } g_child_watch_add (pid, child_exit_cb, NULL); } static void show_offline_updates_error (GsdUpdatesManager *manager) { const gchar *title; gboolean show_geeky = FALSE; GString *msg; GtkWidget *dialog; /* TRANSLATORS: this is when the offline update failed */ title = _("Failed To Update"); msg = g_string_new (""); switch (pk_error_get_code (manager->priv->offline_update_error)) { case PK_ERROR_ENUM_UNFINISHED_TRANSACTION: /* TRANSLATORS: the transaction could not be completed * as a previous transaction was unfinished */ g_string_append (msg, _("A previous update was unfinished.")); show_geeky = TRUE; break; case PK_ERROR_ENUM_PACKAGE_DOWNLOAD_FAILED: case PK_ERROR_ENUM_NO_CACHE: case PK_ERROR_ENUM_NO_NETWORK: case PK_ERROR_ENUM_NO_MORE_MIRRORS_TO_TRY: case PK_ERROR_ENUM_CANNOT_FETCH_SOURCES: /* TRANSLATORS: the package manager needed to download * something with no network available */ g_string_append (msg, _("Network access was required but not available.")); break; case PK_ERROR_ENUM_BAD_GPG_SIGNATURE: case PK_ERROR_ENUM_CANNOT_UPDATE_REPO_UNSIGNED: case PK_ERROR_ENUM_GPG_FAILURE: case PK_ERROR_ENUM_MISSING_GPG_SIGNATURE: case PK_ERROR_ENUM_PACKAGE_CORRUPT: /* TRANSLATORS: if the package is not signed correctly * */ g_string_append (msg, _("An update was not signed in the correct way.")); show_geeky = TRUE; break; case PK_ERROR_ENUM_DEP_RESOLUTION_FAILED: case PK_ERROR_ENUM_FILE_CONFLICTS: case PK_ERROR_ENUM_INCOMPATIBLE_ARCHITECTURE: case PK_ERROR_ENUM_PACKAGE_CONFLICTS: /* TRANSLATORS: the transaction failed in a way the user * probably cannot comprehend. Package management systems * really are teh suck.*/ g_string_append (msg, _("The update could not be completed.")); show_geeky = TRUE; break; case PK_ERROR_ENUM_TRANSACTION_CANCELLED: /* TRANSLATORS: the user aborted the update manually */ g_string_append (msg, _("The update was cancelled.")); break; case PK_ERROR_ENUM_NO_PACKAGES_TO_UPDATE: case PK_ERROR_ENUM_UPDATE_NOT_FOUND: /* TRANSLATORS: the user must have updated manually after * the updates were prepared */ g_string_append (msg, _("An offline update was requested but no packages required updating.")); break; case PK_ERROR_ENUM_NO_SPACE_ON_DEVICE: /* TRANSLATORS: we ran out of disk space */ g_string_append (msg, _("No space was left on the drive.")); break; case PK_ERROR_ENUM_PACKAGE_FAILED_TO_BUILD: case PK_ERROR_ENUM_PACKAGE_FAILED_TO_INSTALL: case PK_ERROR_ENUM_PACKAGE_FAILED_TO_REMOVE: /* TRANSLATORS: the update process failed in a general * way, usually this message will come from source distros * like gentoo */ g_string_append (msg, _("An update failed to install correctly.")); show_geeky = TRUE; break; default: /* TRANSLATORS: We didn't handle the error type */ g_string_append (msg, _("The offline update failed in an unexpected way.")); show_geeky = TRUE; break; } if (show_geeky) { g_string_append_printf (msg, "\n%s\n\n%s", /* TRANSLATORS: these are geeky messages from the * package manager no mortal is supposed to understand, * but google might know what they mean */ _("Detailed errors from the package manager follow:"), pk_error_get_details (manager->priv->offline_update_error)); } dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s", title); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", msg->str); g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); gtk_widget_show (dialog); clear_offline_updates_message (); g_string_free (msg, TRUE); } static void libnotify_action_cb (NotifyNotification *notification, gchar *action, gpointer user_data) { gboolean ret; GError *error = NULL; GsdUpdatesManager *manager = GSD_UPDATES_MANAGER (user_data); notify_notification_close (notification, NULL); if (g_strcmp0 (action, "distro-upgrade-info") == 0) { ret = g_spawn_command_line_async (DATADIR "/PackageKit/pk-upgrade-distro.sh", &error); if (!ret) { g_warning ("Failure launching pk-upgrade-distro.sh: %s", error->message); g_error_free (error); } goto out; } if (g_strcmp0 (action, "show-update-viewer") == 0) { ret = g_spawn_command_line_async (BINDIR "/gpk-update-viewer", &error); if (!ret) { g_warning ("Failure launching update viewer: %s", error->message); g_error_free (error); } goto out; } if (g_strcmp0 (action, "clear-offline-updates") == 0) { clear_offline_updates_message (); goto out; } if (g_strcmp0 (action, "error-offline-updates") == 0) { show_offline_updates_error (manager); goto out; } if (g_strcmp0 (action, "cancel") == 0) { /* try to cancel */ g_cancellable_cancel (manager->priv->cancellable); goto out; } g_warning ("unknown action id: %s", action); out: return; } static void on_notification_closed (NotifyNotification *notification, gpointer data) { g_object_unref (notification); } static void get_distro_upgrades_finished_cb (GObject *object, GAsyncResult *res, GsdUpdatesManager *manager) { const gchar *title; gboolean ret; gchar *name = NULL; GError *error = NULL; GPtrArray *array = NULL; GString *string = NULL; guint i; NotifyNotification *notification; PkClient *client = PK_CLIENT(object); PkDistroUpgrade *item; PkError *error_code = NULL; PkResults *results; PkUpdateStateEnum state; /* get the results */ results = pk_client_generic_finish (PK_CLIENT(client), res, &error); if (results == NULL) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error_free (error); return; } if (error->domain != PK_CLIENT_ERROR || error->code != PK_CLIENT_ERROR_NOT_SUPPORTED) { g_warning ("failed to get upgrades: %s", error->message); } g_error_free (error); goto out; } /* check error code */ error_code = pk_results_get_error_code (results); if (error_code != NULL) { g_warning ("failed to get upgrades: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code)); goto out; } /* process results */ array = pk_results_get_distro_upgrade_array (results); /* any updates? */ if (array->len == 0) { g_debug ("no upgrades"); goto out; } /* do we do the notification? */ ret = g_settings_get_boolean (manager->priv->settings_gsd, GSD_SETTINGS_NOTIFY_DISTRO_UPGRADES); if (!ret) { g_debug ("ignoring due to GSettings"); goto out; } /* find the upgrade string */ string = g_string_new (""); for (i=0; i < array->len; i++) { item = (PkDistroUpgrade *) g_ptr_array_index (array, i); g_object_get (item, "name", &name, "state", &state, NULL); g_string_append_printf (string, "%s (%s)\n", name, pk_distro_upgrade_enum_to_string (state)); g_free (name); } if (string->len != 0) g_string_set_size (string, string->len-1); /* TRANSLATORS: a distro update is available, e.g. Fedora 8 to Fedora 9 */ title = _("Distribution upgrades available"); notification = notify_notification_new (title, string->str, GSD_UPDATES_ICON_NORMAL); notify_notification_set_hint_string (notification, "desktop-entry", "gpk-update-viewer"); notify_notification_set_app_name (notification, _("Software Updates")); notify_notification_set_timeout (notification, NOTIFY_EXPIRES_NEVER); notify_notification_set_urgency (notification, NOTIFY_URGENCY_NORMAL); notify_notification_add_action (notification, "distro-upgrade-info", /* TRANSLATORS: provides more information about the upgrade */ _("More information"), libnotify_action_cb, manager, NULL); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); ret = notify_notification_show (notification, &error); if (!ret) { g_warning ("error: %s", error->message); g_error_free (error); } out: if (error_code != NULL) g_object_unref (error_code); if (array != NULL) g_ptr_array_unref (array); if (string != NULL) g_string_free (string, TRUE); if (results != NULL) g_object_unref (results); } static void due_get_upgrades_cb (GsdUpdatesRefresh *refresh, GsdUpdatesManager *manager) { /* optimize the amount of downloaded data by setting the cache age */ pk_client_set_cache_age (PK_CLIENT(manager->priv->task), g_settings_get_int (manager->priv->settings_gsd, GSD_SETTINGS_FREQUENCY_GET_UPGRADES)); /* get new distro upgrades list */ pk_client_get_distro_upgrades_async (PK_CLIENT(manager->priv->task), NULL, NULL, NULL, (GAsyncReadyCallback) get_distro_upgrades_finished_cb, manager); } static void refresh_cache_finished_cb (GObject *object, GAsyncResult *res, GsdUpdatesManager *manager) { PkClient *client = PK_CLIENT(object); PkResults *results; GError *error = NULL; PkError *error_code = NULL; /* get the results */ results = pk_client_generic_finish (PK_CLIENT(client), res, &error); if (results == NULL) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error_free (error); return; } g_warning ("failed to refresh the cache: %s", error->message); g_error_free (error); return; } /* check error code */ error_code = pk_results_get_error_code (results); if (error_code != NULL) { g_warning ("failed to refresh the cache: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code)); } if (error_code != NULL) g_object_unref (error_code); if (results != NULL) g_object_unref (results); } static void due_refresh_cache_cb (GsdUpdatesRefresh *refresh, GsdUpdatesManager *manager) { /* optimize the amount of downloaded data by setting the cache age */ pk_client_set_cache_age (PK_CLIENT(manager->priv->task), g_settings_get_int (manager->priv->settings_gsd, GSD_SETTINGS_FREQUENCY_REFRESH_CACHE)); pk_client_refresh_cache_async (PK_CLIENT(manager->priv->task), TRUE, NULL, NULL, NULL, (GAsyncReadyCallback) refresh_cache_finished_cb, manager); } static void notify_critical_updates (GsdUpdatesManager *manager, GPtrArray *array) { const gchar *message; const gchar *title; gboolean ret; GError *error = NULL; NotifyNotification *notification; /* if the number of critical updates is the same as the last notification, * then skip the notifcation as we don't want to bombard the user every hour */ if (array->len == manager->priv->number_updates_critical_last_shown) { g_debug ("ignoring as user ignored last warning"); return; } /* save for comparison later */ manager->priv->number_updates_critical_last_shown = array->len; /* TRANSLATORS: title in the libnotify popup */ title = ngettext ("Update", "Updates", array->len); /* TRANSLATORS: message when there are security updates */ message = ngettext ("An important software update is available", "Important software updates are available", array->len); /* close any existing notification */ if (manager->priv->notification_updates != NULL) { notify_notification_close (manager->priv->notification_updates, NULL); manager->priv->notification_updates = NULL; } /* do the bubble */ g_debug ("title=%s, message=%s", title, message); notification = notify_notification_new (title, message, GSD_UPDATES_ICON_URGENT); notify_notification_set_hint_string (notification, "desktop-entry", "gpk-update-viewer"); notify_notification_set_app_name (notification, _("Software Updates")); notify_notification_set_timeout (notification, 15000); notify_notification_set_urgency (notification, NOTIFY_URGENCY_CRITICAL); notify_notification_add_action (notification, "show-update-viewer", /* TRANSLATORS: button: open the update viewer to install updates*/ _("Install updates"), libnotify_action_cb, manager, NULL); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); ret = notify_notification_show (notification, &error); if (!ret) { g_warning ("error: %s", error->message); g_error_free (error); } /* track so we can prevent doubled notifications */ manager->priv->notification_updates = notification; g_object_add_weak_pointer (G_OBJECT (manager->priv->notification_updates), (void **) &manager->priv->notification_updates); } static void notify_normal_updates_maybe (GsdUpdatesManager *manager, GPtrArray *array) { const gchar *message; const gchar *title; gboolean ret; GError *error = NULL; guint64 time_last_notify; guint64 time_now; guint freq_updates_notify; NotifyNotification *notification; /* find out if enough time has passed since the last notification */ time_now = g_get_real_time () / 1000000; freq_updates_notify = g_settings_get_int (manager->priv->settings_gsd, GSD_SETTINGS_FREQUENCY_UPDATES_NOTIFICATION); g_settings_get (manager->priv->settings_gsd, GSD_SETTINGS_LAST_UPDATES_NOTIFICATION, "t", &time_last_notify); if (time_last_notify > 0 && (guint64) freq_updates_notify > time_now - time_last_notify) { g_debug ("not showing non-critical notification as already shown %i hours ago", (guint) (time_now - time_last_notify) / (60 * 60)); return; } /* TRANSLATORS: title in the libnotify popup */ title = ngettext ("Update", "Updates", array->len); /* TRANSLATORS: message when there are non-security updates */ message = ngettext ("A software update is available.", "Software updates are available.", array->len); /* close any existing notification */ if (manager->priv->notification_updates != NULL) { notify_notification_close (manager->priv->notification_updates, NULL); manager->priv->notification_updates = NULL; } /* do the bubble */ g_debug ("title=%s, message=%s", title, message); notification = notify_notification_new (title, message, GSD_UPDATES_ICON_NORMAL); notify_notification_set_hint_string (notification, "desktop-entry", "gpk-update-viewer"); notify_notification_set_app_name (notification, _("Software Updates")); notify_notification_set_timeout (notification, 15000); notify_notification_set_urgency (notification, NOTIFY_URGENCY_NORMAL); notify_notification_add_action (notification, "show-update-viewer", /* TRANSLATORS: button: open the update viewer to install updates*/ _("Install updates"), libnotify_action_cb, manager, NULL); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); ret = notify_notification_show (notification, &error); if (!ret) { g_warning ("error: %s", error->message); g_error_free (error); } /* reset notification time */ g_settings_set (manager->priv->settings_gsd, GSD_SETTINGS_LAST_UPDATES_NOTIFICATION, "t", time_now); /* track so we can prevent doubled notifications */ manager->priv->notification_updates = notification; g_object_add_weak_pointer (G_OBJECT (manager->priv->notification_updates), (void **) &manager->priv->notification_updates); } static void notify_failed_get_updates_maybe (GsdUpdatesManager *manager) { const gchar *button; const gchar *message; const gchar *title; gboolean ret; GError *error = NULL; NotifyNotification *notification; /* give the user a break */ if (manager->priv->failed_get_updates_count++ < MAX_FAILED_GET_UPDATES) { g_debug ("failed GetUpdates, but will retry %i more times before notification", MAX_FAILED_GET_UPDATES - manager->priv->failed_get_updates_count); goto out; } /* TRANSLATORS: the updates mechanism */ title = _("Updates"); /* TRANSLATORS: we failed to get the updates multiple times, * and now we need to inform the user that something might be wrong */ message = _("Unable to access software updates"); /* TRANSLATORS: try again, this time launching the update viewer */ button = _("Try again"); notification = notify_notification_new (title, message, GSD_UPDATES_ICON_NORMAL); notify_notification_set_hint_string (notification, "desktop-entry", "gpk-update-viewer"); notify_notification_set_app_name (notification, _("Software Updates")); notify_notification_set_timeout (notification, 120*1000); notify_notification_set_urgency (notification, NOTIFY_URGENCY_NORMAL); notify_notification_add_action (notification, "show-update-viewer", button, libnotify_action_cb, manager, NULL); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); ret = notify_notification_show (notification, &error); if (!ret) { g_warning ("failed to show notification: %s", error->message); g_error_free (error); } out: /* reset, even if the message failed */ manager->priv->failed_get_updates_count = 0; } static void check_updates_for_importance (GsdUpdatesManager *manager) { guint i; PkPackage *pkg; GPtrArray *important_array; /* check each package */ important_array = g_ptr_array_new (); for (i = 0; i < manager->priv->update_packages->len; i++) { pkg = g_ptr_array_index (manager->priv->update_packages, i); if (pk_package_get_info (pkg) == PK_INFO_ENUM_SECURITY || pk_package_get_info (pkg) == PK_INFO_ENUM_IMPORTANT) g_ptr_array_add (important_array, pkg); } if (important_array->len > 0) { notify_critical_updates (manager, important_array); } else { notify_normal_updates_maybe (manager, manager->priv->update_packages); } g_ptr_array_unref (important_array); } static void package_download_finished_cb (GObject *object, GAsyncResult *res, GsdUpdatesManager *manager) { PkClient *client = PK_CLIENT(object); PkResults *results; GError *error = NULL; PkError *error_code = NULL; /* get the results */ results = pk_client_generic_finish (PK_CLIENT(client), res, &error); if (results == NULL) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error_free (error); return; } g_warning ("failed to download: %s", error->message); g_error_free (error); notify_failed_get_updates_maybe (manager); return; } /* check error code */ error_code = pk_results_get_error_code (results); if (error_code != NULL) { g_warning ("failed to download: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code)); switch (pk_error_get_code (error_code)) { case PK_ERROR_ENUM_CANCELLED_PRIORITY: case PK_ERROR_ENUM_TRANSACTION_CANCELLED: g_debug ("ignoring error"); break; default: notify_failed_get_updates_maybe (manager); break; } goto out; } /* check to see if should notify */ check_updates_for_importance (manager); out: if (error_code != NULL) g_object_unref (error_code); if (results != NULL) g_object_unref (results); } static void auto_download_updates (GsdUpdatesManager *manager) { gchar **package_ids; guint i; PkPackage *pkg; /* download each package */ package_ids = g_new0 (gchar *, manager->priv->update_packages->len + 1); for (i = 0; i < manager->priv->update_packages->len; i++) { pkg = g_ptr_array_index (manager->priv->update_packages, i); package_ids[i] = g_strdup (pk_package_get_id (pkg)); } #if PK_CHECK_VERSION(0,8,1) /* we've set only-download in PkTask */ pk_task_update_packages_async (manager->priv->task, package_ids, manager->priv->cancellable, NULL, NULL, (GAsyncReadyCallback) package_download_finished_cb, manager); #else /* download them all */ pk_client_download_packages_async (PK_CLIENT(manager->priv->task), package_ids, NULL, /* this means system cache */ manager->priv->cancellable, NULL, NULL, (GAsyncReadyCallback) package_download_finished_cb, manager); #endif g_strfreev (package_ids); } static void get_updates_finished_cb (GObject *object, GAsyncResult *res, GsdUpdatesManager *manager) { PkClient *client = PK_CLIENT(object); PkResults *results; GError *error = NULL; gboolean ret; PkError *error_code = NULL; /* get the results */ results = pk_client_generic_finish (PK_CLIENT(client), res, &error); if (results == NULL) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { g_error_free (error); return; } g_warning ("failed to get updates: %s", error->message); g_error_free (error); notify_failed_get_updates_maybe (manager); goto out; } /* check error code */ error_code = pk_results_get_error_code (results); if (error_code != NULL) { g_warning ("failed to get updates: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code)); switch (pk_error_get_code (error_code)) { case PK_ERROR_ENUM_CANCELLED_PRIORITY: case PK_ERROR_ENUM_TRANSACTION_CANCELLED: g_debug ("ignoring error"); break; default: notify_failed_get_updates_maybe (manager); break; } goto out; } /* we succeeded, so clear the count */ manager->priv->failed_get_updates_count = 0; /* so we can download or check for important & security updates */ if (manager->priv->update_packages != NULL) g_ptr_array_unref (manager->priv->update_packages); manager->priv->update_packages = pk_results_get_package_array (results); /* we have no updates */ if (manager->priv->update_packages->len == 0) { g_debug ("no updates"); goto out; } /* should we auto-download the updates? */ ret = g_settings_get_boolean (manager->priv->settings_gsd, GSD_SETTINGS_AUTO_DOWNLOAD_UPDATES); if (ret) { auto_download_updates (manager); goto out; } /* just check to see if should notify */ check_updates_for_importance (manager); out: if (error_code != NULL) g_object_unref (error_code); if (results != NULL) g_object_unref (results); } static void query_updates (GsdUpdatesManager *manager) { /* optimize the amount of downloaded data by setting the cache age */ pk_client_set_cache_age (PK_CLIENT(manager->priv->task), g_settings_get_int (manager->priv->settings_gsd, GSD_SETTINGS_FREQUENCY_GET_UPDATES)); /* get new update list */ pk_client_get_updates_async (PK_CLIENT(manager->priv->task), pk_bitfield_value (PK_FILTER_ENUM_NONE), manager->priv->cancellable, NULL, NULL, (GAsyncReadyCallback) get_updates_finished_cb, manager); } static void due_get_updates_cb (GsdUpdatesRefresh *refresh, GsdUpdatesManager *manager) { query_updates (manager); } static gchar * get_proxy_http (GsdUpdatesManager *manager) { gboolean ret; gchar *host = NULL; gchar *password = NULL; gchar *proxy = NULL; gchar *username = NULL; GString *string = NULL; guint port; GDesktopProxyMode proxy_mode; proxy_mode = g_settings_get_enum (manager->priv->settings_proxy, "mode"); if (proxy_mode != G_DESKTOP_PROXY_MODE_MANUAL) goto out; host = g_settings_get_string (manager->priv->settings_http, "host"); if (host == NULL) goto out; port = g_settings_get_int (manager->priv->settings_http, "port"); /* use an HTTP auth string? */ ret = g_settings_get_boolean (manager->priv->settings_http, "use-authentication"); if (ret) { username = g_settings_get_string (manager->priv->settings_http, "authentication-user"); password = g_settings_get_string (manager->priv->settings_http, "authentication-password"); } /* make PackageKit proxy string */ string = g_string_new (host); if (port > 0) g_string_append_printf (string, ":%i", port); if (username != NULL && password != NULL) g_string_append_printf (string, "@%s:%s", username, password); else if (username != NULL) g_string_append_printf (string, "@%s", username); else if (password != NULL) g_string_append_printf (string, "@:%s", password); proxy = g_string_free (string, FALSE); out: g_free (host); g_free (username); g_free (password); return proxy; } static gchar * get_proxy_ftp (GsdUpdatesManager *manager) { gchar *host = NULL; gchar *proxy = NULL; GString *string = NULL; guint port; GDesktopProxyMode proxy_mode; proxy_mode = g_settings_get_enum (manager->priv->settings_proxy, "mode"); if (proxy_mode != G_DESKTOP_PROXY_MODE_MANUAL) goto out; host = g_settings_get_string (manager->priv->settings_ftp, "host"); if (host == NULL) goto out; port = g_settings_get_int (manager->priv->settings_ftp, "port"); if (port == 0) goto out; /* make PackageKit proxy string */ string = g_string_new (host); if (port > 0) g_string_append_printf (string, ":%i", port); proxy = g_string_free (string, FALSE); out: g_free (host); return proxy; } static void set_proxy_cb (GObject *object, GAsyncResult *res, gpointer user_data) { gboolean ret; GError *error = NULL; PkControl *control = PK_CONTROL (object); /* get the result */ ret = pk_control_set_proxy_finish (control, res, &error); if (!ret) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning ("failed to set proxies: %s", error->message); g_error_free (error); } } static void reload_proxy_settings (GsdUpdatesManager *manager) { gchar *proxy_http; gchar *proxy_ftp; proxy_http = get_proxy_http (manager); proxy_ftp = get_proxy_ftp (manager); /* send to daemon */ pk_control_set_proxy_async (manager->priv->control, proxy_http, proxy_ftp, NULL, set_proxy_cb, manager); g_free (proxy_http); g_free (proxy_ftp); } static void settings_changed_cb (GSettings *settings, const char *key, GsdUpdatesManager *manager) { reload_proxy_settings (manager); } static void settings_gsd_changed_cb (GSettings *settings, const char *key, GsdUpdatesManager *manager) { } static void session_inhibit (GsdUpdatesManager *manager) { const gchar *reason; GError *error = NULL; GVariant *retval = NULL; /* state invalid somehow */ if (manager->priv->inhibit_cookie != 0) { g_warning ("already locked"); goto out; } /* TRANSLATORS: the reason why we've inhibited it */ reason = _("A transaction that cannot be interrupted is running"); retval = g_dbus_proxy_call_sync (manager->priv->proxy_session, "Inhibit", g_variant_new ("(susu)", "gnome-settings-daemon", /* app-id */ 0, /* xid */ reason, /* reason */ 4 /* flags */), G_DBUS_CALL_FLAGS_NONE, -1, manager->priv->cancellable, &error); if (retval == NULL) { g_warning ("failed to inhibit gnome-session: %s", error->message); g_error_free (error); goto out; } /* get cookie */ g_variant_get (retval, "(u)", &manager->priv->inhibit_cookie); out: if (retval != NULL) g_variant_unref (retval); } static void session_uninhibit (GsdUpdatesManager *manager) { GError *error = NULL; GVariant *retval = NULL; /* state invalid somehow */ if (manager->priv->inhibit_cookie == 0) { g_warning ("not locked"); goto out; } retval = g_dbus_proxy_call_sync (manager->priv->proxy_session, "Uninhibit", g_variant_new ("(u)", manager->priv->inhibit_cookie), G_DBUS_CALL_FLAGS_NONE, -1, manager->priv->cancellable, &error); if (retval == NULL) { g_warning ("failed to uninhibit gnome-session: %s", error->message); g_error_free (error); goto out; } out: manager->priv->inhibit_cookie = 0; if (retval != NULL) g_variant_unref (retval); } static void notify_locked_cb (PkControl *control, GParamSpec *pspec, GsdUpdatesManager *manager) { gboolean locked; g_object_get (control, "locked", &locked, NULL); /* TODO: locked is a bit harsh, we can probably still allow * reboot when packages are downloading or the transaction is * depsolving */ if (locked) { session_inhibit (manager); } else { session_uninhibit (manager); } } static void update_viewer_appeared_cb (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) { GsdUpdatesManager *manager = GSD_UPDATES_MANAGER (user_data); /* close any existing notification */ if (manager->priv->notification_updates != NULL) { g_debug ("update viewer on the bus, clearing bubble"); notify_notification_close (manager->priv->notification_updates, NULL); manager->priv->notification_updates = NULL; } } static gboolean file_exists_in_root (const gchar *root, const gchar *filename) { gboolean ret = FALSE; GFile *source; gchar *source_path; source_path = g_build_filename (root, filename, NULL); source = g_file_new_for_path (source_path); /* ignore virtual mountpoints */ if (!g_file_is_native (source)) goto out; /* an interesting file exists */ ret = g_file_query_exists (source, NULL); g_debug ("checking for %s: %s", source_path, ret ? "yes" : "no"); if (!ret) goto out; out: g_free (source_path); g_object_unref (source); return ret; } static void mount_added_cb (GVolumeMonitor *volume_monitor, GMount *mount, GsdUpdatesManager *manager) { gboolean ret = FALSE; gchar **filenames = NULL; gchar *media_repo_filenames; gchar *root_path; GFile *root; guint i; /* check if any installed media is an install disk */ root = g_mount_get_root (mount); root_path = g_file_get_path (root); /* use settings */ media_repo_filenames = g_settings_get_string (manager->priv->settings_gsd, GSD_SETTINGS_MEDIA_REPO_FILENAMES); if (media_repo_filenames == NULL) { g_warning ("failed to get media repo filenames"); goto out; } /* search each possible filename */ filenames = g_strsplit (media_repo_filenames, ",", -1); for (i=0; filenames[i] != NULL; i++) { ret = file_exists_in_root (root_path, filenames[i]); if (ret) break; } /* do an updates check with the new media */ if (ret) query_updates (manager); out: g_strfreev (filenames); g_free (media_repo_filenames); g_free (root_path); g_object_unref (root); } #define PK_OFFLINE_UPDATE_RESULTS_GROUP "PackageKit Offline Update Results" #define PK_OFFLINE_UPDATE_RESULTS_FILENAME "/var/lib/PackageKit/offline-update-competed" static gboolean check_offline_update_cb (gpointer user_data) { const gchar *message; const gchar *title; gboolean ret; gboolean success; gchar *error_code = NULL; gchar *error_details = NULL; gchar *packages = NULL; GError *error = NULL; GKeyFile *key_file = NULL; GsdUpdatesManager *manager = (GsdUpdatesManager *) user_data; guint i; guint num_packages = 1; NotifyNotification *notification; PkErrorEnum error_enum = PK_ERROR_ENUM_UNKNOWN; /* was any offline update attempted */ if (!g_file_test (PK_OFFLINE_UPDATE_RESULTS_FILENAME, G_FILE_TEST_EXISTS)) goto out; /* open the file and see what happened */ key_file = g_key_file_new (); ret = g_key_file_load_from_file (key_file, PK_OFFLINE_UPDATE_RESULTS_FILENAME, G_KEY_FILE_NONE, &error); if (!ret) { g_warning ("failed to open %s: %s", PK_OFFLINE_UPDATE_RESULTS_FILENAME, error->message); g_error_free (error); goto out; } success = g_key_file_get_boolean (key_file, PK_OFFLINE_UPDATE_RESULTS_GROUP, "Success", NULL); if (success) { packages = g_key_file_get_string (key_file, PK_OFFLINE_UPDATE_RESULTS_GROUP, "Packages", NULL); if (packages == NULL) { g_warning ("No 'Packages' in %s", PK_OFFLINE_UPDATE_RESULTS_FILENAME); goto out; } /* count the packages for translators */ for (i = 0; packages[i] != '\0'; i++) { if (packages[i] == ',') num_packages++; } /* TRANSLATORS: title in the libnotify popup */ title = ngettext ("Software Update Installed", "Software Updates Installed", num_packages); /* TRANSLATORS: message when we've done offline updates */ message = ngettext ("An important OS update has been installed.", "Important OS updates have been installed.", num_packages); /* no need to keep the file around anymore */ clear_offline_updates_message (); } else { /* get error details */ manager->priv->offline_update_error = pk_error_new (); error_code = g_key_file_get_string (key_file, PK_OFFLINE_UPDATE_RESULTS_GROUP, "ErrorCode", NULL); if (error_code != NULL) error_enum = pk_error_enum_from_string (error_code); error_details = g_key_file_get_string (key_file, PK_OFFLINE_UPDATE_RESULTS_GROUP, "ErrorDetails", NULL); g_object_set (manager->priv->offline_update_error, "code", error_enum, "details", error_details, NULL); /* TRANSLATORS: title in the libnotify popup */ title = _("Software Updates Failed"); /* TRANSLATORS: message when we've not done offline updates */ message = _("An important OS update failed to be installed."); } /* do the bubble */ g_debug ("title=%s, message=%s", title, message); notification = notify_notification_new (title, message, GSD_UPDATES_ICON_URGENT); notify_notification_set_hint_string (notification, "desktop-entry", "gpk-update-viewer"); notify_notification_set_app_name (notification, _("Software Updates")); notify_notification_set_timeout (notification, -1); notify_notification_set_urgency (notification, NOTIFY_URGENCY_NORMAL); if (success) { #if 0 notify_notification_add_action (notification, "review-offline-updates", /* TRANSLATORS: button: review the offline update changes */ _("Review"), libnotify_action_cb, manager, NULL); #endif } else { notify_notification_add_action (notification, "error-offline-updates", /* TRANSLATORS: button: review the offline update changes */ _("Show details"), libnotify_action_cb, manager, NULL); } notify_notification_add_action (notification, "clear-offline-updates", /* TRANSLATORS: button: clear notification */ _("OK"), libnotify_action_cb, manager, NULL); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); ret = notify_notification_show (notification, &error); if (!ret) { g_warning ("error: %s", error->message); g_error_free (error); } out: g_free (packages); g_free (error_code); g_free (error_details); if (key_file != NULL) g_key_file_free (key_file); manager->priv->offline_update_id = 0; return FALSE; } gboolean gsd_updates_manager_start (GsdUpdatesManager *manager, GError **error) { gboolean ret = FALSE; g_debug ("Starting updates manager"); /* use PackageKit */ manager->priv->cancellable = g_cancellable_new (); manager->priv->control = pk_control_new (); g_signal_connect (manager->priv->control, "notify::locked", G_CALLBACK (notify_locked_cb), manager); manager->priv->task = pk_task_new (); g_object_set (manager->priv->task, "background", TRUE, "interactive", FALSE, #if PK_CHECK_VERSION(0,8,1) "only-download", TRUE, #endif NULL); /* watch UDev for missing firmware */ manager->priv->firmware = gsd_updates_firmware_new (); /* get automatic callbacks about when we should check for * updates, refresh-caches and upgrades */ manager->priv->refresh = gsd_updates_refresh_new (); g_signal_connect (manager->priv->refresh, "get-upgrades", G_CALLBACK (due_get_upgrades_cb), manager); g_signal_connect (manager->priv->refresh, "refresh-cache", G_CALLBACK (due_refresh_cache_cb), manager); g_signal_connect (manager->priv->refresh, "get-updates", G_CALLBACK (due_get_updates_cb), manager); /* get proxy settings */ manager->priv->settings_proxy = g_settings_new ("org.gnome.system.proxy"); g_signal_connect (manager->priv->settings_proxy, "changed", G_CALLBACK (settings_changed_cb), manager); /* get http settings */ manager->priv->settings_http = g_settings_new ("org.gnome.system.proxy.http"); g_signal_connect (manager->priv->settings_http, "changed", G_CALLBACK (settings_changed_cb), manager); /* get ftp settings */ manager->priv->settings_ftp = g_settings_new ("org.gnome.system.proxy.ftp"); g_signal_connect (manager->priv->settings_ftp, "changed", G_CALLBACK (settings_changed_cb), manager); /* get ftp settings */ manager->priv->settings_gsd = g_settings_new ("org.gnome.settings-daemon.plugins.updates"); g_signal_connect (manager->priv->settings_gsd, "changed", G_CALLBACK (settings_gsd_changed_cb), manager); /* use gnome-session for the idle detection */ manager->priv->proxy_session = gnome_settings_session_get_session_proxy (); if (manager->priv->proxy_session == NULL) goto out; /* if the update viewer is started, then hide the notification */ manager->priv->update_viewer_watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION, "org.freedesktop.PackageKit.UpdateViewer", G_BUS_NAME_WATCHER_FLAGS_NONE, update_viewer_appeared_cb, NULL, manager, NULL); /* get a volume monitor so we can watch media */ manager->priv->volume_monitor = g_volume_monitor_get (); g_signal_connect (manager->priv->volume_monitor, "mount-added", G_CALLBACK (mount_added_cb), manager); /* coldplug */ reload_proxy_settings (manager); /* check for offline update */ manager->priv->offline_update_id = g_timeout_add_seconds (GSD_UPDATES_CHECK_OFFLINE_TIMEOUT, check_offline_update_cb, manager); /* success */ ret = TRUE; g_debug ("Started updates manager"); out: return ret; } void gsd_updates_manager_stop (GsdUpdatesManager *manager) { g_debug ("Stopping updates manager"); g_clear_object (&manager->priv->settings_proxy); g_clear_object (&manager->priv->settings_http); g_clear_object (&manager->priv->settings_ftp); g_clear_object (&manager->priv->settings_gsd); g_clear_object (&manager->priv->control); g_clear_object (&manager->priv->task); g_clear_object (&manager->priv->refresh); g_clear_object (&manager->priv->firmware); g_clear_object (&manager->priv->proxy_session); g_clear_object (&manager->priv->volume_monitor); if (manager->priv->cancellable) { g_cancellable_cancel (manager->priv->cancellable); g_clear_object (&manager->priv->cancellable); } if (manager->priv->update_viewer_watcher_id != 0) { g_bus_unwatch_name (manager->priv->update_viewer_watcher_id); manager->priv->update_viewer_watcher_id = 0; } if (manager->priv->offline_update_id) { g_source_remove (manager->priv->offline_update_id); manager->priv->offline_update_id = 0; } if (manager->priv->update_packages != NULL) { g_ptr_array_unref (manager->priv->update_packages); manager->priv->update_packages = NULL; } g_clear_object (&manager->priv->offline_update_error); } static GObject * gsd_updates_manager_constructor ( GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GsdUpdatesManager *m; m = GSD_UPDATES_MANAGER (G_OBJECT_CLASS (gsd_updates_manager_parent_class)->constructor ( type, n_construct_properties, construct_properties)); return G_OBJECT (m); } static void gsd_updates_manager_dispose (GObject *object) { GsdUpdatesManager *manager; manager = GSD_UPDATES_MANAGER (object); gsd_updates_manager_stop (manager); G_OBJECT_CLASS (gsd_updates_manager_parent_class)->dispose (object); } static void gsd_updates_manager_class_init (GsdUpdatesManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = gsd_updates_manager_constructor; object_class->dispose = gsd_updates_manager_dispose; g_type_class_add_private (klass, sizeof (GsdUpdatesManagerPrivate)); } static void gsd_updates_manager_init (GsdUpdatesManager *manager) { manager->priv = GSD_UPDATES_MANAGER_GET_PRIVATE (manager); } GsdUpdatesManager * gsd_updates_manager_new (void) { if (manager_object) { g_object_ref (manager_object); } else { manager_object = g_object_new (GSD_TYPE_UPDATES_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return GSD_UPDATES_MANAGER (manager_object); } unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/gsd-updates-firmware.h0000644000015300001610000000367012567031542030031 0ustar pbuserpbgroup00000000000000/* -*- 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 __GSD_UPDATES_FIRMWARE_H #define __GSD_UPDATES_FIRMWARE_H #include G_BEGIN_DECLS #define GSD_UPDATES_TYPE_FIRMWARE (gsd_updates_firmware_get_type ()) #define GSD_UPDATES_FIRMWARE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_UPDATES_TYPE_FIRMWARE, GsdUpdatesFirmware)) #define GSD_UPDATES_FIRMWARE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_UPDATES_TYPE_FIRMWARE, GsdUpdatesFirmwareClass)) #define GSD_UPDATES_IS_FIRMWARE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_UPDATES_TYPE_FIRMWARE)) typedef struct GsdUpdatesFirmwarePrivate GsdUpdatesFirmwarePrivate; typedef struct { GObject parent; GsdUpdatesFirmwarePrivate *priv; } GsdUpdatesFirmware; typedef struct { GObjectClass parent_class; } GsdUpdatesFirmwareClass; GType gsd_updates_firmware_get_type (void); GsdUpdatesFirmware *gsd_updates_firmware_new (void); G_END_DECLS #endif /* __GSD_UPDATES_FIRMWARE_H */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/gsd-updates-manager.h0000644000015300001610000000420512567031542027622 0ustar pbuserpbgroup00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __GSD_UPDATES_MANAGER_H #define __GSD_UPDATES_MANAGER_H #include #include G_BEGIN_DECLS #define GSD_TYPE_UPDATES_MANAGER (gsd_updates_manager_get_type ()) #define GSD_UPDATES_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_UPDATES_MANAGER, GsdUpdatesManager)) #define GSD_UPDATES_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GSD_TYPE_UPDATES_MANAGER, GsdUpdatesManagerClass)) #define GSD_IS_UPDATES_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_UPDATES_MANAGER)) #define GSD_IS_UPDATES_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_UPDATES_MANAGER)) #define GSD_UPDATES_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_UPDATES_MANAGER, GsdUpdatesManagerClass)) typedef struct GsdUpdatesManagerPrivate GsdUpdatesManagerPrivate; typedef struct { GObject parent; GsdUpdatesManagerPrivate *priv; } GsdUpdatesManager; typedef struct { GObjectClass parent_class; } GsdUpdatesManagerClass; GType gsd_updates_manager_get_type (void) G_GNUC_CONST; GsdUpdatesManager *gsd_updates_manager_new (void); gboolean gsd_updates_manager_start (GsdUpdatesManager *manager, GError **error); void gsd_updates_manager_stop (GsdUpdatesManager *manager); G_END_DECLS #endif /* __GSD_UPDATES_MANAGER_H */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/gsd-updates-firmware.c0000644000015300001610000010750412567031542030025 0ustar pbuserpbgroup00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007-2012 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 #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include #include #include #ifdef HAVE_GUDEV #include #endif #include "gsd-updates-common.h" #include "gsd-updates-firmware.h" static void gsd_updates_firmware_finalize (GObject *object); #define GSD_UPDATES_FIRMWARE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_UPDATES_TYPE_FIRMWARE, GsdUpdatesFirmwarePrivate)) #define GSD_UPDATES_FIRMWARE_MISSING_DIR "/run/udev/firmware-missing" #define GSD_UPDATES_FIRMWARE_LOADING_DIR "/lib/firmware" #define GSD_UPDATES_FIRMWARE_LOGIN_DELAY 10 /* seconds */ #define GSD_UPDATES_FIRMWARE_PROCESS_DELAY 2 /* seconds */ #define GSD_UPDATES_FIRMWARE_INSERT_DELAY 2 /* seconds */ #define GSD_UPDATES_FIRMWARE_DEVICE_REBIND_PROGRAM "/usr/sbin/pk-device-rebind" struct GsdUpdatesFirmwarePrivate { GSettings *settings; GFileMonitor *monitor; GPtrArray *array_requested; PkTask *task; GPtrArray *packages_found; guint timeout_id; }; typedef enum { FIRMWARE_SUBSYSTEM_USB, FIRMWARE_SUBSYSTEM_PCI, FIRMWARE_SUBSYSTEM_UNKNOWN } FirmwareSubsystem; typedef struct { gchar *filename; gchar *sysfs_path; gchar *model; gchar *id; FirmwareSubsystem subsystem; } GsdUpdatesFirmwareRequest; G_DEFINE_TYPE (GsdUpdatesFirmware, gsd_updates_firmware, G_TYPE_OBJECT) static void install_package_ids (GsdUpdatesFirmware *firmware); static void ignore_devices (GsdUpdatesFirmware *firmware); static gboolean subsystem_can_replug (FirmwareSubsystem subsystem) { if (subsystem == FIRMWARE_SUBSYSTEM_USB) return TRUE; return FALSE; } static GsdUpdatesFirmwareRequest * request_new (const gchar *filename, const gchar *sysfs_path) { GsdUpdatesFirmwareRequest *req; #ifdef HAVE_GUDEV GUdevDevice *device; GUdevClient *client; const gchar *subsystem; const gchar *model; const gchar *id_vendor; const gchar *id_product; #endif req = g_new0 (GsdUpdatesFirmwareRequest, 1); req->filename = g_strdup (filename); req->sysfs_path = g_strdup (sysfs_path); req->subsystem = FIRMWARE_SUBSYSTEM_UNKNOWN; #ifdef HAVE_GUDEV /* get all subsystems */ client = g_udev_client_new (NULL); device = g_udev_client_query_by_sysfs_path (client, sysfs_path); if (device == NULL) goto out; /* find subsystem, which will affect if we have to replug, or reboot */ subsystem = g_udev_device_get_subsystem (device); if (g_strcmp0 (subsystem, "usb") == 0) { req->subsystem = FIRMWARE_SUBSYSTEM_USB; } else if (g_strcmp0 (subsystem, "pci") == 0) { req->subsystem = FIRMWARE_SUBSYSTEM_PCI; } else { g_warning ("subsystem unrecognised: %s", subsystem); } /* get model, so we can show something sensible */ model = g_udev_device_get_property (device, "ID_MODEL"); if (model != NULL && model[0] != '\0') { req->model = g_strdup (model); /* replace invalid chars */ g_strdelimit (req->model, "_", ' '); } /* create ID so we can ignore the specific device */ id_vendor = g_udev_device_get_property (device, "ID_VENDOR"); id_product = g_udev_device_get_property (device, "ID_MODEL_ID"); req->id = g_strdup_printf ("%s_%s", id_vendor, id_product); out: if (device != NULL) g_object_unref (device); g_object_unref (client); #endif return req; } static void request_free (GsdUpdatesFirmwareRequest *req) { g_free (req->filename); g_free (req->model); g_free (req->sysfs_path); g_free (req->id); g_free (req); } static gboolean device_rebind (GsdUpdatesFirmware *firmware) { gboolean ret; gchar *argv[4]; gchar *rebind_stderr = NULL; gchar *rebind_stdout = NULL; GError *error = NULL; gint exit_status = 0; guint i; GPtrArray *array; const GsdUpdatesFirmwareRequest *req; GString *string; string = g_string_new (""); /* make a string array of all the devices to replug */ array = firmware->priv->array_requested; for (i=0; ilen; i++) { req = g_ptr_array_index (array, i); g_string_append_printf (string, "%s ", req->sysfs_path); } /* remove trailing space */ if (string->len > 0) g_string_set_size (string, string->len-1); /* use PolicyKit to do this as root */ argv[0] = "pkexec"; argv[1] = GSD_UPDATES_FIRMWARE_DEVICE_REBIND_PROGRAM; argv[2] = string->str; argv[3] = NULL; ret = g_spawn_sync (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &rebind_stdout, &rebind_stderr, &exit_status, &error); if (!ret) { g_warning ("failed to spawn '%s': %s", argv[1], error->message); g_error_free (error); goto out; } /* if we failed to rebind the device */ if (exit_status != 0) { g_warning ("failed to rebind: %s, %s", rebind_stdout, rebind_stderr); ret = FALSE; goto out; } out: g_free (rebind_stdout); g_free (rebind_stderr); g_string_free (string, TRUE); return ret; } static void libnotify_cb (NotifyNotification *notification, gchar *action, gpointer data) { GsdUpdatesFirmware *firmware = GSD_UPDATES_FIRMWARE (data); if (g_strcmp0 (action, "install-firmware") == 0) { install_package_ids (firmware); } else if (g_strcmp0 (action, "ignore-devices") == 0) { ignore_devices (firmware); } else { g_warning ("unknown action id: %s", action); } notify_notification_close (notification, NULL); } static void on_notification_closed (NotifyNotification *notification, gpointer data) { g_object_unref (notification); } static void require_restart (GsdUpdatesFirmware *firmware) { const gchar *message; gboolean ret; GError *error = NULL; NotifyNotification *notification; /* TRANSLATORS: we need to restart so the new hardware can re-request the firmware */ message = _("You will need to restart this computer before the hardware will work correctly."); /* TRANSLATORS: title of libnotify bubble */ notification = notify_notification_new (_("Additional software was installed"), message, NULL); notify_notification_set_hint_string (notification, "desktop-entry", "gpk-update-viewer"); notify_notification_set_app_name (notification, _("Software Updates")); notify_notification_set_timeout (notification, NOTIFY_EXPIRES_NEVER); notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); /* show the bubble */ ret = notify_notification_show (notification, &error); if (!ret) { g_warning ("error: %s", error->message); g_error_free (error); } } static void require_replug (GsdUpdatesFirmware *firmware) { const gchar *message; gboolean ret; GError *error = NULL; NotifyNotification *notification; /* TRANSLATORS: we need to remove an replug so the new hardware can re-request the firmware */ message = _("You will need to remove and then reinsert the hardware before it will work correctly."); /* TRANSLATORS: title of libnotify bubble */ notification = notify_notification_new (_("Additional software was installed"), message, NULL); notify_notification_set_hint_string (notification, "desktop-entry", "gpk-update-viewer"); notify_notification_set_app_name (notification, _("Software Updates")); notify_notification_set_timeout (notification, NOTIFY_EXPIRES_NEVER); notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); /* show the bubble */ ret = notify_notification_show (notification, &error); if (!ret) { g_warning ("error: %s", error->message); g_error_free (error); } } static void require_nothing (GsdUpdatesFirmware *firmware) { const gchar *message; gboolean ret; GError *error = NULL; NotifyNotification *notification; /* TRANSLATORS: we need to remove an replug so the new hardware can re-request the firmware */ message = _("Your hardware has been set up and is now ready to use."); /* TRANSLATORS: title of libnotify bubble */ notification = notify_notification_new (_("Additional software was installed"), message, NULL); notify_notification_set_hint_string (notification, "desktop-entry", "gpk-update-viewer"); notify_notification_set_app_name (notification, _("Software Updates")); notify_notification_set_timeout (notification, NOTIFY_EXPIRES_NEVER); notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); /* show the bubble */ ret = notify_notification_show (notification, &error); if (!ret) { g_warning ("error: %s", error->message); g_error_free (error); } } static void install_packages_cb (GObject *object, GAsyncResult *res, GsdUpdatesFirmware *firmware) { PkClient *client = PK_CLIENT (object); GError *error = NULL; PkResults *results = NULL; GPtrArray *array = NULL; gboolean restart = FALSE; const GsdUpdatesFirmwareRequest *req; gboolean ret; guint i; PkError *error_code = NULL; /* get the results */ results = pk_client_generic_finish (client, res, &error); if (results == NULL) { g_warning ("failed to install file: %s", error->message); g_error_free (error); goto out; } /* check error code */ error_code = pk_results_get_error_code (results); if (error_code != NULL) { g_warning ("failed to install file: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code)); goto out; } /* go through all the requests, and find the worst type */ array = firmware->priv->array_requested; for (i=0; ilen; i++) { req = g_ptr_array_index (array, i); ret = subsystem_can_replug (req->subsystem); if (!ret) { restart = TRUE; break; } } /* can we just rebind the device */ ret = g_file_test (GSD_UPDATES_FIRMWARE_DEVICE_REBIND_PROGRAM, G_FILE_TEST_EXISTS); if (ret) { ret = device_rebind (firmware); if (ret) { require_nothing (firmware); goto out; } } else { /* give the user the correct message */ if (restart) require_restart (firmware); else require_replug (firmware); } /* clear array */ g_ptr_array_set_size (firmware->priv->array_requested, 0); out: if (error_code != NULL) g_object_unref (error_code); if (array != NULL) g_ptr_array_unref (array); if (results != NULL) g_object_unref (results); } static gchar ** package_array_to_strv (GPtrArray *array) { PkPackage *item; gchar **results; guint i; results = g_new0 (gchar *, array->len+1); for (i=0; ilen; i++) { item = g_ptr_array_index (array, i); results[i] = g_strdup (pk_package_get_id (item)); } return results; } static void install_package_ids (GsdUpdatesFirmware *firmware) { gchar **package_ids; /* install all of the firmware files */ package_ids = package_array_to_strv (firmware->priv->packages_found); pk_client_install_packages_async (PK_CLIENT(firmware->priv->task), TRUE, package_ids, NULL, NULL, NULL, (GAsyncReadyCallback) install_packages_cb, firmware); g_strfreev (package_ids); } static void ignore_devices (GsdUpdatesFirmware *firmware) { gchar *existing = NULL; GsdUpdatesFirmwareRequest *req; GPtrArray *array; GString *string; guint i; /* get from settings */ existing = g_settings_get_string (firmware->priv->settings, GSD_SETTINGS_IGNORED_DEVICES); /* get existing string */ string = g_string_new (existing); if (string->len > 0) g_string_append (string, ","); /* add all listed devices */ array = firmware->priv->array_requested; for (i=0; ilen; i++) { req = g_ptr_array_index (array, i); g_string_append_printf (string, "%s,", req->id); } /* remove final ',' */ if (string->len > 2) g_string_set_size (string, string->len - 1); /* set new string */ g_settings_set_string (firmware->priv->settings, GSD_SETTINGS_IGNORED_DEVICES, string->str); g_free (existing); g_string_free (string, TRUE); } static PkPackage * check_available (GsdUpdatesFirmware *firmware, const gchar *filename) { guint length = 0; GPtrArray *array = NULL; GError *error = NULL; PkPackage *item = NULL; PkBitfield filter; PkResults *results; gchar **values = NULL; PkError *error_code = NULL; /* search for newest not installed package */ filter = pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_INSTALLED, PK_FILTER_ENUM_NEWEST, -1); values = g_strsplit (filename, "&", -1); results = pk_client_search_files (PK_CLIENT(firmware->priv->task), filter, values, NULL, NULL, NULL, &error); if (results == NULL) { g_warning ("failed to search file %s: %s", filename, error->message); g_error_free (error); goto out; } /* check error code */ error_code = pk_results_get_error_code (results); if (error_code != NULL) { g_warning ("failed to search file: %s, %s", pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code)); goto out; } /* make sure we have one package */ array = pk_results_get_package_array (results); if (array->len == 0) g_debug ("no package providing %s found", filename); else if (array->len != 1) g_warning ("not one package providing %s found (%i)", filename, length); else item = g_object_ref (g_ptr_array_index (array, 0)); out: g_strfreev (values); if (error_code != NULL) g_object_unref (error_code); if (array != NULL) g_ptr_array_unref (array); if (results != NULL) g_object_unref (results); return item; } static void remove_duplicate (GPtrArray *array) { guint i, j; const gchar *val; const gchar *val_tmp; /* remove each duplicate entry */ for (i=0; ilen; i++) { val = g_ptr_array_index (array, i); for (j=i+1; jlen; j++) { val_tmp = g_ptr_array_index (array, j); if (g_strcmp0 (val_tmp, val) == 0) g_ptr_array_remove_index_fast (array, j); } } } static gboolean delay_timeout_cb (gpointer data) { guint i; gboolean ret; GString *string; GsdUpdatesFirmware *firmware = GSD_UPDATES_FIRMWARE (data); NotifyNotification *notification; GPtrArray *array; GError *error = NULL; PkPackage *item = NULL; const GsdUpdatesFirmwareRequest *req; gboolean has_data = FALSE; /* message string */ string = g_string_new (""); /* try to find each firmware file in an available package */ array = firmware->priv->array_requested; for (i=0; ilen; i++) { req = g_ptr_array_index (array, i); /* save to new array if we found one package for this file */ item = check_available (firmware, req->filename); if (item != NULL) { g_ptr_array_add (firmware->priv->packages_found, item); g_object_unref (item); } } /* nothing to do */ if (firmware->priv->packages_found->len == 0) { g_debug ("no packages providing any of the missing firmware"); goto out; } /* check we don't want the same package more than once */ remove_duplicate (firmware->priv->packages_found); /* have we got any models to array */ for (i=0; ilen; i++) { req = g_ptr_array_index (array, i); if (req->model != NULL) { has_data = TRUE; break; } } /* TRANSLATORS: we need another package to keep udev quiet */ g_string_append (string, _("Additional firmware is required to make hardware in this computer function correctly.")); /* sdd what information we have */ if (has_data) { g_string_append (string, "\n"); for (i=0; ilen; i++) { req = g_ptr_array_index (array, i); if (req->model != NULL) g_string_append_printf (string, "\n• %s", req->model); } g_string_append (string, "\n"); } /* TRANSLATORS: title of libnotify bubble */ notification = notify_notification_new (_("Additional firmware required"), string->str, NULL); notify_notification_set_hint_string (notification, "desktop-entry", "gpk-update-viewer"); notify_notification_set_app_name (notification, _("Software Updates")); notify_notification_set_timeout (notification, NOTIFY_EXPIRES_NEVER); notify_notification_set_urgency (notification, NOTIFY_URGENCY_LOW); notify_notification_add_action (notification, "install-firmware", /* TRANSLATORS: button label */ _("Install firmware"), libnotify_cb, firmware, NULL); notify_notification_add_action (notification, "ignore-devices", /* TRANSLATORS: we should ignore this device and not ask anymore */ _("Ignore devices"), libnotify_cb, firmware, NULL); g_signal_connect (notification, "closed", G_CALLBACK (on_notification_closed), NULL); ret = notify_notification_show (notification, &error); if (!ret) { g_warning ("error: %s", error->message); g_error_free (error); } out: g_string_free (string, TRUE); /* never repeat */ return FALSE; } static void remove_banned (GsdUpdatesFirmware *firmware, GPtrArray *array) { gboolean ret; gchar **banned = NULL; gchar *banned_str; GsdUpdatesFirmwareRequest *req; guint i, j; /* get from settings */ banned_str = g_settings_get_string (firmware->priv->settings, GSD_SETTINGS_BANNED_FIRMWARE); if (banned_str == NULL) { g_warning ("could not read banned list"); goto out; } /* nothing in list, common case */ if (banned_str[0] == '\0') { g_debug ("nothing in banned list"); goto out; } /* split using "," */ banned = g_strsplit (banned_str, ",", 0); /* remove any banned pattern matches */ i = 0; while (i < array->len) { ret = FALSE; req = g_ptr_array_index (array, i); for (j=0; banned[j] != NULL; j++) { ret = g_pattern_match_simple (banned[j], req->filename); if (ret) { g_debug ("match %s for %s, removing", banned[j], req->filename); g_ptr_array_remove_index_fast (array, i); break; } } if (!ret) i++; } out: g_free (banned_str); g_strfreev (banned); } static void remove_ignored (GsdUpdatesFirmware *firmware, GPtrArray *array) { gboolean ret; gchar **ignored = NULL; gchar *ignored_str; GsdUpdatesFirmwareRequest *req; guint i, j; /* get from settings */ ignored_str = g_settings_get_string (firmware->priv->settings, GSD_SETTINGS_IGNORED_DEVICES); if (ignored_str == NULL) { g_warning ("could not read ignored list"); goto out; } /* nothing in list, common case */ if (ignored_str[0] == '\0') { g_debug ("nothing in ignored list"); goto out; } /* split using "," */ ignored = g_strsplit (ignored_str, ",", 0); /* remove any ignored pattern matches */ i = 0; while (i < array->len) { ret = FALSE; req = g_ptr_array_index (array, i); if (req->id == NULL) continue; for (j=0; ignored[j] != NULL; j++) { ret = g_pattern_match_simple (ignored[j], req->id); if (ret) { g_debug ("match %s for %s, removing", ignored[j], req->id); g_ptr_array_remove_index_fast (array, i); break; } } if (!ret) i++; } out: g_free (ignored_str); g_strfreev (ignored); } static gchar * udev_text_decode (const gchar *data) { guint i; guint j; gchar *decode; decode = g_strdup (data); for (i = 0, j = 0; data[i] != '\0'; j++) { if (memcmp (&data[i], "\\x2f", 4) == 0) { decode[j] = '/'; i += 4; } else if (memcmp (&data[i], "\\x5c", 4) == 0) { decode[j] = '\\'; i += 4; } else { decode[j] = data[i]; i++; } } decode[j] = '\0'; return decode; } static gchar * get_device (GsdUpdatesFirmware *firmware, const gchar *filename) { GFile *file; GFileInfo *info; const gchar *symlink_path; gchar *syspath = NULL; GError *error = NULL; gchar *target = NULL; gchar *tmp; /* get the file data */ file = g_file_new_for_path (filename); info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET, G_FILE_QUERY_INFO_NONE, NULL, &error); if (info == NULL) { g_warning ("Failed to get symlink: %s", error->message); g_error_free (error); goto out; } /* /devices/pci0000:00/0000:00:1d.0/usb5/5-2/firmware/5-2 */ symlink_path = g_file_info_get_symlink_target (info); if (symlink_path == NULL) { g_warning ("failed to get symlink target"); goto out; } /* prepend sys to make '/sys/devices/pci0000:00/0000:00:1d.0/usb5/5-2/firmware/5-2' */ syspath = g_strconcat ("/sys", symlink_path, NULL); /* start with the longest, and try to find a sub-path that exists */ tmp = &syspath[strlen (syspath)]; while (tmp != NULL) { *tmp = '\0'; g_debug ("testing %s", target); if (g_file_test (syspath, G_FILE_TEST_EXISTS)) { target = g_strdup (syspath); goto out; } tmp = g_strrstr (syspath, "/"); } out: if (info != NULL) g_object_unref (info); g_object_unref (file); g_free (syspath); return target; } static void add_filename (GsdUpdatesFirmware *firmware, const gchar *filename_no_path) { gboolean ret; gchar *filename_path = NULL; gchar *missing_path = NULL; gchar *sysfs_path = NULL; GsdUpdatesFirmwareRequest *req; GPtrArray *array; guint i; /* this is the file we want to load */ filename_path = g_build_filename (GSD_UPDATES_FIRMWARE_LOADING_DIR, filename_no_path, NULL); /* file already exists */ ret = g_file_test (filename_path, G_FILE_TEST_EXISTS); if (ret) goto out; /* this is the file that udev created for us */ missing_path = g_build_filename (GSD_UPDATES_FIRMWARE_MISSING_DIR, filename_no_path, NULL); g_debug ("filename=%s -> %s", missing_path, filename_path); /* get symlink target */ sysfs_path = get_device (firmware, missing_path); if (sysfs_path == NULL) goto out; /* find any previous requests with this path or firmware */ array = firmware->priv->array_requested; for (i=0; ilen; i++) { req = g_ptr_array_index (array, i); if (g_strcmp0 (sysfs_path, req->sysfs_path) == 0) { g_debug ("ignoring previous sysfs request for %s", sysfs_path); goto out; } if (g_strcmp0 (filename_path, req->filename) == 0) { g_debug ("ignoring previous filename request for %s", filename_path); goto out; } } /* create new request object */ req = request_new (filename_path, sysfs_path); g_ptr_array_add (firmware->priv->array_requested, req); out: g_free (missing_path); g_free (filename_path); g_free (sysfs_path); } static void scan_directory (GsdUpdatesFirmware *firmware) { gboolean ret; GError *error = NULL; GDir *dir; const gchar *filename; gchar *filename_decoded; guint i; GPtrArray *array; const GsdUpdatesFirmwareRequest *req; guint scan_id = 0; /* should we check and show the user */ ret = g_settings_get_boolean (firmware->priv->settings, GSD_SETTINGS_ENABLE_CHECK_FIRMWARE); if (!ret) { g_debug ("not showing thanks to GSettings"); return; } /* open the directory of requests */ dir = g_dir_open (GSD_UPDATES_FIRMWARE_MISSING_DIR, 0, &error); if (dir == NULL) { if (error->code != G_FILE_ERROR_NOENT) { g_warning ("failed to open directory: %s", error->message); } g_error_free (error); return; } /* find all the firmware requests */ filename = g_dir_read_name (dir); while (filename != NULL) { filename_decoded = udev_text_decode (filename); add_filename (firmware, filename_decoded); g_free (filename_decoded); /* next file */ filename = g_dir_read_name (dir); } g_dir_close (dir); /* debugging */ array = firmware->priv->array_requested; for (i=0; ilen; i++) { req = g_ptr_array_index (array, i); g_debug ("requested: %s", req->filename); } /* remove banned files */ remove_banned (firmware, array); /* remove ignored devices */ remove_ignored (firmware, array); /* debugging */ array = firmware->priv->array_requested; for (i=0; ilen; i++) { req = g_ptr_array_index (array, i); g_debug ("searching for: %s", req->filename); } /* don't spam the user at startup, so wait a little delay */ if (array->len > 0) { scan_id = g_timeout_add_seconds (GSD_UPDATES_FIRMWARE_PROCESS_DELAY, delay_timeout_cb, firmware); g_source_set_name_by_id (scan_id, "[GsdUpdatesFirmware] process"); } } static gboolean scan_directory_cb (GsdUpdatesFirmware *firmware) { scan_directory (firmware); firmware->priv->timeout_id = 0; return FALSE; } static void monitor_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, GsdUpdatesFirmware *firmware) { if (firmware->priv->timeout_id > 0) { g_debug ("clearing timeout as device changed"); g_source_remove (firmware->priv->timeout_id); } /* wait for the device to settle */ firmware->priv->timeout_id = g_timeout_add_seconds (GSD_UPDATES_FIRMWARE_INSERT_DELAY, (GSourceFunc) scan_directory_cb, firmware); g_source_set_name_by_id (firmware->priv->timeout_id, "[GsdUpdatesFirmware] changed"); } static void gsd_updates_firmware_class_init (GsdUpdatesFirmwareClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gsd_updates_firmware_finalize; g_type_class_add_private (klass, sizeof (GsdUpdatesFirmwarePrivate)); } static void gsd_updates_firmware_init (GsdUpdatesFirmware *firmware) { GFile *file; GError *error = NULL; firmware->priv = GSD_UPDATES_FIRMWARE_GET_PRIVATE (firmware); firmware->priv->timeout_id = 0; firmware->priv->packages_found = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); firmware->priv->array_requested = g_ptr_array_new_with_free_func ((GDestroyNotify) request_free); firmware->priv->settings = g_settings_new (GSD_SETTINGS_SCHEMA); firmware->priv->task = pk_task_new (); g_object_set (firmware->priv->task, "background", TRUE, NULL); /* setup watch for new hardware */ file = g_file_new_for_path (GSD_UPDATES_FIRMWARE_MISSING_DIR); firmware->priv->monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, &error); if (firmware->priv->monitor == NULL) { g_warning ("failed to setup monitor: %s", error->message); g_error_free (error); goto out; } /* limit to one per second */ g_file_monitor_set_rate_limit (firmware->priv->monitor, 1000); /* get notified of changes */ g_signal_connect (firmware->priv->monitor, "changed", G_CALLBACK (monitor_changed_cb), firmware); out: g_object_unref (file); firmware->priv->timeout_id = g_timeout_add_seconds (GSD_UPDATES_FIRMWARE_LOGIN_DELAY, (GSourceFunc) scan_directory_cb, firmware); g_source_set_name_by_id (firmware->priv->timeout_id, "[GsdUpdatesFirmware] login coldplug"); } static void gsd_updates_firmware_finalize (GObject *object) { GsdUpdatesFirmware *firmware; g_return_if_fail (GSD_UPDATES_IS_FIRMWARE (object)); firmware = GSD_UPDATES_FIRMWARE (object); g_return_if_fail (firmware->priv != NULL); g_ptr_array_unref (firmware->priv->array_requested); g_ptr_array_unref (firmware->priv->packages_found); g_object_unref (PK_CLIENT(firmware->priv->task)); g_object_unref (firmware->priv->settings); if (firmware->priv->monitor != NULL) g_object_unref (firmware->priv->monitor); if (firmware->priv->timeout_id > 0) g_source_remove (firmware->priv->timeout_id); G_OBJECT_CLASS (gsd_updates_firmware_parent_class)->finalize (object); } GsdUpdatesFirmware * gsd_updates_firmware_new (void) { GsdUpdatesFirmware *firmware; firmware = g_object_new (GSD_UPDATES_TYPE_FIRMWARE, NULL); return GSD_UPDATES_FIRMWARE (firmware); } unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/updates-design.svg0000644000015300001610000010124012567031542027253 0ustar pbuserpbgroup00000000000000 image/svg+xml Wait for refresh dueGetUpdates (typ. 1 day) GetUpdates() 'Auto download'checkbox set? Y N UpdatePackages(only-download) Any security orcritical updates? Y N Y N > notify threshold?typ. 1 week Y N 'Use Mobile'checkbox set? Y N On GPRS orCDMA? Notify the user aboutimportant updates Notify the user aboutregular updates unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/gsd-updates-plugin.c0000644000015300001610000000202412567031542027476 0ustar pbuserpbgroup00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include #include #include "gnome-settings-plugin.h" #include "gsd-updates-manager.h" GNOME_SETTINGS_PLUGIN_REGISTER (GsdUpdates, gsd_updates) unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/gsd-updates-refresh.c0000644000015300001610000004755112567031542027654 0ustar pbuserpbgroup00000000000000/* -*- 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 "gnome-settings-session.h" #include "gsd-updates-common.h" #include "gsd-updates-refresh.h" static void gsd_updates_refresh_finalize (GObject *object); #define GSD_UPDATES_REFRESH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_UPDATES_REFRESH, GsdUpdatesRefreshPrivate)) #define PERIODIC_CHECK_TIME 60*60 /* poke PackageKit every hour */ #define LOGIN_TIMEOUT 3 /* seconds */ #define SESSION_STARTUP_TIMEOUT 10 /* seconds */ enum { PRESENCE_STATUS_AVAILABLE = 0, PRESENCE_STATUS_INVISIBLE, PRESENCE_STATUS_BUSY, PRESENCE_STATUS_IDLE, PRESENCE_STATUS_UNKNOWN }; /* * at startup, after a small delay, force a GetUpdates call * every hour (or any event) check: - if we are online, idle and on AC power, it's been more than a day since we refreshed then RefreshCache - if we are online and it's been longer than the timeout since getting the updates period then GetUpdates */ struct GsdUpdatesRefreshPrivate { gboolean session_idle; gboolean on_battery; gboolean network_active; guint timeout_id; guint periodic_id; UpClient *client; GSettings *settings; GDBusProxy *proxy_session; PkControl *control; }; enum { REFRESH_CACHE, GET_UPDATES, GET_UPGRADES, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (GsdUpdatesRefresh, gsd_updates_refresh, G_TYPE_OBJECT) static void gsd_updates_refresh_class_init (GsdUpdatesRefreshClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gsd_updates_refresh_finalize; g_type_class_add_private (klass, sizeof (GsdUpdatesRefreshPrivate)); signals [REFRESH_CACHE] = g_signal_new ("refresh-cache", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals [GET_UPDATES] = g_signal_new ("get-updates", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals [GET_UPGRADES] = g_signal_new ("get-upgrades", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void get_time_refresh_cache_cb (GObject *object, GAsyncResult *res, GsdUpdatesRefresh *refresh) { PkControl *control = PK_CONTROL (object); GError *error = NULL; guint seconds; guint thresh; /* get the result */ seconds = pk_control_get_time_since_action_finish (control, res, &error); if (seconds == 0) { g_warning ("failed to get time: %s", error->message); g_error_free (error); return; } /* have we passed the timout? */ thresh = g_settings_get_int (refresh->priv->settings, GSD_SETTINGS_FREQUENCY_GET_UPDATES); if (seconds < thresh) { g_debug ("not before timeout, thresh=%u, now=%u", thresh, seconds); return; } /* send signal */ g_debug ("emitting refresh-cache"); g_signal_emit (refresh, signals [REFRESH_CACHE], 0); } static void maybe_refresh_cache (GsdUpdatesRefresh *refresh) { guint thresh; g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh)); /* if we don't want to auto check for updates, don't do this either */ thresh = g_settings_get_int (refresh->priv->settings, GSD_SETTINGS_FREQUENCY_GET_UPDATES); if (thresh == 0) { g_debug ("not when policy is set to never"); return; } /* only do the refresh cache when the user is idle */ if (!refresh->priv->session_idle) { g_debug ("not when session active"); return; } /* get this each time, as it may have changed behind out back */ thresh = g_settings_get_int (refresh->priv->settings, GSD_SETTINGS_FREQUENCY_REFRESH_CACHE); if (thresh == 0) { g_debug ("not when policy is set to never"); return; } /* get the time since the last refresh */ pk_control_get_time_since_action_async (refresh->priv->control, PK_ROLE_ENUM_REFRESH_CACHE, NULL, (GAsyncReadyCallback) get_time_refresh_cache_cb, refresh); } static void get_time_get_updates_cb (GObject *object, GAsyncResult *res, GsdUpdatesRefresh *refresh) { PkControl *control = PK_CONTROL (object); GError *error = NULL; guint seconds; guint thresh; /* get the result */ seconds = pk_control_get_time_since_action_finish (control, res, &error); if (seconds == 0) { g_warning ("failed to get time: %s", error->message); g_error_free (error); return; } /* have we passed the timout? */ thresh = g_settings_get_int (refresh->priv->settings, GSD_SETTINGS_FREQUENCY_GET_UPDATES); if (seconds < thresh) { g_debug ("not before timeout, thresh=%u, now=%u", thresh, seconds); return; } /* send signal */ g_debug ("emitting get-updates"); g_signal_emit (refresh, signals [GET_UPDATES], 0); } static void maybe_get_updates (GsdUpdatesRefresh *refresh) { guint thresh; g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh)); /* if we don't want to auto check for updates, don't do this either */ thresh = g_settings_get_int (refresh->priv->settings, GSD_SETTINGS_FREQUENCY_GET_UPDATES); if (thresh == 0) { g_debug ("not when policy is set to never"); return; } /* get the time since the last refresh */ pk_control_get_time_since_action_async (refresh->priv->control, PK_ROLE_ENUM_GET_UPDATES, NULL, (GAsyncReadyCallback) get_time_get_updates_cb, refresh); } static void get_time_get_upgrades_cb (GObject *object, GAsyncResult *res, GsdUpdatesRefresh *refresh) { PkControl *control = PK_CONTROL (object); GError *error = NULL; guint seconds; guint thresh; /* get the result */ seconds = pk_control_get_time_since_action_finish (control, res, &error); if (seconds == 0) { g_warning ("failed to get time: %s", error->message); g_error_free (error); return; } /* have we passed the timout? */ thresh = g_settings_get_int (refresh->priv->settings, GSD_SETTINGS_FREQUENCY_GET_UPDATES); if (seconds < thresh) { g_debug ("not before timeout, thresh=%u, now=%u", thresh, seconds); return; } /* send signal */ g_debug ("emitting get-upgrades"); g_signal_emit (refresh, signals [GET_UPGRADES], 0); } static void maybe_get_upgrades (GsdUpdatesRefresh *refresh) { guint thresh; g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh)); /* get this each time, as it may have changed behind out back */ thresh = g_settings_get_int (refresh->priv->settings, GSD_SETTINGS_FREQUENCY_GET_UPGRADES); if (thresh == 0) { g_debug ("not when policy is set to never"); return; } /* get the time since the last refresh */ pk_control_get_time_since_action_async (refresh->priv->control, PK_ROLE_ENUM_GET_DISTRO_UPGRADES, NULL, (GAsyncReadyCallback) get_time_get_upgrades_cb, refresh); } static gboolean change_state_cb (GsdUpdatesRefresh *refresh) { /* check all actions */ maybe_refresh_cache (refresh); maybe_get_updates (refresh); maybe_get_upgrades (refresh); return FALSE; } static gboolean change_state (GsdUpdatesRefresh *refresh) { gboolean ret; g_return_val_if_fail (GSD_IS_UPDATES_REFRESH (refresh), FALSE); /* no point continuing if we have no network */ if (!refresh->priv->network_active) { g_debug ("not when no network"); return FALSE; } /* not on battery unless overridden */ ret = g_settings_get_boolean (refresh->priv->settings, GSD_SETTINGS_UPDATE_BATTERY); if (!ret && refresh->priv->on_battery) { g_debug ("not when on battery"); return FALSE; } /* wait a little time for things to settle down */ if (refresh->priv->timeout_id != 0) g_source_remove (refresh->priv->timeout_id); g_debug ("defering action for %i seconds", SESSION_STARTUP_TIMEOUT); refresh->priv->timeout_id = g_timeout_add_seconds (SESSION_STARTUP_TIMEOUT, (GSourceFunc) change_state_cb, refresh); g_source_set_name_by_id (refresh->priv->timeout_id, "[GsdUpdatesRefresh] change-state"); return TRUE; } static void settings_key_changed_cb (GSettings *client, const gchar *key, GsdUpdatesRefresh *refresh) { g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh)); if (g_strcmp0 (key, GSD_SETTINGS_FREQUENCY_GET_UPDATES) == 0 || g_strcmp0 (key, GSD_SETTINGS_FREQUENCY_GET_UPGRADES) == 0 || g_strcmp0 (key, GSD_SETTINGS_FREQUENCY_REFRESH_CACHE) == 0 || g_strcmp0 (key, GSD_SETTINGS_UPDATE_BATTERY) == 0) change_state (refresh); } static gboolean convert_network_state (GsdUpdatesRefresh *refresh, PkNetworkEnum state) { /* offline */ if (state == PK_NETWORK_ENUM_OFFLINE) return FALSE; /* online */ if (state == PK_NETWORK_ENUM_ONLINE || state == PK_NETWORK_ENUM_WIFI || state == PK_NETWORK_ENUM_WIRED) return TRUE; /* check policy */ if (state == PK_NETWORK_ENUM_MOBILE) return g_settings_get_boolean (refresh->priv->settings, GSD_SETTINGS_CONNECTION_USE_MOBILE); /* not recognised */ g_warning ("state unknown: %i", state); return TRUE; } static void notify_network_state_cb (PkControl *control, GParamSpec *pspec, GsdUpdatesRefresh *refresh) { PkNetworkEnum state; g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh)); g_object_get (control, "network-state", &state, NULL); refresh->priv->network_active = convert_network_state (refresh, state); g_debug ("setting online %i", refresh->priv->network_active); if (refresh->priv->network_active) change_state (refresh); } static gboolean periodic_timeout_cb (gpointer user_data) { GsdUpdatesRefresh *refresh = GSD_UPDATES_REFRESH (user_data); g_return_val_if_fail (GSD_IS_UPDATES_REFRESH (refresh), FALSE); /* debug so we can catch polling */ g_debug ("polling check"); /* triggered once an hour */ change_state (refresh); /* always return */ return TRUE; } static void gsd_updates_refresh_client_changed_cb (UpClient *client, GsdUpdatesRefresh *refresh) { gboolean on_battery; g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh)); /* get the on-battery state */ on_battery = up_client_get_on_battery (refresh->priv->client); if (on_battery == refresh->priv->on_battery) { g_debug ("same state as before, ignoring"); return; } /* save in local cache */ g_debug ("setting on_battery %i", on_battery); refresh->priv->on_battery = on_battery; if (!on_battery) change_state (refresh); } static void get_properties_cb (GObject *object, GAsyncResult *res, GsdUpdatesRefresh *refresh) { PkNetworkEnum state; GError *error = NULL; PkControl *control = PK_CONTROL(object); gboolean ret; /* get the result */ ret = pk_control_get_properties_finish (control, res, &error); if (!ret) { /* TRANSLATORS: backend is broken, and won't tell us what it supports */ g_warning ("could not get properties"); g_error_free (error); goto out; } /* get values */ g_object_get (control, "network-state", &state, NULL); refresh->priv->network_active = convert_network_state (refresh, state); out: return; } static void session_presence_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, GsdUpdatesRefresh *refresh) { guint status; g_return_if_fail (GSD_IS_UPDATES_REFRESH (refresh)); if (g_strcmp0 (signal_name, "StatusChanged") != 0) return; /* map status code into boolean */ g_variant_get (parameters, "(u)", &status); refresh->priv->session_idle = (status == PRESENCE_STATUS_IDLE); g_debug ("setting is_idle %i", refresh->priv->session_idle); if (refresh->priv->session_idle) change_state (refresh); } static void gsd_updates_refresh_init (GsdUpdatesRefresh *refresh) { GVariant *status; guint status_code; refresh->priv = GSD_UPDATES_REFRESH_GET_PRIVATE (refresh); refresh->priv->on_battery = FALSE; refresh->priv->network_active = FALSE; refresh->priv->timeout_id = 0; refresh->priv->periodic_id = 0; /* we need to know the updates frequency */ refresh->priv->settings = g_settings_new (GSD_SETTINGS_SCHEMA); g_signal_connect (refresh->priv->settings, "changed", G_CALLBACK (settings_key_changed_cb), refresh); /* we need to query the last cache refresh time */ refresh->priv->control = pk_control_new (); g_signal_connect (refresh->priv->control, "notify::network-state", G_CALLBACK (notify_network_state_cb), refresh); /* get network state */ pk_control_get_properties_async (refresh->priv->control, NULL, (GAsyncReadyCallback) get_properties_cb, refresh); /* use a UpClient */ refresh->priv->client = up_client_new (); g_signal_connect (refresh->priv->client, "changed", G_CALLBACK (gsd_updates_refresh_client_changed_cb), refresh); /* get the battery state */ refresh->priv->on_battery = up_client_get_on_battery (refresh->priv->client); g_debug ("setting on battery %i", refresh->priv->on_battery); /* use gnome-session for the idle detection */ refresh->priv->proxy_session = gnome_settings_session_get_session_proxy (); if (refresh->priv->proxy_session != NULL) { g_signal_connect (refresh->priv->proxy_session, "g-signal", G_CALLBACK (session_presence_signal_cb), refresh); status = g_dbus_proxy_get_cached_property (refresh->priv->proxy_session, "status"); if (status) { g_variant_get (status, "u", &status_code); refresh->priv->session_idle = (status_code == PRESENCE_STATUS_IDLE); g_variant_unref (status); } else { refresh->priv->session_idle = FALSE; } } /* we check this in case we miss one of the async signals */ refresh->priv->periodic_id = g_timeout_add_seconds (PERIODIC_CHECK_TIME, periodic_timeout_cb, refresh); g_source_set_name_by_id (refresh->priv->periodic_id, "[GsdUpdatesRefresh] periodic check"); /* check system state */ change_state (refresh); } static void gsd_updates_refresh_finalize (GObject *object) { GsdUpdatesRefresh *refresh; g_return_if_fail (GSD_IS_UPDATES_REFRESH (object)); refresh = GSD_UPDATES_REFRESH (object); g_return_if_fail (refresh->priv != NULL); if (refresh->priv->timeout_id != 0) g_source_remove (refresh->priv->timeout_id); if (refresh->priv->periodic_id != 0) g_source_remove (refresh->priv->periodic_id); g_signal_handlers_disconnect_by_data (refresh->priv->client, refresh); g_signal_handlers_disconnect_by_data (refresh->priv->proxy_session, refresh); g_object_unref (refresh->priv->control); g_object_unref (refresh->priv->settings); g_object_unref (refresh->priv->client); if (refresh->priv->proxy_session != NULL) g_object_unref (refresh->priv->proxy_session); G_OBJECT_CLASS (gsd_updates_refresh_parent_class)->finalize (object); } GsdUpdatesRefresh * gsd_updates_refresh_new (void) { GsdUpdatesRefresh *refresh; refresh = g_object_new (GSD_TYPE_UPDATES_REFRESH, NULL); return GSD_UPDATES_REFRESH (refresh); } unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/updates.gnome-settings-plugin.in0000644000015300001610000000024112567031542032050 0ustar pbuserpbgroup00000000000000[GNOME Settings Plugin] Module=updates IAge=0 Priority=300 _Name=Updates _Description=Updates plugin Authors=Richard Hughes Copyright=Copyright © 2011 Website= unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/gsd-updates-refresh.h0000644000015300001610000000361212567031542027647 0ustar pbuserpbgroup00000000000000/* -*- 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. */ #ifndef __GSD_UPDATES_REFRESH_H #define __GSD_UPDATES_REFRESH_H #include G_BEGIN_DECLS #define GSD_TYPE_UPDATES_REFRESH (gsd_updates_refresh_get_type ()) #define GSD_UPDATES_REFRESH(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_UPDATES_REFRESH, GsdUpdatesRefresh)) #define GSD_UPDATES_REFRESH_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_UPDATES_REFRESH, GsdUpdatesRefreshClass)) #define GSD_IS_UPDATES_REFRESH(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_UPDATES_REFRESH)) typedef struct GsdUpdatesRefreshPrivate GsdUpdatesRefreshPrivate; typedef struct { GObject parent; GsdUpdatesRefreshPrivate *priv; } GsdUpdatesRefresh; typedef struct { GObjectClass parent_class; } GsdUpdatesRefreshClass; GType gsd_updates_refresh_get_type (void); GsdUpdatesRefresh *gsd_updates_refresh_new (void); G_END_DECLS #endif /* __GSD_UPDATES_REFRESH_H */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/updates/gsd-updates-common.h0000644000015300001610000000421512567031542027501 0ustar pbuserpbgroup00000000000000/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 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 __GSD_UPDATES_COMMON_H #define __GSD_UPDATES_COMMON_H G_BEGIN_DECLS #define GSD_SETTINGS_BANNED_FIRMWARE "banned-firmware" #define GSD_SETTINGS_CONNECTION_USE_MOBILE "connection-use-mobile" #define GSD_SETTINGS_ENABLE_CHECK_FIRMWARE "enable-check-firmware" #define GSD_SETTINGS_FREQUENCY_GET_UPDATES "frequency-get-updates" #define GSD_SETTINGS_FREQUENCY_GET_UPGRADES "frequency-get-upgrades" #define GSD_SETTINGS_FREQUENCY_REFRESH_CACHE "frequency-refresh-cache" #define GSD_SETTINGS_FREQUENCY_UPDATES_NOTIFICATION "frequency-updates-notification" #define GSD_SETTINGS_IGNORED_DEVICES "ignored-devices" #define GSD_SETTINGS_LAST_UPDATES_NOTIFICATION "last-updates-notification" #define GSD_SETTINGS_MEDIA_REPO_FILENAMES "media-repo-filenames" #define GSD_SETTINGS_NOTIFY_DISTRO_UPGRADES "notify-distro-upgrades" #define GSD_SETTINGS_SCHEMA "org.gnome.settings-daemon.plugins.updates" #define GSD_SETTINGS_UPDATE_BATTERY "update-battery" #define GSD_SETTINGS_AUTO_DOWNLOAD_UPDATES "auto-download-updates" G_END_DECLS #endif /* __GSD_UPDATES_COMMON_H */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/Makefile.am0000644000015300001610000000154012567031542024207 0ustar pbuserpbgroup00000000000000NULL = enabled_plugins = \ a11y-keyboard \ a11y-settings \ automount \ background \ clipboard \ color \ cursor \ dummy \ power \ housekeeping \ keyboard \ media-keys \ mouse \ remote-display \ screensaver-proxy \ sound \ xrandr \ xsettings \ $(NULL) disabled_plugins = $(NULL) if HAVE_PACKAGEKIT enabled_plugins += updates else disabled_plugins += updates endif if SMARTCARD_SUPPORT enabled_plugins += smartcard else disabled_plugins += smartcard endif if HAVE_GUDEV enabled_plugins += orientation else disabled_plugins += orientation endif if HAVE_WACOM enabled_plugins += wacom else disabled_plugins += wacom endif if BUILD_PRINT_NOTIFICATIONS enabled_plugins += print-notifications else disabled_plugins += print-notifications endif SUBDIRS = common $(enabled_plugins) DIST_SUBDIRS = $(SUBDIRS) $(disabled_plugins) unity-settings-daemon-14.04.0+14.04.20150825/plugins/a11y-settings/0000755000015300001610000000000012567032025024561 5ustar pbuserpbgroup00000000000000unity-settings-daemon-14.04.0+14.04.20150825/plugins/a11y-settings/Makefile.am0000644000015300001610000000260512567031542026623 0ustar pbuserpbgroup00000000000000plugin_name = a11y-settings libexec_PROGRAMS = usd-test-a11y-settings usd_test_a11y_settings_SOURCES = \ gsd-a11y-settings-manager.h \ gsd-a11y-settings-manager.c \ test-a11y-settings.c usd_test_a11y_settings_CFLAGS = \ -I$(top_srcdir)/gnome-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) usd_test_a11y_settings_LDADD = \ $(top_builddir)/gnome-settings-daemon/libgsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_PLUGIN_LIBS) plugin_LTLIBRARIES = \ liba11y-settings.la liba11y_settings_la_SOURCES = \ gsd-a11y-settings-manager.c \ gsd-a11y-settings-manager.h \ gsd-a11y-settings-plugin.c liba11y_settings_la_CPPFLAGS = \ -I$(top_srcdir)/gnome-settings-daemon \ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) liba11y_settings_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) liba11y_settings_la_LDFLAGS = \ $(GSD_PLUGIN_LDFLAGS) liba11y_settings_la_LIBADD = \ $(SETTINGS_PLUGIN_LIBS) plugin_in_files = \ a11y-settings.gnome-settings-plugin.in plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.in=.gnome-settings-plugin) EXTRA_DIST = \ $(plugin_in_files) CLEANFILES = \ $(plugin_DATA) DISTCLEANFILES = \ $(plugin_DATA) @GSD_INTLTOOL_PLUGIN_RULE@ unity-settings-daemon-14.04.0+14.04.20150825/plugins/a11y-settings/test-a11y-settings.c0000644000015300001610000000035412567031542030320 0ustar pbuserpbgroup00000000000000#define NEW gsd_a11y_settings_manager_new #define START gsd_a11y_settings_manager_start #define STOP gsd_a11y_settings_manager_stop #define MANAGER GsdA11ySettingsManager #include "gsd-a11y-settings-manager.h" #include "test-plugin.h" unity-settings-daemon-14.04.0+14.04.20150825/plugins/a11y-settings/gsd-a11y-settings-manager.c0000644000015300001610000001541212567031542031527 0ustar pbuserpbgroup00000000000000/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "gnome-settings-profile.h" #include "gsd-a11y-settings-manager.h" #define GSD_A11Y_SETTINGS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_A11Y_SETTINGS_MANAGER, GsdA11ySettingsManagerPrivate)) struct GsdA11ySettingsManagerPrivate { GSettings *interface_settings; GSettings *a11y_apps_settings; }; enum { PROP_0, }; static void gsd_a11y_settings_manager_class_init (GsdA11ySettingsManagerClass *klass); static void gsd_a11y_settings_manager_init (GsdA11ySettingsManager *a11y_settings_manager); static void gsd_a11y_settings_manager_finalize (GObject *object); G_DEFINE_TYPE (GsdA11ySettingsManager, gsd_a11y_settings_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static void apps_settings_changed (GSettings *settings, const char *key, GsdA11ySettingsManager *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 gsd_a11y_settings_manager_start (GsdA11ySettingsManager *manager, GError **error) { g_debug ("Starting a11y_settings manager"); gnome_settings_profile_start (NULL); manager->priv->interface_settings = g_settings_new ("org.gnome.desktop.interface"); manager->priv->a11y_apps_settings = g_settings_new ("org.gnome.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); gnome_settings_profile_end (NULL); return TRUE; } void gsd_a11y_settings_manager_stop (GsdA11ySettingsManager *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 * gsd_a11y_settings_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GsdA11ySettingsManager *a11y_settings_manager; a11y_settings_manager = GSD_A11Y_SETTINGS_MANAGER (G_OBJECT_CLASS (gsd_a11y_settings_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (a11y_settings_manager); } static void gsd_a11y_settings_manager_dispose (GObject *object) { G_OBJECT_CLASS (gsd_a11y_settings_manager_parent_class)->dispose (object); } static void gsd_a11y_settings_manager_class_init (GsdA11ySettingsManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = gsd_a11y_settings_manager_constructor; object_class->dispose = gsd_a11y_settings_manager_dispose; object_class->finalize = gsd_a11y_settings_manager_finalize; g_type_class_add_private (klass, sizeof (GsdA11ySettingsManagerPrivate)); } static void gsd_a11y_settings_manager_init (GsdA11ySettingsManager *manager) { manager->priv = GSD_A11Y_SETTINGS_MANAGER_GET_PRIVATE (manager); } static void gsd_a11y_settings_manager_finalize (GObject *object) { GsdA11ySettingsManager *a11y_settings_manager; g_return_if_fail (object != NULL); g_return_if_fail (GSD_IS_A11Y_SETTINGS_MANAGER (object)); a11y_settings_manager = GSD_A11Y_SETTINGS_MANAGER (object); g_return_if_fail (a11y_settings_manager->priv != NULL); G_OBJECT_CLASS (gsd_a11y_settings_manager_parent_class)->finalize (object); } GsdA11ySettingsManager * gsd_a11y_settings_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (GSD_TYPE_A11Y_SETTINGS_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return GSD_A11Y_SETTINGS_MANAGER (manager_object); } unity-settings-daemon-14.04.0+14.04.20150825/plugins/a11y-settings/gsd-a11y-settings-manager.h0000644000015300001610000000474112567031542031537 0ustar pbuserpbgroup00000000000000/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __GSD_A11Y_SETTINGS_MANAGER_H #define __GSD_A11Y_SETTINGS_MANAGER_H #include G_BEGIN_DECLS #define GSD_TYPE_A11Y_SETTINGS_MANAGER (gsd_a11y_settings_manager_get_type ()) #define GSD_A11Y_SETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_A11Y_SETTINGS_MANAGER, GsdA11ySettingsManager)) #define GSD_A11Y_SETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_A11Y_SETTINGS_MANAGER, GsdA11ySettingsManagerClass)) #define GSD_IS_A11Y_SETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_A11Y_SETTINGS_MANAGER)) #define GSD_IS_A11Y_SETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_A11Y_SETTINGS_MANAGER)) #define GSD_A11Y_SETTINGS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_A11Y_SETTINGS_MANAGER, GsdA11ySettingsManagerClass)) typedef struct GsdA11ySettingsManagerPrivate GsdA11ySettingsManagerPrivate; typedef struct { GObject parent; GsdA11ySettingsManagerPrivate *priv; } GsdA11ySettingsManager; typedef struct { GObjectClass parent_class; } GsdA11ySettingsManagerClass; GType gsd_a11y_settings_manager_get_type (void); GsdA11ySettingsManager *gsd_a11y_settings_manager_new (void); gboolean gsd_a11y_settings_manager_start (GsdA11ySettingsManager *manager, GError **error); void gsd_a11y_settings_manager_stop (GsdA11ySettingsManager *manager); G_END_DECLS #endif /* __GSD_A11Y_SETTINGS_MANAGER_H */ ././@LongLink0000000000000000000000000000015200000000000011213 Lustar 00000000000000unity-settings-daemon-14.04.0+14.04.20150825/plugins/a11y-settings/a11y-settings.gnome-settings-plugin.inunity-settings-daemon-14.04.0+14.04.20150825/plugins/a11y-settings/a11y-settings.gnome-settings-plug0000644000015300001610000000034412567031542033030 0ustar pbuserpbgroup00000000000000[GNOME Settings Plugin] Module=a11y-settings IAge=0 Priority=7 _Name=Accessibility settings _Description=Accessibility settings plugin Authors=Bastien Nocera Copyright=Copyright © 2011 Red Hat Inc. Website= unity-settings-daemon-14.04.0+14.04.20150825/plugins/a11y-settings/gsd-a11y-settings-plugin.c0000644000015300001610000000204412567031542031410 0ustar pbuserpbgroup00000000000000/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include #include #include "gnome-settings-plugin.h" #include "gsd-a11y-settings-manager.h" GNOME_SETTINGS_PLUGIN_REGISTER (GsdA11ySettings, gsd_a11y_settings) unity-settings-daemon-14.04.0+14.04.20150825/plugins/remote-display/0000755000015300001610000000000012567032025025106 5ustar pbuserpbgroup00000000000000unity-settings-daemon-14.04.0+14.04.20150825/plugins/remote-display/Makefile.am0000644000015300001610000000301512567031542027144 0ustar pbuserpbgroup00000000000000plugin_name = remote-display plugin_LTLIBRARIES = libremote-display.la libremote_display_la_SOURCES = \ gsd-remote-display-manager.c \ gsd-remote-display-manager.h \ gsd-remote-display-plugin.c libremote_display_la_CPPFLAGS = \ -I$(top_srcdir)/gnome-settings-daemon \ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) libremote_display_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) libremote_display_la_LDFLAGS = $(GSD_PLUGIN_LDFLAGS) libremote_display_la_LIBADD = $(SETTINGS_PLUGIN_LIBS) libexec_PROGRAMS = usd-test-remote-display usd_test_remote_display_SOURCES = \ test-remote-display.c \ gsd-remote-display-manager.c \ gsd-remote-display-manager.h usd_test_remote_display_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/gnome-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) usd_test_remote_display_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) usd_test_remote_display_LDADD = \ $(top_builddir)/gnome-settings-daemon/libgsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) plugin_in_files = remote-display.gnome-settings-plugin.in plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.in=.gnome-settings-plugin) EXTRA_DIST = $(plugin_in_files) CLEANFILES = $(plugin_DATA) DISTCLEANFILES = $(plugin_DATA) @GSD_INTLTOOL_PLUGIN_RULE@ ././@LongLink0000000000000000000000000000015400000000000011215 Lustar 00000000000000unity-settings-daemon-14.04.0+14.04.20150825/plugins/remote-display/remote-display.gnome-settings-plugin.inunity-settings-daemon-14.04.0+14.04.20150825/plugins/remote-display/remote-display.gnome-settings-pl0000644000015300001610000000032312567031542033343 0ustar pbuserpbgroup00000000000000[GNOME Settings Plugin] Module=remote-display IAge=0 Priority=8 _Name=Remote Display _Description=Disable animations on remote displays Authors=Bastien Nocera Copyright=Copyright © 2012 Bastien Nocera Website= unity-settings-daemon-14.04.0+14.04.20150825/plugins/remote-display/test-remote-display.c0000644000015300001610000000036112567031542031170 0ustar pbuserpbgroup00000000000000#define NEW gsd_remote_display_manager_new #define START gsd_remote_display_manager_start #define STOP gsd_remote_display_manager_stop #define MANAGER GsdRemoteDisplayManager #include "gsd-remote-display-manager.h" #include "test-plugin.h" unity-settings-daemon-14.04.0+14.04.20150825/plugins/remote-display/gsd-remote-display-plugin.c0000644000015300001610000000217312567031542032265 0ustar pbuserpbgroup00000000000000/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include #include #include "gnome-settings-plugin.h" #include "gsd-remote-display-manager.h" struct GsdRemoteDisplayPluginPrivate { GsdRemoteDisplayManager *manager; }; GNOME_SETTINGS_PLUGIN_REGISTER (GsdRemoteDisplay, gsd_remote_display) unity-settings-daemon-14.04.0+14.04.20150825/plugins/remote-display/gsd-remote-display-manager.c0000644000015300001610000001642512567031542032406 0ustar pbuserpbgroup00000000000000/* -*- 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., 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 "gnome-settings-session.h" #include "gnome-settings-profile.h" #include "gsd-remote-display-manager.h" #define GSD_REMOTE_DISPLAY_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_REMOTE_DISPLAY_MANAGER, GsdRemoteDisplayManagerPrivate)) struct GsdRemoteDisplayManagerPrivate { GSettings *desktop_settings; GDBusProxy *vino_proxy; GCancellable *cancellable; guint vino_watch_id; gboolean vnc_in_use; }; static void gsd_remote_display_manager_class_init (GsdRemoteDisplayManagerClass *klass); static void gsd_remote_display_manager_init (GsdRemoteDisplayManager *remote_display_manager); G_DEFINE_TYPE (GsdRemoteDisplayManager, gsd_remote_display_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static void update_settings_from_variant (GsdRemoteDisplayManager *manager, GVariant *variant) { manager->priv->vnc_in_use = g_variant_get_boolean (variant); g_debug ("%s because of remote display status (vnc: %d)", !manager->priv->vnc_in_use ? "Enabling" : "Disabling", manager->priv->vnc_in_use); g_settings_set_boolean (manager->priv->desktop_settings, "enable-animations", !manager->priv->vnc_in_use); } static void props_changed (GDBusProxy *proxy, GVariant *changed_properties, GStrv invalidated_properties, GsdRemoteDisplayManager *manager) { GVariant *v; v = g_variant_lookup_value (changed_properties, "Connected", G_VARIANT_TYPE_BOOLEAN); if (v) { g_debug ("Received connected change"); update_settings_from_variant (manager, v); g_variant_unref (v); } } static void got_vino_proxy (GObject *source_object, GAsyncResult *res, GsdRemoteDisplayManager *manager) { GError *error = NULL; GVariant *v; manager->priv->vino_proxy = g_dbus_proxy_new_finish (res, &error); if (manager->priv->vino_proxy == NULL) { g_warning ("Failed to get Vino's D-Bus proxy: %s", error->message); g_error_free (error); return; } g_signal_connect (manager->priv->vino_proxy, "g-properties-changed", G_CALLBACK (props_changed), manager); v = g_dbus_proxy_get_cached_property (manager->priv->vino_proxy, "Connected"); if (v) { g_debug ("Setting original state"); update_settings_from_variant (manager, v); g_variant_unref (v); } } static void vino_appeared_cb (GDBusConnection *connection, const gchar *name, const gchar *name_owner, GsdRemoteDisplayManager *manager) { g_debug ("Vino appeared"); g_dbus_proxy_new (connection, G_DBUS_PROXY_FLAGS_NONE, NULL, name, "/org/gnome/vino/screens/0", "org.gnome.VinoScreen", manager->priv->cancellable, (GAsyncReadyCallback) got_vino_proxy, manager); } static void vino_vanished_cb (GDBusConnection *connection, const char *name, GsdRemoteDisplayManager *manager) { g_debug ("Vino vanished"); if (manager->priv->cancellable != NULL) { g_cancellable_cancel (manager->priv->cancellable); g_clear_object (&manager->priv->cancellable); } g_clear_object (&manager->priv->vino_proxy); /* And reset for us to have animations */ g_settings_set_boolean (manager->priv->desktop_settings, "enable-animations", TRUE); } static gboolean gsd_display_has_extension (const gchar *ext) { int op, event, error; return XQueryExtension (gdk_x11_get_default_xdisplay (), ext, &op, &event, &error); } gboolean gsd_remote_display_manager_start (GsdRemoteDisplayManager *manager, GError **error) { g_debug ("Starting remote-display manager"); gnome_settings_profile_start (NULL); manager->priv->desktop_settings = g_settings_new ("org.gnome.desktop.interface"); /* Check if spice is used: * https://bugzilla.gnome.org/show_bug.cgi?id=680195#c7 * This doesn't change at run-time, so it's to the point */ if (g_file_test ("/dev/virtio-ports/com.redhat.spice.0", G_FILE_TEST_EXISTS)) { g_debug ("Disabling animations because SPICE is in use"); g_settings_set_boolean (manager->priv->desktop_settings, "enable-animations", FALSE); goto out; } /* Xvnc exposes an extension named VNC-EXTENSION */ if (gsd_display_has_extension ("VNC-EXTENSION")) { g_debug ("Disabling animations because VNC-EXTENSION was detected"); g_settings_set_boolean (manager->priv->desktop_settings, "enable-animations", FALSE); goto out; } /* Monitor Vino's usage */ manager->priv->vino_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, "org.gnome.Vino", G_BUS_NAME_WATCHER_FLAGS_NONE, (GBusNameAppearedCallback) vino_appeared_cb, (GBusNameVanishedCallback) vino_vanished_cb, manager, NULL); out: gnome_settings_profile_end (NULL); return TRUE; } void gsd_remote_display_manager_stop (GsdRemoteDisplayManager *manager) { g_debug ("Stopping remote_display manager"); if (manager->priv->cancellable != NULL) { g_cancellable_cancel (manager->priv->cancellable); g_clear_object (&manager->priv->cancellable); } g_clear_object (&manager->priv->vino_proxy); if (manager->priv->desktop_settings) { g_settings_reset (manager->priv->desktop_settings, "enable-animations"); g_clear_object (&manager->priv->desktop_settings); } } static void gsd_remote_display_manager_class_init (GsdRemoteDisplayManagerClass *klass) { g_type_class_add_private (klass, sizeof (GsdRemoteDisplayManagerPrivate)); } static void gsd_remote_display_manager_init (GsdRemoteDisplayManager *manager) { manager->priv = GSD_REMOTE_DISPLAY_MANAGER_GET_PRIVATE (manager); } GsdRemoteDisplayManager * gsd_remote_display_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (GSD_TYPE_REMOTE_DISPLAY_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return GSD_REMOTE_DISPLAY_MANAGER (manager_object); } unity-settings-daemon-14.04.0+14.04.20150825/plugins/remote-display/gsd-remote-display-manager.h0000644000015300001610000000503512567031542032406 0ustar pbuserpbgroup00000000000000/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __GSD_REMOTE_DISPLAY_MANAGER_H #define __GSD_REMOTE_DISPLAY_MANAGER_H #include G_BEGIN_DECLS #define GSD_TYPE_REMOTE_DISPLAY_MANAGER (gsd_remote_display_manager_get_type ()) #define GSD_REMOTE_DISPLAY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_REMOTE_DISPLAY_MANAGER, GsdRemoteDisplayManager)) #define GSD_REMOTE_DISPLAY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_REMOTE_DISPLAY_MANAGER, GsdRemoteDisplayManagerClass)) #define GSD_IS_REMOTE_DISPLAY_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_REMOTE_DISPLAY_MANAGER)) #define GSD_IS_REMOTE_DISPLAY_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_REMOTE_DISPLAY_MANAGER)) #define GSD_REMOTE_DISPLAY_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_REMOTE_DISPLAY_MANAGER, GsdRemoteDisplayManagerClass)) typedef struct GsdRemoteDisplayManagerPrivate GsdRemoteDisplayManagerPrivate; typedef struct { GObject parent; GsdRemoteDisplayManagerPrivate *priv; } GsdRemoteDisplayManager; typedef struct { GObjectClass parent_class; } GsdRemoteDisplayManagerClass; GType gsd_remote_display_manager_get_type (void); GsdRemoteDisplayManager *gsd_remote_display_manager_new (void); gboolean gsd_remote_display_manager_start (GsdRemoteDisplayManager *manager, GError **error); void gsd_remote_display_manager_stop (GsdRemoteDisplayManager *manager); G_END_DECLS #endif /* __GSD_REMOTE_DISPLAY_MANAGER_H */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/0000755000015300001610000000000012567032025024200 5ustar pbuserpbgroup00000000000000unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/Makefile.am0000644000015300001610000000464412567031542026247 0ustar pbuserpbgroup00000000000000NULL = plugin_name = xsettings noinst_PROGRAMS = test-gtk-modules test_gtk_modules_SOURCES = \ gsd-xsettings-gtk.c \ gsd-xsettings-gtk.h \ test-gtk-modules.c test_gtk_modules_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(AM_CFLAGS) test_gtk_modules_LDADD = \ $(top_builddir)/gnome-settings-daemon/libgsd.la \ $(XSETTINGS_LIBS) \ $(SETTINGS_PLUGIN_LIBS) test_gtk_modules_CPPFLAGS = \ -I$(top_srcdir)/gnome-settings-daemon \ -I$(top_srcdir)/data/ \ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DGTK_MODULES_DIRECTORY=\""$(libdir)/unity-settings-daemon-@GSD_API_VERSION@/gtk-modules/"\" \ $(AM_CPPFLAGS) libexec_PROGRAMS = usd-test-xsettings usd_test_xsettings_SOURCES = \ gsd-xsettings-gtk.c \ gsd-xsettings-gtk.h \ gsd-xsettings-manager.c \ gsd-xsettings-gtk.h \ xsettings-common.c \ xsettings-common.h \ xsettings-manager.c \ xsettings-manager.h \ fontconfig-monitor.c \ fontconfig-monitor.h \ test-xsettings.c usd_test_xsettings_CFLAGS = $(test_gtk_modules_CFLAGS) usd_test_xsettings_CPPFLAGS = $(test_gtk_modules_CPPFLAGS) -I$(top_srcdir)/plugins/common usd_test_xsettings_LDADD = $(test_gtk_modules_LDADD) plugin_LTLIBRARIES = \ libxsettings.la \ $(NULL) libxsettings_la_SOURCES = \ gsd-xsettings-plugin.c \ gsd-xsettings-manager.h \ gsd-xsettings-manager.c \ gsd-xsettings-gtk.c \ gsd-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)/gnome-settings-daemon \ -I$(top_srcdir)/data/ \ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DGTK_MODULES_DIRECTORY=\""$(libdir)/unity-settings-daemon-@GSD_API_VERSION@/gtk-modules/"\" \ $(AM_CPPFLAGS) libxsettings_la_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(XSETTINGS_CFLAGS) \ $(AM_CFLAGS) libxsettings_la_LDFLAGS = \ $(GSD_PLUGIN_LDFLAGS) \ $(NULL) libxsettings_la_LIBADD = \ $(top_builddir)/gnome-settings-daemon/libgsd.la \ $(SETTINGS_PLUGIN_LIBS) \ $(XSETTINGS_LIBS) \ $(NULL) plugin_in_files = \ xsettings.gnome-settings-plugin.in \ $(NULL) plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.in=.gnome-settings-plugin) EXTRA_DIST = \ README.xsettings \ $(plugin_in_files) \ $(NULL) CLEANFILES = \ $(plugin_DATA) \ $(NULL) DISTCLEANFILES = \ $(plugin_DATA) \ $(NULL) @GSD_INTLTOOL_PLUGIN_RULE@ unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/xsettings.gnome-settings-plugin.in0000644000015300001610000000027612567031542033026 0ustar pbuserpbgroup00000000000000[GNOME Settings Plugin] Module=xsettings IAge=0 Priority=2 _Name=X Settings _Description=Manage X Settings Authors=William Jon McCann Copyright=Copyright © 2007 William Jon McCann Website= unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/test-gtk-modules.c0000644000015300001610000000124112567031542027555 0ustar pbuserpbgroup00000000000000 #include "gsd-xsettings-gtk.h" static void gtk_modules_callback (GsdXSettingsGtk *gtk, GParamSpec *spec, gpointer user_data) { const char *modules; modules = gsd_xsettings_gtk_get_modules (gtk); g_message ("GTK+ modules list changed to: %s", modules ? modules : "(empty)"); } int main (int argc, char **argv) { GMainLoop *loop; GsdXSettingsGtk *gtk; gtk = gsd_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); return 0; } unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/test-xsettings.c0000644000015300001610000000034112567031542027352 0ustar pbuserpbgroup00000000000000#define NEW gnome_xsettings_manager_new #define START gnome_xsettings_manager_start #define STOP gnome_xsettings_manager_stop #define MANAGER GnomeXSettingsManager #include "gsd-xsettings-manager.h" #include "test-plugin.h" unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/gsd-xsettings-manager.h0000644000015300001610000000466212567031542030577 0ustar pbuserpbgroup00000000000000/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __GNOME_XSETTINGS_MANAGER_H #define __GNOME_XSETTINGS_MANAGER_H #include G_BEGIN_DECLS #define GNOME_TYPE_XSETTINGS_MANAGER (gnome_xsettings_manager_get_type ()) #define GNOME_XSETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GNOME_TYPE_XSETTINGS_MANAGER, GnomeXSettingsManager)) #define GNOME_XSETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GNOME_TYPE_XSETTINGS_MANAGER, GnomeXSettingsManagerClass)) #define GNOME_IS_XSETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GNOME_TYPE_XSETTINGS_MANAGER)) #define GNOME_IS_XSETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GNOME_TYPE_XSETTINGS_MANAGER)) #define GNOME_XSETTINGS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GNOME_TYPE_XSETTINGS_MANAGER, GnomeXSettingsManagerClass)) typedef struct GnomeXSettingsManagerPrivate GnomeXSettingsManagerPrivate; typedef struct { GObject parent; GnomeXSettingsManagerPrivate *priv; } GnomeXSettingsManager; typedef struct { GObjectClass parent_class; } GnomeXSettingsManagerClass; GType gnome_xsettings_manager_get_type (void); GnomeXSettingsManager * gnome_xsettings_manager_new (void); gboolean gnome_xsettings_manager_start (GnomeXSettingsManager *manager, GError **error); void gnome_xsettings_manager_stop (GnomeXSettingsManager *manager); G_END_DECLS #endif /* __GNOME_XSETTINGS_MANAGER_H */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/gsd-xsettings-gtk.c0000644000015300001610000003015212567031542027736 0ustar pbuserpbgroup00000000000000/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include #include #include "gsd-xsettings-gtk.h" #define XSETTINGS_PLUGIN_SCHEMA "org.gnome.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 GsdXSettingsGtkPrivate { char *modules; GHashTable *dir_modules; GSettings *settings; guint64 dir_mtime; GFileMonitor *monitor; GList *cond_settings; }; #define GSD_XSETTINGS_GTK_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GSD_TYPE_XSETTINGS_GTK, GsdXSettingsGtkPrivate)) G_DEFINE_TYPE(GsdXSettingsGtk, gsd_xsettings_gtk, G_TYPE_OBJECT) static void update_gtk_modules (GsdXSettingsGtk *gtk); static void empty_cond_settings_list (GsdXSettingsGtk *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, GsdXSettingsGtk *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, GsdXSettingsGtk *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 (GsdXSettingsGtk *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 (GsdXSettingsGtk *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, GsdXSettingsGtk *gtk) { get_gtk_modules_from_dir (gtk); update_gtk_modules (gtk); } static void gsd_xsettings_gtk_init (GsdXSettingsGtk *gtk) { GFile *file; gtk->priv = GSD_XSETTINGS_GTK_GET_PRIVATE (gtk); g_debug ("GsdXSettingsGtk 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 gsd_xsettings_gtk_finalize (GObject *object) { GsdXSettingsGtk *gtk; g_return_if_fail (object != NULL); g_return_if_fail (GSD_IS_XSETTINGS_GTK (object)); g_debug ("GsdXSettingsGtk finalizing"); gtk = GSD_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 (gsd_xsettings_gtk_parent_class)->finalize (object); } static void gsd_xsettings_gtk_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GsdXSettingsGtk *self; self = GSD_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 gsd_xsettings_gtk_class_init (GsdXSettingsGtkClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = gsd_xsettings_gtk_get_property; object_class->finalize = gsd_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 (GsdXSettingsGtkPrivate)); } GsdXSettingsGtk * gsd_xsettings_gtk_new (void) { return GSD_XSETTINGS_GTK (g_object_new (GSD_TYPE_XSETTINGS_GTK, NULL)); } const char * gsd_xsettings_gtk_get_modules (GsdXSettingsGtk *gtk) { return gtk->priv->modules; } unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/gsd-xsettings-manager.c0000644000015300001610000012670612567031542030576 0ustar pbuserpbgroup00000000000000/* -*- 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., 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 "gnome-settings-profile.h" #include "gsd-enums.h" #include "gsd-xsettings-manager.h" #include "gsd-xsettings-gtk.h" #include "xsettings-manager.h" #include "fontconfig-monitor.h" #define GNOME_XSETTINGS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNOME_TYPE_XSETTINGS_MANAGER, GnomeXSettingsManagerPrivate)) #define MOUSE_SETTINGS_SCHEMA "org.gnome.settings-daemon.peripherals.mouse" #define INTERFACE_SETTINGS_SCHEMA "org.gnome.desktop.interface" #define SOUND_SETTINGS_SCHEMA "org.gnome.desktop.sound" #define PRIVACY_SETTINGS_SCHEMA "org.gnome.desktop.privacy" #define XSETTINGS_PLUGIN_SCHEMA "org.gnome.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 #define HIDPI_LIMIT (DPI_FALLBACK * 2) typedef struct _TranslationEntry TranslationEntry; typedef void (* TranslationFunc) (GnomeXSettingsManager *manager, TranslationEntry *trans, GVariant *value); struct _TranslationEntry { const char *gsettings_schema; const char *gsettings_key; const char *xsetting_name; TranslationFunc translate; }; struct GnomeXSettingsManagerPrivate { guint start_idle_id; XSettingsManager **managers; GHashTable *settings; GSettings *plugin_settings; fontconfig_monitor_handle_t *fontconfig_handle; GsdXSettingsGtk *gtk; guint shell_name_watch_id; guint unity_name_watch_id; gboolean have_shell; gboolean have_unity; guint notify_idle_id; }; #define GSD_XSETTINGS_ERROR gsd_xsettings_error_quark () enum { GSD_XSETTINGS_ERROR_INIT }; static void gnome_xsettings_manager_class_init (GnomeXSettingsManagerClass *klass); static void gnome_xsettings_manager_init (GnomeXSettingsManager *xsettings_manager); static void gnome_xsettings_manager_finalize (GObject *object); G_DEFINE_TYPE (GnomeXSettingsManager, gnome_xsettings_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static GQuark gsd_xsettings_error_quark (void) { return g_quark_from_static_string ("gsd-xsettings-error-quark"); } static void translate_bool_int (GnomeXSettingsManager *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 (GnomeXSettingsManager *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 (GnomeXSettingsManager *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 (GnomeXSettingsManager *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.gnome.settings-daemon.peripherals.mouse", "double-click", "Net/DoubleClickTime", translate_int_int }, { "org.gnome.settings-daemon.peripherals.mouse", "drag-threshold", "Net/DndDragThreshold", translate_int_int }, { "org.gnome.desktop.interface", "gtk-color-palette", "Gtk/ColorPalette", translate_string_string }, { "org.gnome.desktop.interface", "font-name", "Gtk/FontName", translate_string_string }, { "org.gnome.desktop.interface", "gtk-key-theme", "Gtk/KeyThemeName", translate_string_string }, { "org.gnome.desktop.interface", "toolbar-style", "Gtk/ToolbarStyle", translate_string_string_toolbar }, { "org.gnome.desktop.interface", "toolbar-icons-size", "Gtk/ToolbarIconSize", translate_string_string }, { "org.gnome.desktop.interface", "can-change-accels", "Gtk/CanChangeAccels", translate_bool_int }, { "org.gnome.desktop.interface", "cursor-blink", "Net/CursorBlink", translate_bool_int }, { "org.gnome.desktop.interface", "cursor-blink-time", "Net/CursorBlinkTime", translate_int_int }, { "org.gnome.desktop.interface", "cursor-blink-timeout", "Gtk/CursorBlinkTimeout", translate_int_int }, { "org.gnome.desktop.interface", "gtk-theme", "Net/ThemeName", translate_string_string }, { "org.gnome.desktop.interface", "gtk-timeout-initial", "Gtk/TimeoutInitial", translate_int_int }, { "org.gnome.desktop.interface", "gtk-timeout-repeat", "Gtk/TimeoutRepeat", translate_int_int }, { "org.gnome.desktop.interface", "gtk-color-scheme", "Gtk/ColorScheme", translate_string_string }, { "org.gnome.desktop.interface", "gtk-im-preedit-style", "Gtk/IMPreeditStyle", translate_string_string }, { "org.gnome.desktop.interface", "gtk-im-status-style", "Gtk/IMStatusStyle", translate_string_string }, { "org.gnome.desktop.interface", "gtk-im-module", "Gtk/IMModule", translate_string_string }, { "org.gnome.desktop.interface", "icon-theme", "Net/IconThemeName", translate_string_string }, { "org.gnome.desktop.interface", "menus-have-icons", "Gtk/MenuImages", translate_bool_int }, { "org.gnome.desktop.interface", "buttons-have-icons", "Gtk/ButtonImages", translate_bool_int }, { "org.gnome.desktop.interface", "menubar-accel", "Gtk/MenuBarAccel", translate_string_string }, { "org.gnome.desktop.interface", "enable-animations", "Gtk/EnableAnimations", translate_bool_int }, { "org.gnome.desktop.interface", "cursor-theme", "Gtk/CursorThemeName", translate_string_string }, /* cursor-size is handled via the Xft side as it needs the scaling factor */ { "org.gnome.desktop.interface", "show-input-method-menu", "Gtk/ShowInputMethodMenu", translate_bool_int }, { "org.gnome.desktop.interface", "show-unicode-menu", "Gtk/ShowUnicodeMenu", translate_bool_int }, { "org.gnome.desktop.interface", "automatic-mnemonics", "Gtk/AutoMnemonics", translate_bool_int }, { "org.gnome.desktop.sound", "theme-name", "Net/SoundThemeName", translate_string_string }, { "org.gnome.desktop.sound", "event-sounds", "Net/EnableEventSounds" , translate_bool_int }, { "org.gnome.desktop.sound", "input-feedback-sounds", "Net/EnableInputFeedbackSounds", translate_bool_int }, { "org.gnome.desktop.privacy", "recent-files-max-age", "Gtk/RecentFilesMaxAge", translate_int_int }, { "org.gnome.desktop.privacy", "remember-recent-files", "Gtk/RecentFilesEnabled", translate_bool_int } }; static gboolean notify_idle (gpointer data) { GnomeXSettingsManager *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 (GnomeXSettingsManager *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 (GnomeXSettingsManager *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 (GnomeXSettingsManager *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) { window_scale = 1; } 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; } GnomeXftSettings; /* Read GSettings and determine the appropriate Xft settings based on them. */ static void xft_settings_get (GnomeXSettingsManager *manager, GnomeXftSettings *settings) { GSettings *interface_settings; GsdFontAntialiasingMode antialiasing; GsdFontHinting hinting; GsdFontRgbaOrder 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 != GSD_FONT_ANTIALIASING_MODE_NONE); settings->hinting = (hinting != GSD_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 GSD_FONT_HINTING_NONE: settings->hintstyle = "hintnone"; break; case GSD_FONT_HINTING_SLIGHT: settings->hintstyle = "hintslight"; break; case GSD_FONT_HINTING_MEDIUM: settings->hintstyle = "hintmedium"; break; case GSD_FONT_HINTING_FULL: settings->hintstyle = "hintfull"; break; } switch (order) { case GSD_FONT_RGBA_ORDER_RGBA: settings->rgba = "rgba"; break; case GSD_FONT_RGBA_ORDER_RGB: settings->rgba = "rgb"; break; case GSD_FONT_RGBA_ORDER_BGR: settings->rgba = "bgr"; break; case GSD_FONT_RGBA_ORDER_VRGB: settings->rgba = "vrgb"; break; case GSD_FONT_RGBA_ORDER_VBGR: settings->rgba = "vbgr"; break; } switch (antialiasing) { case GSD_FONT_ANTIALIASING_MODE_NONE: settings->antialias = 0; break; case GSD_FONT_ANTIALIASING_MODE_GRAYSCALE: settings->antialias = 1; break; case GSD_FONT_ANTIALIASING_MODE_RGBA: settings->antialias = 1; use_rgba = TRUE; } if (!use_rgba) { settings->rgba = "none"; } } static void xft_settings_set_xsettings (GnomeXSettingsManager *manager, GnomeXftSettings *settings) { int i; gnome_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); } gnome_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 (GnomeXftSettings *settings) { GString *add_string; char dpibuf[G_ASCII_DTOSTR_BUF_SIZE]; Display *dpy; gnome_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); gnome_settings_profile_end (NULL); } /* We mirror the Xft properties both through XSETTINGS and through * X resources */ static void update_xft_settings (GnomeXSettingsManager *manager) { GnomeXftSettings settings; gnome_settings_profile_start (NULL); xft_settings_get (manager, &settings); xft_settings_set_xsettings (manager, &settings); xft_settings_set_xresources (&settings); gnome_settings_profile_end (NULL); } static void xft_callback (GSettings *settings, const gchar *key, GnomeXSettingsManager *manager) { update_xft_settings (manager); queue_notify (manager); } static void override_callback (GSettings *settings, const gchar *key, GnomeXSettingsManager *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, GnomeXSettingsManager *manager) { if (g_str_equal (key, GTK_MODULES_DISABLED_KEY) || g_str_equal (key, GTK_MODULES_ENABLED_KEY)) { /* Do nothing, as GsdXsettingsGtk 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 (GsdXSettingsGtk *gtk, GParamSpec *spec, GnomeXSettingsManager *manager) { const char *modules = gsd_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, GnomeXSettingsManager *manager) { int i; int timestamp = time (NULL); gnome_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); gnome_settings_profile_end (NULL); } static gboolean start_fontconfig_monitor_idle_cb (GnomeXSettingsManager *manager) { gnome_settings_profile_start (NULL); manager->priv->fontconfig_handle = fontconfig_monitor_start ((GFunc) fontconfig_callback, manager); gnome_settings_profile_end (NULL); manager->priv->start_idle_id = 0; return FALSE; } static void start_fontconfig_monitor (GnomeXSettingsManager *manager) { gnome_settings_profile_start (NULL); fontconfig_cache_init (); manager->priv->start_idle_id = g_idle_add ((GSourceFunc) start_fontconfig_monitor_idle_cb, manager); gnome_settings_profile_end (NULL); } static void stop_fontconfig_monitor (GnomeXSettingsManager *manager) { if (manager->priv->fontconfig_handle) { fontconfig_monitor_stop (manager->priv->fontconfig_handle); manager->priv->fontconfig_handle = NULL; } } static void notify_have_shell (GnomeXSettingsManager *manager) { int i; gnome_settings_profile_start (NULL); for (i = 0; manager->priv->managers [i]; i++) { /* Shell is showing appmenu if either GNOME Shell or Unity is running. */ xsettings_manager_set_int (manager->priv->managers [i], "Gtk/ShellShowsAppMenu", manager->priv->have_shell || manager->priv->have_unity); /* Shell is showing menubar *only* if Unity runs */ xsettings_manager_set_int (manager->priv->managers [i], "Gtk/ShellShowsMenubar", manager->priv->have_unity); } queue_notify (manager); gnome_settings_profile_end (NULL); } static void on_shell_appeared (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) { GnomeXSettingsManager *manager = user_data; manager->priv->have_shell = TRUE; notify_have_shell (manager); } static void on_shell_disappeared (GDBusConnection *connection, const gchar *name, gpointer user_data) { GnomeXSettingsManager *manager = user_data; manager->priv->have_shell = FALSE; notify_have_shell (manager); } static void on_unity_appeared (GDBusConnection *connection, const gchar *name, const gchar *name_owner, gpointer user_data) { GnomeXSettingsManager *manager = user_data; manager->priv->have_unity = TRUE; notify_have_shell (manager); } static void on_unity_disappeared (GDBusConnection *connection, const gchar *name, gpointer user_data) { GnomeXSettingsManager *manager = user_data; manager->priv->have_unity = FALSE; notify_have_shell (manager); } static void process_value (GnomeXSettingsManager *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", &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, GnomeXSettingsManager *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 (GnomeXSettingsManager *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; } } return TRUE; } static void start_shell_monitor (GnomeXSettingsManager *manager) { notify_have_shell (manager); manager->priv->have_shell = TRUE; manager->priv->shell_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, "org.gnome.Shell", 0, on_shell_appeared, on_shell_disappeared, manager, NULL); } static void start_unity_monitor (GnomeXSettingsManager *manager) { notify_have_shell (manager); manager->priv->have_unity = TRUE; manager->priv->shell_name_watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION, "com.canonical.AppMenu.Registrar", 0, on_unity_appeared, on_unity_disappeared, manager, NULL); } gboolean gnome_xsettings_manager_start (GnomeXSettingsManager *manager, GError **error) { GVariant *overrides; guint i; GList *list, *l; g_debug ("Starting xsettings manager"); gnome_settings_profile_start (NULL); if (!setup_xsettings_managers (manager)) { g_set_error (error, GSD_XSETTINGS_ERROR, GSD_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, 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 = gsd_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); start_shell_monitor (manager); start_unity_monitor (manager); for (i = 0; manager->priv->managers [i]; i++) xsettings_manager_set_string (manager->priv->managers [i], "Net/FallbackIconTheme", "gnome"); overrides = g_settings_get_value (manager->priv->plugin_settings, XSETTINGS_OVERRIDE_KEY); for (i = 0; manager->priv->managers [i]; i++) { xsettings_manager_set_overrides (manager->priv->managers [i], overrides); } queue_notify (manager); g_variant_unref (overrides); gnome_settings_profile_end (NULL); return TRUE; } void gnome_xsettings_manager_stop (GnomeXSettingsManager *manager) { GnomeXSettingsManagerPrivate *p = manager->priv; int i; g_debug ("Stopping xsettings manager"); if (p->shell_name_watch_id > 0) g_bus_unwatch_name (p->shell_name_watch_id); 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 (manager->priv->unity_name_watch_id > 0) g_bus_unwatch_name (manager->priv->unity_name_watch_id); 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 * gnome_xsettings_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GnomeXSettingsManager *xsettings_manager; xsettings_manager = GNOME_XSETTINGS_MANAGER (G_OBJECT_CLASS (gnome_xsettings_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (xsettings_manager); } static void gnome_xsettings_manager_class_init (GnomeXSettingsManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = gnome_xsettings_manager_constructor; object_class->finalize = gnome_xsettings_manager_finalize; g_type_class_add_private (klass, sizeof (GnomeXSettingsManagerPrivate)); } static void gnome_xsettings_manager_init (GnomeXSettingsManager *manager) { manager->priv = GNOME_XSETTINGS_MANAGER_GET_PRIVATE (manager); } static void gnome_xsettings_manager_finalize (GObject *object) { GnomeXSettingsManager *xsettings_manager; g_return_if_fail (object != NULL); g_return_if_fail (GNOME_IS_XSETTINGS_MANAGER (object)); xsettings_manager = GNOME_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); G_OBJECT_CLASS (gnome_xsettings_manager_parent_class)->finalize (object); } GnomeXSettingsManager * gnome_xsettings_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (GNOME_TYPE_XSETTINGS_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return GNOME_XSETTINGS_MANAGER (manager_object); } unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/xsettings-common.h0000644000015300001610000000442712567031542027701 0ustar pbuserpbgroup00000000000000/* * 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 */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/xsettings-manager.c0000644000015300001610000002560712567031542030021 0ustar pbuserpbgroup00000000000000/* * 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); } } unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/README.xsettings0000644000015300001610000000257212567031542027120 0ustar pbuserpbgroup00000000000000This is very simple documentation for the 'override' GSettings key for gnome-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 gnome-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. unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/fontconfig-monitor.h0000644000015300001610000000254112567031542030177 0ustar pbuserpbgroup00000000000000/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/fontconfig-monitor.c0000644000015300001610000001125612567031542030175 0ustar pbuserpbgroup00000000000000/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 = g_timeout_add_seconds (TIMEOUT_SECONDS, update, data); } fontconfig_monitor_handle_t * fontconfig_monitor_start (GFunc notify_callback, gpointer notify_data) { fontconfig_monitor_handle_t *handle = g_slice_new0 (fontconfig_monitor_handle_t); handle->notify_callback = notify_callback; handle->notify_data = notify_data; handle->monitors = monitors_create (handle); return handle; } void fontconfig_monitor_stop (fontconfig_monitor_handle_t *handle) { if (handle->timeout) g_source_remove (handle->timeout); handle->timeout = 0; monitors_free (handle->monitors); handle->monitors = NULL; } #ifdef FONTCONFIG_MONITOR_TEST static void yay (void) { g_message ("yay"); } int main (void) { GMainLoop *loop; fontconfig_monitor_start ((GFunc) yay, NULL); loop = g_main_loop_new (NULL, TRUE); g_main_loop_run (loop); return 0; } #endif unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/gsd-xsettings-plugin.c0000644000015300001610000000203512567031542030446 0ustar pbuserpbgroup00000000000000/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include #include #include "gnome-settings-plugin.h" #include "gsd-xsettings-manager.h" GNOME_SETTINGS_PLUGIN_REGISTER (GnomeXSettings, gnome_xsettings) unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/gsd-xsettings-gtk.h0000644000015300001610000000414112567031542027742 0ustar pbuserpbgroup00000000000000/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __GSD_XSETTINGS_GTK_H__ #define __GSD_XSETTINGS_GTK_H__ #include #include #include G_BEGIN_DECLS #define GSD_TYPE_XSETTINGS_GTK (gsd_xsettings_gtk_get_type ()) #define GSD_XSETTINGS_GTK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_XSETTINGS_GTK, GsdXSettingsGtk)) #define GSD_XSETTINGS_GTK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_XSETTINGS_GTK, GsdXSettingsGtkClass)) #define GSD_IS_XSETTINGS_GTK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_XSETTINGS_GTK)) #define GSD_IS_XSETTINGS_GTK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_XSETTINGS_GTK)) #define GSD_XSETTINGS_GTK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_XSETTINGS_GTK, GsdXSettingsGtkClass)) typedef struct GsdXSettingsGtkPrivate GsdXSettingsGtkPrivate; typedef struct { GObject parent; GsdXSettingsGtkPrivate *priv; } GsdXSettingsGtk; typedef struct { GObjectClass parent_class; } GsdXSettingsGtkClass; GType gsd_xsettings_gtk_get_type (void) G_GNUC_CONST; GsdXSettingsGtk *gsd_xsettings_gtk_new (void); const char * gsd_xsettings_gtk_get_modules (GsdXSettingsGtk *gtk); G_END_DECLS #endif /* __GSD_XSETTINGS_GTK_H__ */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/xsettings-common.c0000644000015300001610000000561412567031542027673 0ustar pbuserpbgroup00000000000000/* * 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; } unity-settings-daemon-14.04.0+14.04.20150825/plugins/xsettings/xsettings-manager.h0000644000015300001610000000524012567031542030015 0ustar pbuserpbgroup00000000000000/* * 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 */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/0000755000015300001610000000000012567032025023256 5ustar pbuserpbgroup00000000000000unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/test-osd-window.c0000644000015300001610000000715712567031542026506 0ustar pbuserpbgroup00000000000000/* * 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 * */ #include "config.h" #include #include #include #include #include #include "gsd-wacom-osd-window.h" static gboolean option_debug = FALSE; static GsdWacomDevice * search_pad_device (void) { GdkDeviceManager *mgr; GList *list, *l; mgr = gdk_display_get_device_manager (gdk_display_get_default ()); list = gdk_device_manager_list_devices (mgr, GDK_DEVICE_TYPE_SLAVE); for (l = list; l ; l = l->next) { GsdWacomDevice *device; device = gsd_wacom_device_new (l->data); if (gsd_wacom_device_get_device_type (device) == WACOM_TYPE_PAD) return (device); g_object_unref (device); } g_list_free (list); return NULL; } static GsdWacomDevice * create_fake_device (const char *tablet) { GsdWacomDevice *device; gchar *tool; tool = g_strdup_printf ("%s pad", tablet); device = gsd_wacom_device_create_fake (WACOM_TYPE_PAD, tablet, tool); g_free (tool); return device; } static gboolean on_key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { gtk_main_quit(); return FALSE; } int main(int argc, char** argv) { GtkWidget *widget; GError *error = NULL; GOptionContext *context; GsdWacomDevice *device; gchar *message; gchar *tablet = NULL; const GOptionEntry entries[] = { { "tablet", 't', 0, G_OPTION_ARG_STRING, &tablet, "Name of the tablet to show", ""}, { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug, "Debug output", NULL }, { NULL } }; gtk_init (&argc, &argv); context = g_option_context_new ("- test functions"); g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); g_option_context_add_group (context, gtk_get_option_group (TRUE)); g_option_context_set_help_enabled (context, TRUE); if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) { g_print ("%s\n", error->message); return 1; } g_option_context_free (context); if (option_debug) g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); if (tablet) device = create_fake_device (tablet); else device = search_pad_device (); if (device == NULL) { g_print ("No pad device found, consider using --tablet\n"); return 1; } if (gsd_wacom_device_get_layout_path (device) == NULL) { g_print ("This device has not layout available in libwacom\n"); return 1; } message = g_strdup_printf ("%s\n(Press a key to exit)", gsd_wacom_device_get_name (device)); widget = gsd_wacom_osd_window_new (device, message); g_free (message); g_signal_connect (widget, "key-release-event", G_CALLBACK(on_key_release_event), NULL); g_signal_connect (widget, "delete-event", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect (widget, "unmap", G_CALLBACK (gtk_main_quit), NULL); gtk_widget_show (widget); gtk_main (); return 0; } unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/Makefile.am0000644000015300001610000001147712567031542025327 0ustar pbuserpbgroup00000000000000plugin_name = wacom plugin_LTLIBRARIES = libgsdwacom.la libgsdwacom_la_SOURCES = \ gsd-wacom-plugin.c \ gsd-wacom-manager.h \ gsd-wacom-manager.c \ gsd-wacom-osd-window.h \ gsd-wacom-osd-window.c \ gsd-wacom-device.c \ gsd-wacom-device.h \ gsd-wacom-resources.c libgsdwacom_la_CPPFLAGS = \ -I$(top_srcdir)/gnome-settings-daemon \ -I$(top_srcdir)/plugins/common/ \ -I$(top_srcdir)/data/ \ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) libgsdwacom_la_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(WACOM_CFLAGS) \ $(AM_CFLAGS) libgsdwacom_la_LDFLAGS = \ $(GSD_PLUGIN_LDFLAGS) libgsdwacom_la_LIBADD = \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_PLUGIN_LIBS) \ $(WACOM_LIBS) com.ubuntu.unity-settings-daemon.plugins.wacom.policy.in: com.ubuntu.unity-settings-daemon.plugins.wacom.policy.in.in Makefile $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ gsd-wacom-resources.c: wacom.gresource.xml tablet-layout.css glib-compile-resources \ --target=$@ \ --sourcedir=$(srcdir) \ --generate-source \ --c-name gsd_wacom \ $(srcdir)/wacom.gresource.xml @INTLTOOL_POLICY_RULE@ polkit_policydir = $(datadir)/polkit-1/actions polkit_policy_in_files = com.ubuntu.unity-settings-daemon.plugins.wacom.policy.in polkit_policy_DATA = $(polkit_policy_in_files:.policy.in=.policy) # so it always gets included in the tarball usd_wacom_led_helper_SOURCES = gsd-wacom-led-helper.c EXTRA_DIST = $(usd_wacom_led_helper_SOURCES) wacom.gresource.xml tablet-layout.css if HAVE_GUDEV libexec_PROGRAMS = usd-wacom-led-helper usd_wacom_led_helper_LDFLAGS = \ $(BACKLIGHT_HELPER_LIBS) \ -lm usd_wacom_led_helper_CFLAGS = \ $(BACKLIGHT_HELPER_CFLAGS) else libexec_PROGRAMS = endif EXTRA_DIST += com.ubuntu.unity-settings-daemon.plugins.wacom.policy.in.in libexec_PROGRAMS += usd-test-wacom usd-list-wacom usd-test-wacom-osd usd_test_wacom_SOURCES = \ test-wacom.c \ gsd-wacom-manager.c \ gsd-wacom-manager.h \ gsd-wacom-osd-window.h \ gsd-wacom-osd-window.c \ gsd-wacom-device.c \ gsd-wacom-device.h \ gsd-wacom-resources.c usd_test_wacom_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/gnome-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DBINDIR=\"$(bindir)\" \ -DPIXMAPDIR=\""$(pkgdatadir)"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ -DSCHEMA_NAME=\""gsdwacom"\" \ $(AM_CPPFLAGS) usd_test_wacom_CFLAGS = \ $(PLUGIN_CFLAGS) \ $(SETTINGS_PLUGIN_CFLAGS) \ $(WACOM_CFLAGS) \ $(AM_CFLAGS) usd_test_wacom_LDADD = \ $(top_builddir)/gnome-settings-daemon/libgsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(WACOM_LIBS) \ -lm usd_list_wacom_SOURCES = \ list-wacom.c \ gsd-wacom-device.c \ gsd-wacom-device.h usd_list_wacom_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/gnome-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DBINDIR=\"$(bindir)\" \ -DPIXMAPDIR=\""$(pkgdatadir)"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ $(AM_CPPFLAGS) usd_list_wacom_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(WACOM_CFLAGS) \ $(AM_CFLAGS) usd_list_wacom_LDADD = \ $(top_builddir)/gnome-settings-daemon/libgsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(WACOM_LIBS) \ -lm usd_test_wacom_osd_SOURCES = \ test-osd-window.c \ gsd-wacom-osd-window.h \ gsd-wacom-osd-window.c \ gsd-wacom-device.c \ gsd-wacom-device.h \ gsd-wacom-resources.c usd_test_wacom_osd_CPPFLAGS = \ -I$(top_srcdir)/data/ \ -I$(top_srcdir)/gnome-settings-daemon \ -I$(top_srcdir)/plugins/common \ -DBINDIR=\"$(bindir)\" \ -DPIXMAPDIR=\""$(pkgdatadir)"\" \ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \ -DGNOME_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) usd_test_wacom_osd_CFLAGS = \ $(SETTINGS_PLUGIN_CFLAGS) \ $(WACOM_CFLAGS) \ $(AM_CFLAGS) usd_test_wacom_osd_LDADD = \ $(top_builddir)/gnome-settings-daemon/libgsd.la \ $(top_builddir)/plugins/common/libcommon.la \ $(SETTINGS_DAEMON_LIBS) \ $(SETTINGS_PLUGIN_LIBS) \ $(WACOM_LIBS) \ -lm plugin_in_files = wacom.gnome-settings-plugin.in plugin_DATA = $(plugin_in_files:.gnome-settings-plugin.in=.gnome-settings-plugin) EXTRA_DIST += $(plugin_in_files) README.config-storage CLEANFILES = \ $(plugin_DATA) \ gsd-wacom-resources.c \ com.ubuntu.unity-settings-daemon.plugins.wacom.policy \ com.ubuntu.unity-settings-daemon.plugins.wacom.policy.in @GSD_INTLTOOL_PLUGIN_RULE@ unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/tablet-layout.css0000644000015300001610000000162512567031542026565 0ustar pbuserpbgroup00000000000000 unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/test-wacom.c0000644000015300001610000000030512567031542025506 0ustar pbuserpbgroup00000000000000#define NEW gsd_wacom_manager_new #define START gsd_wacom_manager_start #define STOP gsd_wacom_manager_stop #define MANAGER GsdWacomManager #include "gsd-wacom-manager.h" #include "test-plugin.h" unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/gsd-wacom-device.h0000644000015300001610000002041212567031542026547 0ustar pbuserpbgroup00000000000000/* * 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 __GSD_WACOM_DEVICE_MANAGER_H #define __GSD_WACOM_DEVICE_MANAGER_H #include #include "gsd-enums.h" G_BEGIN_DECLS #define NUM_ELEMS_MATRIX 9 #define GSD_TYPE_WACOM_DEVICE (gsd_wacom_device_get_type ()) #define GSD_WACOM_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_WACOM_DEVICE, GsdWacomDevice)) #define GSD_WACOM_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_WACOM_DEVICE, GsdWacomDeviceClass)) #define GSD_IS_WACOM_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_WACOM_DEVICE)) #define GSD_IS_WACOM_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_WACOM_DEVICE)) #define GSD_WACOM_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_WACOM_DEVICE, GsdWacomDeviceClass)) typedef struct GsdWacomDevicePrivate GsdWacomDevicePrivate; typedef struct { GObject parent; GsdWacomDevicePrivate *priv; } GsdWacomDevice; typedef struct { GObjectClass parent_class; } GsdWacomDeviceClass; #define GSD_TYPE_WACOM_STYLUS (gsd_wacom_stylus_get_type ()) #define GSD_WACOM_STYLUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_WACOM_STYLUS, GsdWacomStylus)) #define GSD_WACOM_STYLUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_WACOM_STYLUS, GsdWacomStylusClass)) #define GSD_IS_WACOM_STYLUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_WACOM_STYLUS)) #define GSD_IS_WACOM_STYLUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_WACOM_STYLUS)) #define GSD_WACOM_STYLUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_WACOM_STYLUS, GsdWacomStylusClass)) typedef struct GsdWacomStylusPrivate GsdWacomStylusPrivate; typedef struct { GObject parent; GsdWacomStylusPrivate *priv; } GsdWacomStylus; typedef struct { GObjectClass parent_class; } GsdWacomStylusClass; 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 } GsdWacomStylusType; GType gsd_wacom_stylus_get_type (void); GSettings * gsd_wacom_stylus_get_settings (GsdWacomStylus *stylus); const char * gsd_wacom_stylus_get_name (GsdWacomStylus *stylus); const char * gsd_wacom_stylus_get_icon_name (GsdWacomStylus *stylus); GsdWacomDevice * gsd_wacom_stylus_get_device (GsdWacomStylus *stylus); gboolean gsd_wacom_stylus_get_has_eraser (GsdWacomStylus *stylus); guint gsd_wacom_stylus_get_num_buttons(GsdWacomStylus *stylus); int gsd_wacom_stylus_get_id (GsdWacomStylus *stylus); GsdWacomStylusType gsd_wacom_stylus_get_stylus_type (GsdWacomStylus *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 } GsdWacomTabletButtonType; /* * 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 } GsdWacomTabletButtonPos; #define MAX_GROUP_ID 4 #define GSD_WACOM_NO_LED -1 typedef struct { char *name; char *id; GSettings *settings; GsdWacomTabletButtonType type; GsdWacomTabletButtonPos pos; int group_id, idx; int status_led; } GsdWacomTabletButton; void gsd_wacom_tablet_button_free (GsdWacomTabletButton *button); GsdWacomTabletButton *gsd_wacom_tablet_button_copy (GsdWacomTabletButton *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 } GsdWacomDeviceType; /* We use -1 for entire screen when setting/getting monitor value */ #define GSD_WACOM_SET_ALL_MONITORS -1 GType gsd_wacom_device_get_type (void); void gsd_wacom_device_set_display (GsdWacomDevice *device, int monitor); gint gsd_wacom_device_get_display_monitor (GsdWacomDevice *device); gboolean gsd_wacom_device_get_display_matrix (GsdWacomDevice *device, float matrix[NUM_ELEMS_MATRIX]); GsdWacomRotation gsd_wacom_device_get_display_rotation (GsdWacomDevice *device); GsdWacomDevice * gsd_wacom_device_new (GdkDevice *device); GList * gsd_wacom_device_list_styli (GsdWacomDevice *device); const char * gsd_wacom_device_get_name (GsdWacomDevice *device); const char * gsd_wacom_device_get_layout_path (GsdWacomDevice *device); const char * gsd_wacom_device_get_path (GsdWacomDevice *device); const char * gsd_wacom_device_get_icon_name (GsdWacomDevice *device); const char * gsd_wacom_device_get_tool_name (GsdWacomDevice *device); gboolean gsd_wacom_device_reversible (GsdWacomDevice *device); gboolean gsd_wacom_device_is_screen_tablet (GsdWacomDevice *device); gboolean gsd_wacom_device_is_isd (GsdWacomDevice *device); gboolean gsd_wacom_device_is_fallback (GsdWacomDevice *device); gint gsd_wacom_device_get_num_strips (GsdWacomDevice *device); gint gsd_wacom_device_get_num_rings (GsdWacomDevice *device); GSettings * gsd_wacom_device_get_settings (GsdWacomDevice *device); void gsd_wacom_device_set_current_stylus (GsdWacomDevice *device, int stylus_id); GsdWacomStylus * gsd_wacom_device_get_stylus_for_type (GsdWacomDevice *device, GsdWacomStylusType type); GsdWacomDeviceType gsd_wacom_device_get_device_type (GsdWacomDevice *device); gint * gsd_wacom_device_get_area (GsdWacomDevice *device); const char * gsd_wacom_device_type_to_string (GsdWacomDeviceType type); GList * gsd_wacom_device_get_buttons (GsdWacomDevice *device); GsdWacomTabletButton *gsd_wacom_device_get_button (GsdWacomDevice *device, int button, GtkDirectionType *dir); int gsd_wacom_device_get_num_modes (GsdWacomDevice *device, int group_id); int gsd_wacom_device_get_current_mode (GsdWacomDevice *device, int group_id); int gsd_wacom_device_set_next_mode (GsdWacomDevice *device, GsdWacomTabletButton *button); GsdWacomRotation gsd_wacom_device_rotation_name_to_type (const char *rotation); const char * gsd_wacom_device_rotation_type_to_name (GsdWacomRotation type); /* Helper and debug functions */ GsdWacomDevice * gsd_wacom_device_create_fake (GsdWacomDeviceType type, const char *name, const char *tool_name); GList * gsd_wacom_device_create_fake_cintiq (void); GList * gsd_wacom_device_create_fake_bt (void); GList * gsd_wacom_device_create_fake_x201 (void); GList * gsd_wacom_device_create_fake_intuos4 (void); G_END_DECLS #endif /* __GSD_WACOM_DEVICE_MANAGER_H */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/list-wacom.c0000644000015300001610000001723112567031542025510 0ustar pbuserpbgroup00000000000000/* * 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 "gsd-wacom-device.h" static gboolean fake_devices = FALSE; static gboolean monitor_styli = FALSE; static gboolean option_debug = FALSE; static char * get_loc (GSettings *settings) { char *path, *schema, *ret; g_return_val_if_fail (G_IS_SETTINGS (settings), NULL); g_object_get (G_OBJECT (settings), "path", &path, "schema", &schema, NULL); ret = g_strdup_printf ("schema: %s (path: %s)", schema, path); g_free (schema); g_free (path); return ret; } static const char * stylus_type_to_string (GsdWacomStylusType type) { switch (type) { case WACOM_STYLUS_TYPE_UNKNOWN: return "Unknown"; case WACOM_STYLUS_TYPE_GENERAL: return "General"; case WACOM_STYLUS_TYPE_INKING: return "Inking"; case WACOM_STYLUS_TYPE_AIRBRUSH: return "Airbrush"; case WACOM_STYLUS_TYPE_CLASSIC: return "Classic"; case WACOM_STYLUS_TYPE_MARKER: return "Marker"; case WACOM_STYLUS_TYPE_STROKE: return "Stroke"; case WACOM_STYLUS_TYPE_PUCK: return "Puck"; default: g_assert_not_reached (); } return NULL; } static const char * button_type_to_string (GsdWacomTabletButtonType type) { switch (type) { case WACOM_TABLET_BUTTON_TYPE_NORMAL: return "normal"; case WACOM_TABLET_BUTTON_TYPE_STRIP: return "touch-strip"; case WACOM_TABLET_BUTTON_TYPE_RING: return "touch-ring"; case WACOM_TABLET_BUTTON_TYPE_HARDCODED: return "hard-coded"; default: g_assert_not_reached (); } } #define BOOL_AS_STR(x) (x ? "yes" : "no") static void print_stylus (GsdWacomStylus *stylus, gboolean is_current) { GsdWacomDevice *device; char *loc; device = gsd_wacom_stylus_get_device (stylus); g_print ("\t%sStylus: '%s' (Type: %s, ID: 0x%x)\n", is_current ? "*** " : "", gsd_wacom_stylus_get_name (stylus), stylus_type_to_string (gsd_wacom_stylus_get_stylus_type (stylus)), gsd_wacom_stylus_get_id (stylus)); loc = get_loc (gsd_wacom_stylus_get_settings (stylus)); g_print ("\t\tSettings: %s\n", loc); g_free (loc); g_print ("\t\tIcon name: %s\n", gsd_wacom_stylus_get_icon_name (stylus)); if (gsd_wacom_device_get_device_type (device) == WACOM_TYPE_STYLUS) { int num_buttons; char *buttons; g_print ("\t\tHas Eraser: %s\n", BOOL_AS_STR(gsd_wacom_stylus_get_has_eraser (stylus))); num_buttons = gsd_wacom_stylus_get_num_buttons (stylus); if (num_buttons < 0) num_buttons = 2; if (num_buttons > 0) buttons = g_strdup_printf ("%d buttons", num_buttons); else buttons = g_strdup ("no button"); g_print ("\t\tButtons: %s\n", buttons); g_free (buttons); } } static void print_buttons (GsdWacomDevice *device) { GList *buttons, *l; buttons = gsd_wacom_device_get_buttons (device); if (buttons == NULL) return; for (l = buttons; l != NULL; l = l->next) { GsdWacomTabletButton *button = l->data; g_print ("\tButton: %s (%s)\n", button->name, button->id); g_print ("\t\tType: %s\n", button_type_to_string (button->type)); if (button->group_id > 0) { g_print ("\t\tGroup: %d", button->group_id); if (button->idx >= 0) g_print (" Index: %d\n", button->idx); else g_print ("\n"); } if (button->settings) { char *loc; loc = get_loc (button->settings); g_print ("\t\tSettings: %s\n", loc); g_free (loc); } } g_list_free (buttons); } static void last_stylus_changed (GsdWacomDevice *device, GParamSpec *pspec, gpointer user_data) { GsdWacomStylus *stylus; g_object_get (device, "last-stylus", &stylus, NULL); g_print ("Stylus changed for device '%s'\n", gsd_wacom_device_get_tool_name (device)); print_stylus (stylus, TRUE); } static void list_devices (GList *devices) { GList *l; for (l = devices; l ; l = l->next) { GsdWacomDevice *device; GsdWacomDeviceType type; char *loc; device = l->data; g_signal_connect (G_OBJECT (device), "notify::last-stylus", G_CALLBACK (last_stylus_changed), NULL); g_print ("Device '%s' (type: %s)\n", gsd_wacom_device_get_name (device), gsd_wacom_device_type_to_string (gsd_wacom_device_get_device_type (device))); g_print ("\tReversible: %s\n", BOOL_AS_STR (gsd_wacom_device_reversible (device))); g_print ("\tScreen Tablet: %s\n", BOOL_AS_STR (gsd_wacom_device_is_screen_tablet (device))); g_print ("\tIntegrated Device: %s\n", BOOL_AS_STR (gsd_wacom_device_is_isd (device))); g_print ("\tUnknown (fallback) device: %s\n", BOOL_AS_STR(gsd_wacom_device_is_fallback (device))); loc = get_loc (gsd_wacom_device_get_settings (device)); g_print ("\tGeneric settings: %s\n", loc); g_free (loc); type = gsd_wacom_device_get_device_type (device); if (type == WACOM_TYPE_STYLUS || type == WACOM_TYPE_ERASER) { GList *styli, *j; GsdWacomStylus *current_stylus; g_object_get (device, "last-stylus", ¤t_stylus, NULL); styli = gsd_wacom_device_list_styli (device); for (j = styli; j; j = j->next) { GsdWacomStylus *stylus; stylus = j->data; print_stylus (stylus, current_stylus == stylus); } g_list_free (styli); } print_buttons (device); if (monitor_styli == FALSE) g_object_unref (device); } g_list_free (devices); } static void list_actual_devices (void) { GdkDeviceManager *mgr; GList *list, *l, *devices; mgr = gdk_display_get_device_manager (gdk_display_get_default ()); list = gdk_device_manager_list_devices (mgr, GDK_DEVICE_TYPE_SLAVE); devices = NULL; for (l = list; l ; l = l->next) { GsdWacomDevice *device; device = gsd_wacom_device_new (l->data); if (gsd_wacom_device_get_device_type (device) == WACOM_TYPE_INVALID) { g_object_unref (device); continue; } devices = g_list_prepend (devices, device); } g_list_free (list); list_devices (devices); } static void list_fake_devices (void) { GList *devices; devices = gsd_wacom_device_create_fake_cintiq (); list_devices (devices); devices = gsd_wacom_device_create_fake_bt (); list_devices (devices); devices = gsd_wacom_device_create_fake_x201 (); list_devices (devices); devices = gsd_wacom_device_create_fake_intuos4 (); list_devices (devices); } int main (int argc, char **argv) { GError *error = NULL; GOptionContext *context; const GOptionEntry entries[] = { { "fake", 'f', 0, G_OPTION_ARG_NONE, &fake_devices, "Output fake devices", NULL }, { "monitor", 'm', 0, G_OPTION_ARG_NONE, &monitor_styli, "Monitor changing styli", NULL }, { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug, "Debug output", NULL }, { NULL } }; gtk_init (&argc, &argv); context = g_option_context_new ("- test parser functions"); g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) { g_print ("Option parsing failed: %s\n", error->message); return 1; } if (option_debug) g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); if (fake_devices == FALSE) list_actual_devices (); else list_fake_devices (); if (monitor_styli) gtk_main (); return 0; } unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/gsd-wacom-osd-window.c0000644000015300001610000014254012567031542027404 0ustar pbuserpbgroup00000000000000/* * 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 * */ #include "config.h" #include #include #include #include #include #include #include "gsd-wacom-osd-window.h" #include "gsd-wacom-device.h" #include "gsd-enums.h" #define ROTATION_KEY "rotation" #define ACTION_TYPE_KEY "action-type" #define CUSTOM_ACTION_KEY "custom-action" #define CUSTOM_ELEVATOR_ACTION_KEY "custom-elevator-action" #define RES_PATH "/org/gnome/settings-daemon/plugins/wacom/" #define BACK_OPACITY 0.8 #define INACTIVE_COLOR "#ededed" #define ACTIVE_COLOR "#729fcf" #define STROKE_COLOR "#000000" #define DARK_COLOR "#535353" #define BACK_COLOR "#000000" #define ELEVATOR_TIMEOUT 250 /* ms */ static struct { const gchar *color_name; const gchar *color_value; } css_color_table[] = { { "inactive_color", INACTIVE_COLOR }, { "active_color", ACTIVE_COLOR }, { "stroke_color", STROKE_COLOR }, { "dark_color", DARK_COLOR }, { "back_color", BACK_COLOR } }; static gchar * replace_string (gchar **string, const gchar *search, const char *replacement) { GRegex *regex; gchar *res; g_return_val_if_fail (*string != NULL, NULL); g_return_val_if_fail (string != NULL, NULL); g_return_val_if_fail (search != NULL, *string); g_return_val_if_fail (replacement != NULL, *string); regex = g_regex_new (search, 0, 0, NULL); res = g_regex_replace_literal (regex, *string, -1, 0, replacement, 0, NULL); g_regex_unref (regex); /* The given string is freed and replaced by the resulting replacement */ g_free (*string); *string = res; return res; } static gchar get_last_char (gchar *string) { size_t pos; g_return_val_if_fail (string != NULL, '\0'); pos = strlen (string); g_return_val_if_fail (pos > 0, '\0'); return string[pos - 1]; } static double get_rotation_in_radian (GsdWacomRotation rotation) { switch (rotation) { case GSD_WACOM_ROTATION_NONE: return 0.0; break; case GSD_WACOM_ROTATION_HALF: return G_PI; break; /* We only support left-handed/right-handed */ case GSD_WACOM_ROTATION_CCW: case GSD_WACOM_ROTATION_CW: default: break; } /* Fallback */ return 0.0; } static gboolean get_sub_location (RsvgHandle *handle, const char *sub, cairo_t *cr, double *x, double *y) { RsvgPositionData position; double tx, ty; if (!rsvg_handle_get_position_sub (handle, &position, sub)) { g_warning ("Failed to retrieve '%s' position", sub); return FALSE; } tx = (double) position.x; ty = (double) position.y; cairo_user_to_device (cr, &tx, &ty); if (x) *x = tx; if (y) *y = ty; return TRUE; } static gboolean get_image_size (const char *filename, int *width, int *height) { RsvgHandle *handle; RsvgDimensionData dimensions; GError* error = NULL; if (filename == NULL) return FALSE; handle = rsvg_handle_new_from_file (filename, &error); if (error != NULL) { g_printerr ("%s\n", error->message); g_error_free (error); } if (handle == NULL) return FALSE; /* Compute image size */ rsvg_handle_get_dimensions (handle, &dimensions); g_object_unref (handle); if (dimensions.width == 0 || dimensions.height == 0) return FALSE; if (width) *width = dimensions.width; if (height) *height = dimensions.height; return TRUE; } static int get_pango_vertical_offset (PangoLayout *layout) { const PangoFontDescription *desc; PangoContext *context; PangoLanguage *language; PangoFontMetrics *metrics; int baseline; int strikethrough; int thickness; context = pango_layout_get_context (layout); language = pango_language_get_default (); desc = pango_layout_get_font_description (layout); metrics = pango_context_get_metrics (context, desc, language); baseline = pango_layout_get_baseline (layout); strikethrough = pango_font_metrics_get_strikethrough_position (metrics); thickness = pango_font_metrics_get_underline_thickness (metrics); return PANGO_PIXELS (baseline - strikethrough - thickness / 2); } #define GSD_TYPE_WACOM_OSD_BUTTON (gsd_wacom_osd_button_get_type ()) #define GSD_WACOM_OSD_BUTTON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_WACOM_OSD_BUTTON, GsdWacomOSDButton)) #define GSD_WACOM_OSD_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_WACOM_OSD_BUTTON, GsdWacomOSDButtonClass)) #define GSD_IS_WACOM_OSD_BUTTON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_WACOM_OSD_BUTTON)) #define GSD_IS_WACOM_OSD_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_WACOM_OSD_BUTTON)) #define GSD_WACOM_OSD_BUTTON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_WACOM_OSD_BUTTON, GsdWacomOSDButtonClass)) typedef struct GsdWacomOSDButtonPrivate GsdWacomOSDButtonPrivate; typedef struct { GObject parent; GsdWacomOSDButtonPrivate *priv; } GsdWacomOSDButton; typedef struct { GObjectClass parent_class; } GsdWacomOSDButtonClass; GType gsd_wacom_osd_button_get_type (void) G_GNUC_CONST; enum { PROP_OSD_BUTTON_0, PROP_OSD_BUTTON_ID, PROP_OSD_BUTTON_CLASS, PROP_OSD_BUTTON_LABEL, PROP_OSD_BUTTON_ACTIVE, PROP_OSD_BUTTON_VISIBLE, PROP_OSD_BUTTON_AUTO_OFF }; #define GSD_WACOM_OSD_BUTTON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ GSD_TYPE_WACOM_OSD_BUTTON, \ GsdWacomOSDButtonPrivate)) #define MATCH_ID(b,s) (g_strcmp0 (b->priv->id, s) == 0) struct GsdWacomOSDButtonPrivate { GtkWidget *widget; char *id; char *class; char *label; double label_x; double label_y; GsdWacomTabletButtonType type; GsdWacomTabletButtonPos position; gboolean active; gboolean visible; guint auto_off; guint timeout; }; static void gsd_wacom_osd_button_class_init (GsdWacomOSDButtonClass *klass); static void gsd_wacom_osd_button_init (GsdWacomOSDButton *osd_button); static void gsd_wacom_osd_button_finalize (GObject *object); G_DEFINE_TYPE (GsdWacomOSDButton, gsd_wacom_osd_button, G_TYPE_OBJECT) static void gsd_wacom_osd_button_set_id (GsdWacomOSDButton *osd_button, const gchar *id) { g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->id = g_strdup (id); } static void gsd_wacom_osd_button_set_class (GsdWacomOSDButton *osd_button, const gchar *class) { g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->class = g_strdup (class); } static gchar* gsd_wacom_osd_button_get_label_class (GsdWacomOSDButton *osd_button) { gchar *label_class; label_class = g_strconcat ("#Label", osd_button->priv->class, NULL); return (label_class); } static void gsd_wacom_osd_button_set_label (GsdWacomOSDButton *osd_button, const gchar *str) { g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button)); g_free (osd_button->priv->label); osd_button->priv->label = g_strdup (str ? str : ""); } static void gsd_wacom_osd_button_set_button_type (GsdWacomOSDButton *osd_button, GsdWacomTabletButtonType type) { g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->type = type; } static void gsd_wacom_osd_button_set_position (GsdWacomOSDButton *osd_button, GsdWacomTabletButtonPos position) { g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->position = position; } static void gsd_wacom_osd_button_set_location (GsdWacomOSDButton *osd_button, double x, double y) { g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->label_x = x; osd_button->priv->label_y = y; } static void gsd_wacom_osd_button_set_auto_off (GsdWacomOSDButton *osd_button, guint timeout) { g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->auto_off = timeout; } static void gsd_wacom_osd_button_redraw (GsdWacomOSDButton *osd_button) { GdkWindow *window; g_return_if_fail (GTK_IS_WIDGET (osd_button->priv->widget)); window = gtk_widget_get_window (GTK_WIDGET (osd_button->priv->widget)); gdk_window_invalidate_rect (window, NULL, FALSE); } static gboolean gsd_wacom_osd_button_timer (GsdWacomOSDButton *osd_button) { /* Auto de-activate the button */ osd_button->priv->active = FALSE; gsd_wacom_osd_button_redraw (osd_button); return FALSE; } static void gsd_wacom_osd_button_set_active (GsdWacomOSDButton *osd_button, gboolean active) { gboolean previous_state; g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button)); previous_state = osd_button->priv->active; if (osd_button->priv->auto_off > 0) { /* For auto-off buttons, apply only if active, de-activation is done in the timeout */ if (active == TRUE) osd_button->priv->active = active; if (osd_button->priv->timeout) g_source_remove (osd_button->priv->timeout); osd_button->priv->timeout = g_timeout_add (osd_button->priv->auto_off, (GSourceFunc) gsd_wacom_osd_button_timer, osd_button); } else { /* Whereas for other buttons, apply the change straight away */ osd_button->priv->active = active; } if (previous_state != osd_button->priv->active) gsd_wacom_osd_button_redraw (osd_button); } static void gsd_wacom_osd_button_set_visible (GsdWacomOSDButton *osd_button, gboolean visible) { g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button)); osd_button->priv->visible = visible; } static GsdWacomOSDButton * gsd_wacom_osd_button_new (GtkWidget *widget, gchar *id) { GsdWacomOSDButton *osd_button; osd_button = GSD_WACOM_OSD_BUTTON (g_object_new (GSD_TYPE_WACOM_OSD_BUTTON, "id", id, NULL)); osd_button->priv->widget = widget; return osd_button; } static void gsd_wacom_osd_button_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GsdWacomOSDButton *osd_button; osd_button = GSD_WACOM_OSD_BUTTON (object); switch (prop_id) { case PROP_OSD_BUTTON_ID: gsd_wacom_osd_button_set_id (osd_button, g_value_get_string (value)); break; case PROP_OSD_BUTTON_CLASS: gsd_wacom_osd_button_set_class (osd_button, g_value_get_string (value)); break; case PROP_OSD_BUTTON_LABEL: gsd_wacom_osd_button_set_label (osd_button, g_value_get_string (value)); break; case PROP_OSD_BUTTON_ACTIVE: gsd_wacom_osd_button_set_active (osd_button, g_value_get_boolean (value)); break; case PROP_OSD_BUTTON_VISIBLE: gsd_wacom_osd_button_set_visible (osd_button, g_value_get_boolean (value)); break; case PROP_OSD_BUTTON_AUTO_OFF: gsd_wacom_osd_button_set_auto_off (osd_button, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gsd_wacom_osd_button_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GsdWacomOSDButton *osd_button; osd_button = GSD_WACOM_OSD_BUTTON (object); switch (prop_id) { case PROP_OSD_BUTTON_ID: g_value_set_string (value, osd_button->priv->id); break; case PROP_OSD_BUTTON_CLASS: g_value_set_string (value, osd_button->priv->class); break; case PROP_OSD_BUTTON_LABEL: g_value_set_string (value, osd_button->priv->label); break; case PROP_OSD_BUTTON_ACTIVE: g_value_set_boolean (value, osd_button->priv->active); break; case PROP_OSD_BUTTON_VISIBLE: g_value_set_boolean (value, osd_button->priv->visible); break; case PROP_OSD_BUTTON_AUTO_OFF: g_value_set_uint (value, osd_button->priv->auto_off); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gsd_wacom_osd_button_class_init (GsdWacomOSDButtonClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = gsd_wacom_osd_button_set_property; object_class->get_property = gsd_wacom_osd_button_get_property; object_class->finalize = gsd_wacom_osd_button_finalize; g_object_class_install_property (object_class, PROP_OSD_BUTTON_ID, g_param_spec_string ("id", "Button Id", "The Wacom Button ID", "", G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_OSD_BUTTON_CLASS, g_param_spec_string ("class", "Button Class", "The Wacom Button Class", "", G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_OSD_BUTTON_LABEL, g_param_spec_string ("label", "Label", "The button label", "", G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_OSD_BUTTON_ACTIVE, g_param_spec_boolean ("active", "Active", "Whether the button is active", FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_OSD_BUTTON_VISIBLE, g_param_spec_boolean ("visible", "Visible", "Whether the button is visible", TRUE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_OSD_BUTTON_AUTO_OFF, g_param_spec_uint ("auto-off", "Auto Off", "Timeout before button disables itself automatically", 0, G_MAXUINT, 0, /* disabled by default */ G_PARAM_READWRITE)); g_type_class_add_private (klass, sizeof (GsdWacomOSDButtonPrivate)); } static void gsd_wacom_osd_button_init (GsdWacomOSDButton *osd_button) { osd_button->priv = GSD_WACOM_OSD_BUTTON_GET_PRIVATE (osd_button); } static void gsd_wacom_osd_button_finalize (GObject *object) { GsdWacomOSDButton *osd_button; GsdWacomOSDButtonPrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (object)); osd_button = GSD_WACOM_OSD_BUTTON (object); g_return_if_fail (osd_button->priv != NULL); priv = osd_button->priv; if (priv->timeout > 0) g_source_remove (priv->timeout); g_clear_pointer (&priv->id, g_free); g_clear_pointer (&priv->class, g_free); g_clear_pointer (&priv->label, g_free); G_OBJECT_CLASS (gsd_wacom_osd_button_parent_class)->finalize (object); } /* Compute the new actual position once rotation is applied */ static GsdWacomTabletButtonPos get_actual_position (GsdWacomTabletButtonPos position, GsdWacomRotation rotation) { switch (rotation) { case GSD_WACOM_ROTATION_NONE: return position; break; case GSD_WACOM_ROTATION_HALF: if (position == WACOM_TABLET_BUTTON_POS_LEFT) return WACOM_TABLET_BUTTON_POS_RIGHT; if (position == WACOM_TABLET_BUTTON_POS_RIGHT) return WACOM_TABLET_BUTTON_POS_LEFT; if (position == WACOM_TABLET_BUTTON_POS_TOP) return WACOM_TABLET_BUTTON_POS_BOTTOM; if (position == WACOM_TABLET_BUTTON_POS_BOTTOM) return WACOM_TABLET_BUTTON_POS_TOP; break; /* We only support left-handed/right-handed */ case GSD_WACOM_ROTATION_CCW: case GSD_WACOM_ROTATION_CW: default: break; } /* fallback */ return position; } static void gsd_wacom_osd_button_draw_label (GsdWacomOSDButton *osd_button, GtkStyleContext *style_context, PangoContext *pango_context, cairo_t *cr, GsdWacomRotation rotation) { GsdWacomOSDButtonPrivate *priv; PangoLayout *layout; PangoRectangle logical_rect; GsdWacomTabletButtonPos actual_position; double lx, ly; gchar *markup; g_return_if_fail (GSD_IS_WACOM_OSD_BUTTON (osd_button)); priv = osd_button->priv; if (priv->visible == FALSE) return; actual_position = get_actual_position (priv->position, rotation); layout = pango_layout_new (pango_context); if (priv->active) markup = g_strdup_printf ("%s", priv->label); else markup = g_strdup_printf ("%s", priv->label); pango_layout_set_markup (layout, markup, -1); g_free (markup); pango_layout_get_pixel_extents (layout, NULL, &logical_rect); switch (actual_position) { case WACOM_TABLET_BUTTON_POS_LEFT: pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT); lx = priv->label_x + logical_rect.x; ly = priv->label_y + logical_rect.y - get_pango_vertical_offset (layout); break; case WACOM_TABLET_BUTTON_POS_RIGHT: pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); lx = priv->label_x + logical_rect.x - logical_rect.width; ly = priv->label_y + logical_rect.y - get_pango_vertical_offset (layout); break; case WACOM_TABLET_BUTTON_POS_TOP: pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); lx = priv->label_x + logical_rect.x - logical_rect.width / 2; ly = priv->label_y + logical_rect.y; break; case WACOM_TABLET_BUTTON_POS_BOTTOM: pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); lx = priv->label_x + logical_rect.x - logical_rect.width / 2; ly = priv->label_y + logical_rect.y - logical_rect.height; break; default: g_warning ("Unhandled button position"); pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); lx = priv->label_x + logical_rect.x - logical_rect.width / 2; ly = priv->label_y + logical_rect.y - logical_rect.height / 2; break; } gtk_render_layout (style_context, cr, lx, ly, layout); g_object_unref (layout); } enum { PROP_OSD_WINDOW_0, PROP_OSD_WINDOW_MESSAGE, PROP_OSD_WINDOW_GSD_WACOM_DEVICE }; #define GSD_WACOM_OSD_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ GSD_TYPE_WACOM_OSD_WINDOW, \ GsdWacomOSDWindowPrivate)) struct GsdWacomOSDWindowPrivate { RsvgHandle *handle; GsdWacomDevice *pad; GsdWacomRotation rotation; GdkRectangle screen_area; GdkRectangle monitor_area; GdkRectangle tablet_area; char *message; GList *buttons; }; static void gsd_wacom_osd_window_class_init (GsdWacomOSDWindowClass *klass); static void gsd_wacom_osd_window_init (GsdWacomOSDWindow *osd_window); static void gsd_wacom_osd_window_finalize (GObject *object); G_DEFINE_TYPE (GsdWacomOSDWindow, gsd_wacom_osd_window, GTK_TYPE_WINDOW) static RsvgHandle * load_rsvg_with_base (const char *css_string, const char *original_layout_path, GError **error) { RsvgHandle *handle; char *dirname; handle = rsvg_handle_new (); dirname = g_path_get_dirname (original_layout_path); rsvg_handle_set_base_uri (handle, dirname); g_free (dirname); if (!rsvg_handle_write (handle, (guint8 *) css_string, strlen (css_string), error)) { g_object_unref (handle); return NULL; } if (!rsvg_handle_close (handle, error)) { g_object_unref (handle); return NULL; } return handle; } static void gsd_wacom_osd_window_update (GsdWacomOSDWindow *osd_window) { GError *error = NULL; gchar *width, *height; gchar *buttons_section; gchar *css_string; const gchar *layout_file; GBytes *css_data; guint i; GList *l; g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window)); g_return_if_fail (GSD_IS_WACOM_DEVICE (osd_window->priv->pad)); css_data = g_resources_lookup_data (RES_PATH "tablet-layout.css", 0, &error); if (error != NULL) { g_printerr ("GResource error: %s\n", error->message); g_clear_pointer (&error, g_error_free); } if (css_data == NULL) return; css_string = g_strdup ((gchar *) g_bytes_get_data (css_data, NULL)); g_bytes_unref(css_data); width = g_strdup_printf ("%d", osd_window->priv->tablet_area.width); replace_string (&css_string, "layout_width", width); g_free (width); height = g_strdup_printf ("%d", osd_window->priv->tablet_area.height); replace_string (&css_string, "layout_height", height); g_free (height); /* Build the buttons section */ buttons_section = g_strdup (""); for (l = osd_window->priv->buttons; l != NULL; l = l->next) { GsdWacomOSDButton *osd_button = l->data; if (osd_button->priv->visible == FALSE) continue; if (osd_button->priv->active) { buttons_section = g_strconcat (buttons_section, ".", osd_button->priv->class, " {\n" " stroke: active_color !important;\n" " fill: active_color !important;\n" " }\n", NULL); } } replace_string (&css_string, "buttons_section", buttons_section); g_free (buttons_section); for (i = 0; i < G_N_ELEMENTS (css_color_table); i++) replace_string (&css_string, css_color_table[i].color_name, css_color_table[i].color_value); layout_file = gsd_wacom_device_get_layout_path (osd_window->priv->pad); replace_string (&css_string, "layout_file", layout_file); /* Render the SVG with the CSS applied */ g_clear_object (&osd_window->priv->handle); osd_window->priv->handle = load_rsvg_with_base (css_string, layout_file, &error); if (osd_window->priv->handle == NULL) { g_debug ("CSS applied:\n%s\n", css_string); g_printerr ("RSVG error: %s\n", error->message); g_clear_error (&error); } g_free (css_string); } static void gsd_wacom_osd_window_draw_message (GsdWacomOSDWindow *osd_window, GtkStyleContext *style_context, PangoContext *pango_context, cairo_t *cr) { GdkRectangle *monitor_area = &osd_window->priv->monitor_area; PangoRectangle logical_rect; PangoLayout *layout; char *markup; double x; double y; if (osd_window->priv->message == NULL) return; layout = pango_layout_new (pango_context); pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); markup = g_strdup_printf ("%s", osd_window->priv->message); pango_layout_set_markup (layout, markup, -1); g_free (markup); pango_layout_get_pixel_extents (layout, NULL, &logical_rect); x = (monitor_area->width - logical_rect.width) / 2 + logical_rect.x; y = (monitor_area->height - logical_rect.height) / 2 + logical_rect.y; gtk_render_layout (style_context, cr, x, y, layout); g_object_unref (layout); } static void gsd_wacom_osd_window_draw_labels (GsdWacomOSDWindow *osd_window, GtkStyleContext *style_context, PangoContext *pango_context, cairo_t *cr) { GList *l; for (l = osd_window->priv->buttons; l != NULL; l = l->next) { GsdWacomOSDButton *osd_button = l->data; if (osd_button->priv->visible == FALSE) continue; gsd_wacom_osd_button_draw_label (osd_button, style_context, pango_context, cr, osd_window->priv->rotation); } } static void gsd_wacom_osd_window_place_buttons (GsdWacomOSDWindow *osd_window, cairo_t *cr) { GList *l; g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window)); for (l = osd_window->priv->buttons; l != NULL; l = l->next) { GsdWacomOSDButton *osd_button = l->data; double label_x, label_y; gchar *sub; sub = gsd_wacom_osd_button_get_label_class (osd_button); if (!get_sub_location (osd_window->priv->handle, sub, cr, &label_x, &label_y)) { g_warning ("Failed to retrieve %s position", sub); g_free (sub); continue; } g_free (sub); gsd_wacom_osd_button_set_location (osd_button, label_x, label_y); } } /* Note: this function does modify the given cairo context */ static void gsd_wacom_osd_window_adjust_cairo (GsdWacomOSDWindow *osd_window, cairo_t *cr) { double scale, twidth, theight; GdkRectangle *tablet_area = &osd_window->priv->tablet_area; GdkRectangle *screen_area = &osd_window->priv->screen_area; GdkRectangle *monitor_area = &osd_window->priv->monitor_area; /* Rotate */ cairo_rotate (cr, get_rotation_in_radian (osd_window->priv->rotation)); /* Scale to fit in window */ scale = MIN ((double) monitor_area->width / tablet_area->width, (double) monitor_area->height / tablet_area->height); cairo_scale (cr, scale, scale); /* Center the result in window */ twidth = (double) tablet_area->width; theight = (double) tablet_area->height; cairo_user_to_device_distance (cr, &twidth, &theight); twidth = ((double) monitor_area->width - twidth) / 2.0; theight = ((double) monitor_area->height - theight) / 2.0; cairo_device_to_user_distance (cr, &twidth, &theight); twidth = twidth + (double) (monitor_area->x - screen_area->x); theight = theight + (double) (monitor_area->y - screen_area->y); cairo_translate (cr, twidth, theight); } static gboolean gsd_wacom_osd_window_draw (GtkWidget *widget, cairo_t *cr) { GsdWacomOSDWindow *osd_window = GSD_WACOM_OSD_WINDOW (widget); g_return_val_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window), FALSE); g_return_val_if_fail (GSD_IS_WACOM_DEVICE (osd_window->priv->pad), FALSE); if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget))) { GtkStyleContext *style_context; PangoContext *pango_context; style_context = gtk_widget_get_style_context (widget); pango_context = gtk_widget_get_pango_context (widget); cairo_set_source_rgba (cr, 0, 0, 0, BACK_OPACITY); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); /* Save original matrix */ cairo_save (cr); /* Apply new cairo transformation matrix */ gsd_wacom_osd_window_adjust_cairo (osd_window, cr); /* And render the tablet layout */ gsd_wacom_osd_window_update (osd_window); rsvg_handle_render_cairo (osd_window->priv->handle, cr); gsd_wacom_osd_window_place_buttons (osd_window, cr); /* Reset to original matrix */ cairo_restore (cr); /* Draw button labels and message */ gsd_wacom_osd_window_draw_labels (osd_window, style_context, pango_context, cr); gsd_wacom_osd_window_draw_message (osd_window, style_context, pango_context, cr); } return FALSE; } static gchar * get_escaped_accel_shortcut (const gchar *accel) { guint keyval; GdkModifierType mask; gchar *str, *label; if (accel == NULL || accel[0] == '\0') return g_strdup (C_("Action type", "None")); gtk_accelerator_parse (accel, &keyval, &mask); str = gtk_accelerator_get_label (keyval, mask); label = g_markup_printf_escaped (C_("Action type", "Send Keystroke %s"), str); g_free (str); return label; } static gchar * get_tablet_button_label_normal (GsdWacomDevice *device, GsdWacomTabletButton *button) { GsdWacomActionType type; gchar *name, *str; type = g_settings_get_enum (button->settings, ACTION_TYPE_KEY); if (type == GSD_WACOM_ACTION_TYPE_NONE) return g_strdup (C_("Action type", "None")); if (type == GSD_WACOM_ACTION_TYPE_HELP) return g_strdup (C_("Action type", "Show On-Screen Help")); if (type == GSD_WACOM_ACTION_TYPE_SWITCH_MONITOR) return g_strdup (C_("Action type", "Switch Monitor")); str = g_settings_get_string (button->settings, CUSTOM_ACTION_KEY); if (str == NULL || *str == '\0') { g_free (str); return g_strdup (C_("Action type", "None")); } name = get_escaped_accel_shortcut (str); g_free (str); return name; } static gchar * get_tablet_button_label_touch (GsdWacomDevice *device, GsdWacomTabletButton *button, GtkDirectionType dir) { char **strv, *name, *str; strv = g_settings_get_strv (button->settings, CUSTOM_ELEVATOR_ACTION_KEY); name = NULL; if (strv) { if (g_strv_length (strv) >= 1 && dir == GTK_DIR_UP) name = g_strdup (strv[0]); else if (g_strv_length (strv) >= 2 && dir == GTK_DIR_DOWN) name = g_strdup (strv[1]); g_strfreev (strv); } str = get_escaped_accel_shortcut (name); g_free (name); name = str; /* With multiple modes, also show the current mode for that action */ if (gsd_wacom_device_get_num_modes (device, button->group_id) > 1) { name = g_strdup_printf (_("Mode %d: %s"), button->idx + 1, str); g_free (str); } return name; } static gchar * get_tablet_button_label (GsdWacomDevice *device, GsdWacomTabletButton *button, GtkDirectionType dir) { g_return_val_if_fail (button, NULL); if (!button->settings) goto out; switch (button->type) { case WACOM_TABLET_BUTTON_TYPE_NORMAL: return get_tablet_button_label_normal (device, button); break; case WACOM_TABLET_BUTTON_TYPE_RING: case WACOM_TABLET_BUTTON_TYPE_STRIP: return get_tablet_button_label_touch (device, button, dir); break; case WACOM_TABLET_BUTTON_TYPE_HARDCODED: default: break; } out: return g_strdup (button->name); } static gchar* get_tablet_button_class_name (GsdWacomTabletButton *tablet_button, GtkDirectionType dir) { gchar *id; gchar c; id = tablet_button->id; switch (tablet_button->type) { case WACOM_TABLET_BUTTON_TYPE_RING: if (id[0] == 'l') /* left-ring */ return g_strdup_printf ("Ring%s", (dir == GTK_DIR_UP ? "CCW" : "CW")); if (id[0] == 'r') /* right-ring */ return g_strdup_printf ("Ring2%s", (dir == GTK_DIR_UP ? "CCW" : "CW")); g_warning ("Unknown ring type '%s'", id); return NULL; break; case WACOM_TABLET_BUTTON_TYPE_STRIP: if (id[0] == 'l') /* left-strip */ return g_strdup_printf ("Strip%s", (dir == GTK_DIR_UP ? "Up" : "Down")); if (id[0] == 'r') /* right-strip */ return g_strdup_printf ("Strip2%s", (dir == GTK_DIR_UP ? "Up" : "Down")); g_warning ("Unknown strip type '%s'", id); return NULL; break; case WACOM_TABLET_BUTTON_TYPE_NORMAL: case WACOM_TABLET_BUTTON_TYPE_HARDCODED: c = get_last_char (id); return g_strdup_printf ("%c", g_ascii_toupper (c)); break; default: g_warning ("Unknown button type '%s'", id); break; } return NULL; } static gchar* get_tablet_button_id_name (GsdWacomTabletButton *tablet_button, GtkDirectionType dir) { gchar *id; gchar c; id = tablet_button->id; switch (tablet_button->type) { case WACOM_TABLET_BUTTON_TYPE_RING: return g_strconcat (id, (dir == GTK_DIR_UP ? "-ccw" : "-cw"), NULL); break; case WACOM_TABLET_BUTTON_TYPE_STRIP: return g_strconcat (id, (dir == GTK_DIR_UP ? "-up" : "-down"), NULL); break; case WACOM_TABLET_BUTTON_TYPE_NORMAL: case WACOM_TABLET_BUTTON_TYPE_HARDCODED: c = get_last_char (id); return g_strdup_printf ("%c", g_ascii_toupper (c)); break; default: g_warning ("Unknown button type '%s'", id); break; } return NULL; } static gint get_elevator_current_mode (GsdWacomOSDWindow *osd_window, GsdWacomTabletButton *elevator_button) { GList *list, *l; gint mode; mode = 1; /* Search in the list of buttons the corresponding * mode-switch button and get the current mode */ list = gsd_wacom_device_get_buttons (osd_window->priv->pad); for (l = list; l != NULL; l = l->next) { GsdWacomTabletButton *tablet_button = l->data; if (tablet_button->type != WACOM_TABLET_BUTTON_TYPE_HARDCODED) continue; if (elevator_button->group_id != tablet_button->group_id) continue; mode = gsd_wacom_device_get_current_mode (osd_window->priv->pad, tablet_button->group_id); break; } g_list_free (list); return mode; } static GsdWacomOSDButton * gsd_wacom_osd_window_add_button_with_dir (GsdWacomOSDWindow *osd_window, GsdWacomTabletButton *tablet_button, guint timeout, GtkDirectionType dir) { GsdWacomOSDButton *osd_button; gchar *str; str = get_tablet_button_id_name (tablet_button, dir); osd_button = gsd_wacom_osd_button_new (GTK_WIDGET (osd_window), str); g_free (str); str = get_tablet_button_class_name (tablet_button, dir); gsd_wacom_osd_button_set_class (osd_button, str); g_free (str); str = get_tablet_button_label (osd_window->priv->pad, tablet_button, dir); gsd_wacom_osd_button_set_label (osd_button, str); g_free (str); gsd_wacom_osd_button_set_button_type (osd_button, tablet_button->type); gsd_wacom_osd_button_set_position (osd_button, tablet_button->pos); gsd_wacom_osd_button_set_auto_off (osd_button, timeout); osd_window->priv->buttons = g_list_append (osd_window->priv->buttons, osd_button); return osd_button; } static void gsd_wacom_osd_window_add_tablet_button (GsdWacomOSDWindow *osd_window, GsdWacomTabletButton *tablet_button) { GsdWacomOSDButton *osd_button; gint mode; switch (tablet_button->type) { case WACOM_TABLET_BUTTON_TYPE_NORMAL: case WACOM_TABLET_BUTTON_TYPE_HARDCODED: osd_button = gsd_wacom_osd_window_add_button_with_dir (osd_window, tablet_button, 0, 0); gsd_wacom_osd_button_set_visible (osd_button, TRUE); break; case WACOM_TABLET_BUTTON_TYPE_RING: case WACOM_TABLET_BUTTON_TYPE_STRIP: mode = get_elevator_current_mode (osd_window, tablet_button) - 1; /* Add 2 buttons per elevator, one "Up"... */ osd_button = gsd_wacom_osd_window_add_button_with_dir (osd_window, tablet_button, ELEVATOR_TIMEOUT, GTK_DIR_UP); gsd_wacom_osd_button_set_visible (osd_button, tablet_button->idx == mode); /* ... and one "Down" */ osd_button = gsd_wacom_osd_window_add_button_with_dir (osd_window, tablet_button, ELEVATOR_TIMEOUT, GTK_DIR_DOWN); gsd_wacom_osd_button_set_visible (osd_button, tablet_button->idx == mode); break; default: g_warning ("Unknown button type"); break; } } /* * Returns the rotation to apply a device to get a representation relative to * the current rotation of the output. * (This function is _not_ the same as in gsd-wacom-manager.c) */ static GsdWacomRotation display_relative_rotation (GsdWacomRotation device_rotation, GsdWacomRotation output_rotation) { GsdWacomRotation rotations[] = { GSD_WACOM_ROTATION_HALF, GSD_WACOM_ROTATION_CW, GSD_WACOM_ROTATION_NONE, GSD_WACOM_ROTATION_CCW }; guint i; if (device_rotation == output_rotation) return GSD_WACOM_ROTATION_NONE; if (output_rotation == GSD_WACOM_ROTATION_NONE) return device_rotation; for (i = 0; i < G_N_ELEMENTS (rotations); i++) { if (device_rotation == rotations[i]) break; } if (output_rotation == GSD_WACOM_ROTATION_HALF) return rotations[(i + G_N_ELEMENTS (rotations) - 2) % G_N_ELEMENTS (rotations)]; if (output_rotation == GSD_WACOM_ROTATION_CW) return rotations[(i + 1) % G_N_ELEMENTS (rotations)]; if (output_rotation == GSD_WACOM_ROTATION_CCW) return rotations[(i + G_N_ELEMENTS (rotations) - 1) % G_N_ELEMENTS (rotations)]; /* fallback */ return GSD_WACOM_ROTATION_NONE; } static void gsd_wacom_osd_window_mapped (GtkWidget *widget, gpointer data) { GsdWacomOSDWindow *osd_window = GSD_WACOM_OSD_WINDOW (widget); g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window)); /* Position the window at its expected postion before moving * to fullscreen, so the window will be on the right monitor. */ gtk_window_move (GTK_WINDOW (osd_window), osd_window->priv->screen_area.x, osd_window->priv->screen_area.y); gtk_window_fullscreen (GTK_WINDOW (osd_window)); gtk_window_set_keep_above (GTK_WINDOW (osd_window), TRUE); } static void gsd_wacom_osd_window_realized (GtkWidget *widget, gpointer data) { GsdWacomOSDWindow *osd_window = GSD_WACOM_OSD_WINDOW (widget); GdkWindow *gdk_window; GdkRGBA transparent; GdkScreen *screen; GdkCursor *cursor; gint monitor; gboolean status; g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window)); g_return_if_fail (GSD_IS_WACOM_DEVICE (osd_window->priv->pad)); if (!gtk_widget_get_realized (widget)) return; screen = gtk_widget_get_screen (widget); gdk_window = gtk_widget_get_window (widget); transparent.red = transparent.green = transparent.blue = 0.0; transparent.alpha = BACK_OPACITY; gdk_window_set_background_rgba (gdk_window, &transparent); cursor = gdk_cursor_new (GDK_BLANK_CURSOR); gdk_window_set_cursor (gdk_window, cursor); g_object_unref (cursor); /* Determine the monitor for that device and set appropriate fullscreen mode*/ monitor = gsd_wacom_device_get_display_monitor (osd_window->priv->pad); if (monitor == GSD_WACOM_SET_ALL_MONITORS) { /* Covers the entire screen */ osd_window->priv->screen_area.x = 0; osd_window->priv->screen_area.y = 0; osd_window->priv->screen_area.width = gdk_screen_get_width (screen); osd_window->priv->screen_area.height = gdk_screen_get_height (screen); gdk_screen_get_monitor_geometry (screen, 0, &osd_window->priv->monitor_area); gdk_window_set_fullscreen_mode (gdk_window, GDK_FULLSCREEN_ON_ALL_MONITORS); } else { gdk_screen_get_monitor_geometry (screen, monitor, &osd_window->priv->screen_area); osd_window->priv->monitor_area = osd_window->priv->screen_area; gdk_window_set_fullscreen_mode (gdk_window, GDK_FULLSCREEN_ON_CURRENT_MONITOR); } gtk_window_set_default_size (GTK_WINDOW (osd_window), osd_window->priv->screen_area.width, osd_window->priv->screen_area.height); status = get_image_size (gsd_wacom_device_get_layout_path (osd_window->priv->pad), &osd_window->priv->tablet_area.width, &osd_window->priv->tablet_area.height); if (status == FALSE) osd_window->priv->tablet_area = osd_window->priv->monitor_area; } static void gsd_wacom_osd_window_set_device (GsdWacomOSDWindow *osd_window, GsdWacomDevice *device) { GsdWacomRotation device_rotation; GsdWacomRotation output_rotation; GSettings *settings; GList *list, *l; g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window)); g_return_if_fail (GSD_IS_WACOM_DEVICE (device)); /* If we had a layout previously handled, get rid of it */ if (osd_window->priv->handle) g_object_unref (osd_window->priv->handle); osd_window->priv->handle = NULL; /* Bind the device with the OSD window */ if (osd_window->priv->pad) g_object_weak_unref (G_OBJECT(osd_window->priv->pad), (GWeakNotify) gtk_widget_destroy, osd_window); osd_window->priv->pad = device; g_object_weak_ref (G_OBJECT(osd_window->priv->pad), (GWeakNotify) gtk_widget_destroy, osd_window); /* Capture current rotation, we do not update that later, OSD window is meant to be short lived */ settings = gsd_wacom_device_get_settings (osd_window->priv->pad); device_rotation = g_settings_get_enum (settings, ROTATION_KEY); output_rotation = gsd_wacom_device_get_display_rotation (osd_window->priv->pad); osd_window->priv->rotation = display_relative_rotation (device_rotation, output_rotation); /* Create the buttons */ list = gsd_wacom_device_get_buttons (device); for (l = list; l != NULL; l = l->next) { GsdWacomTabletButton *tablet_button = l->data; gsd_wacom_osd_window_add_tablet_button (osd_window, tablet_button); } g_list_free (list); } GsdWacomDevice * gsd_wacom_osd_window_get_device (GsdWacomOSDWindow *osd_window) { g_return_val_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window), NULL); return osd_window->priv->pad; } void gsd_wacom_osd_window_set_message (GsdWacomOSDWindow *osd_window, const gchar *str) { g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window)); g_free (osd_window->priv->message); osd_window->priv->message = g_strdup (str); } const char * gsd_wacom_osd_window_get_message (GsdWacomOSDWindow *osd_window) { g_return_val_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window), NULL); return osd_window->priv->message; } static void gsd_wacom_osd_window_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GsdWacomOSDWindow *osd_window; osd_window = GSD_WACOM_OSD_WINDOW (object); switch (prop_id) { case PROP_OSD_WINDOW_MESSAGE: gsd_wacom_osd_window_set_message (osd_window, g_value_get_string (value)); break; case PROP_OSD_WINDOW_GSD_WACOM_DEVICE: gsd_wacom_osd_window_set_device (osd_window, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gsd_wacom_osd_window_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GsdWacomOSDWindow *osd_window; osd_window = GSD_WACOM_OSD_WINDOW (object); switch (prop_id) { case PROP_OSD_WINDOW_MESSAGE: g_value_set_string (value, osd_window->priv->message); break; case PROP_OSD_WINDOW_GSD_WACOM_DEVICE: g_value_set_object (value, (GObject*) osd_window->priv->pad); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } void gsd_wacom_osd_window_set_active (GsdWacomOSDWindow *osd_window, GsdWacomTabletButton *button, GtkDirectionType dir, gboolean active) { GList *l; gchar *id; g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (osd_window)); g_return_if_fail (button != NULL); id = get_tablet_button_id_name (button, dir); for (l = osd_window->priv->buttons; l != NULL; l = l->next) { GsdWacomOSDButton *osd_button = l->data; if (MATCH_ID (osd_button, id)) gsd_wacom_osd_button_set_active (osd_button, active); } g_free (id); } void gsd_wacom_osd_window_set_mode (GsdWacomOSDWindow *osd_window, gint group_id, gint mode) { GList *list, *l; list = gsd_wacom_device_get_buttons (osd_window->priv->pad); for (l = list; l != NULL; l = l->next) { GsdWacomTabletButton *tablet_button = l->data; GList *l2; gchar *id_up, *id_down; if (tablet_button->type != WACOM_TABLET_BUTTON_TYPE_STRIP && tablet_button->type != WACOM_TABLET_BUTTON_TYPE_RING) continue; if (tablet_button->group_id != group_id) continue; id_up = get_tablet_button_id_name (tablet_button, GTK_DIR_UP); id_down = get_tablet_button_id_name (tablet_button, GTK_DIR_DOWN); for (l2 = osd_window->priv->buttons; l2 != NULL; l2 = l2->next) { GsdWacomOSDButton *osd_button = l2->data; gboolean visible = (tablet_button->idx == mode - 1); if (MATCH_ID (osd_button, id_up) || MATCH_ID (osd_button, id_down)) gsd_wacom_osd_button_set_visible (osd_button, visible); } g_free (id_up); g_free (id_down); } g_list_free (list); } GtkWidget * gsd_wacom_osd_window_new (GsdWacomDevice *pad, const gchar *message) { GsdWacomOSDWindow *osd_window; GdkScreen *screen; GdkVisual *visual; osd_window = GSD_WACOM_OSD_WINDOW (g_object_new (GSD_TYPE_WACOM_OSD_WINDOW, "type", GTK_WINDOW_TOPLEVEL, "skip-pager-hint", TRUE, "skip-taskbar-hint", TRUE, "focus-on-map", TRUE, "decorated", FALSE, "deletable", FALSE, "accept-focus", TRUE, "wacom-device", pad, "message", message, NULL)); /* Must set the visual before realizing the window */ gtk_widget_set_app_paintable (GTK_WIDGET (osd_window), TRUE); screen = gdk_screen_get_default (); visual = gdk_screen_get_rgba_visual (screen); if (visual == NULL) visual = gdk_screen_get_system_visual (screen); gtk_widget_set_visual (GTK_WIDGET (osd_window), visual); g_signal_connect (GTK_WIDGET (osd_window), "realize", G_CALLBACK (gsd_wacom_osd_window_realized), NULL); g_signal_connect (GTK_WIDGET (osd_window), "map", G_CALLBACK (gsd_wacom_osd_window_mapped), NULL); return GTK_WIDGET (osd_window); } static void gsd_wacom_osd_window_class_init (GsdWacomOSDWindowClass *klass) { GObjectClass *gobject_class; GtkWidgetClass *widget_class; gobject_class = G_OBJECT_CLASS (klass); widget_class = GTK_WIDGET_CLASS (klass); gobject_class->set_property = gsd_wacom_osd_window_set_property; gobject_class->get_property = gsd_wacom_osd_window_get_property; gobject_class->finalize = gsd_wacom_osd_window_finalize; widget_class->draw = gsd_wacom_osd_window_draw; g_object_class_install_property (gobject_class, PROP_OSD_WINDOW_MESSAGE, g_param_spec_string ("message", "Window message", "The message shown in the OSD window", "", G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_OSD_WINDOW_GSD_WACOM_DEVICE, g_param_spec_object ("wacom-device", "Wacom device", "The Wacom device represented by the OSD window", GSD_TYPE_WACOM_DEVICE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); g_type_class_add_private (klass, sizeof (GsdWacomOSDWindowPrivate)); } static void gsd_wacom_osd_window_init (GsdWacomOSDWindow *osd_window) { osd_window->priv = GSD_WACOM_OSD_WINDOW_GET_PRIVATE (osd_window); } static void gsd_wacom_osd_window_finalize (GObject *object) { GsdWacomOSDWindow *osd_window; GsdWacomOSDWindowPrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (GSD_IS_WACOM_OSD_WINDOW (object)); osd_window = GSD_WACOM_OSD_WINDOW (object); g_return_if_fail (osd_window->priv != NULL); priv = osd_window->priv; g_clear_object (&priv->handle); g_clear_pointer (&priv->message, g_free); if (priv->buttons) { g_list_free_full (priv->buttons, g_object_unref); priv->buttons = NULL; } G_OBJECT_CLASS (gsd_wacom_osd_window_parent_class)->finalize (object); } unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/gsd-wacom-osd-window.h0000644000015300001610000000636012567031542027410 0ustar pbuserpbgroup00000000000000/* * 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 __GSD_WACOM_OSD_WINDOW_H #define __GSD_WACOM_OSD_WINDOW_H #include #include #include "gsd-wacom-device.h" #define GSD_TYPE_WACOM_OSD_WINDOW (gsd_wacom_osd_window_get_type ()) #define GSD_WACOM_OSD_WINDOW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_WACOM_OSD_WINDOW, GsdWacomOSDWindow)) #define GSD_WACOM_OSD_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_WACOM_OSD_WINDOW, GsdWacomOSDWindowClass)) #define GSD_IS_WACOM_OSD_WINDOW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_WACOM_OSD_WINDOW)) #define GSD_IS_WACOM_OSD_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_WACOM_OSD_WINDOW)) #define GSD_WACOM_OSD_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_WACOM_OSD_WINDOW, GsdWacomOSDWindowClass)) typedef struct GsdWacomOSDWindowPrivate GsdWacomOSDWindowPrivate; typedef struct { GtkWindow window; GsdWacomOSDWindowPrivate *priv; } GsdWacomOSDWindow; typedef struct { GtkWindowClass parent_class; } GsdWacomOSDWindowClass; GType gsd_wacom_osd_window_get_type (void) G_GNUC_CONST; GsdWacomDevice * gsd_wacom_osd_window_get_device (GsdWacomOSDWindow *osd_window); void gsd_wacom_osd_window_set_message (GsdWacomOSDWindow *osd_window, const gchar *str); const char * gsd_wacom_osd_window_get_message (GsdWacomOSDWindow *osd_window); void gsd_wacom_osd_window_set_active (GsdWacomOSDWindow *osd_window, GsdWacomTabletButton *button, GtkDirectionType dir, gboolean active); void gsd_wacom_osd_window_set_mode (GsdWacomOSDWindow *osd_window, gint group_id, gint mode); GtkWidget * gsd_wacom_osd_window_new (GsdWacomDevice *pad, const gchar *message); #endif /* __GSD_WACOM_OSD_WINDOW_H */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/gsd-wacom-manager.c0000644000015300001610000013275012567031542026726 0ustar pbuserpbgroup00000000000000/* -*- 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 "gsd-enums.h" #include "gsd-input-helper.h" #include "gsd-keygrab.h" #include "gnome-settings-profile.h" #include "gsd-wacom-manager.h" #include "gsd-wacom-device.h" #include "gsd-wacom-osd-window.h" #define GSD_WACOM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_WACOM_MANAGER, GsdWacomManagerPrivate)) #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 GsdWacomManagerPrivate { guint start_idle_id; GdkDeviceManager *device_manager; guint device_added_id; guint device_removed_id; GHashTable *devices; /* key = GdkDevice, value = GsdWacomDevice */ GList *rr_screens; /* button capture */ GSList *screens; int opcode; /* Help OSD window */ GtkWidget *osd_window; }; static void gsd_wacom_manager_class_init (GsdWacomManagerClass *klass); static void gsd_wacom_manager_init (GsdWacomManager *wacom_manager); static void gsd_wacom_manager_finalize (GObject *object); G_DEFINE_TYPE (GsdWacomManager, gsd_wacom_manager, G_TYPE_OBJECT) static gpointer manager_object = NULL; static GObject * gsd_wacom_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GsdWacomManager *wacom_manager; wacom_manager = GSD_WACOM_MANAGER (G_OBJECT_CLASS (gsd_wacom_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (wacom_manager); } static void gsd_wacom_manager_dispose (GObject *object) { G_OBJECT_CLASS (gsd_wacom_manager_parent_class)->dispose (object); } static void gsd_wacom_manager_class_init (GsdWacomManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = gsd_wacom_manager_constructor; object_class->dispose = gsd_wacom_manager_dispose; object_class->finalize = gsd_wacom_manager_finalize; g_type_class_add_private (klass, sizeof (GsdWacomManagerPrivate)); } static int get_device_id (GsdWacomDevice *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 (GsdWacomDevice *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 (GsdWacomDevice *device, PropertyHelper *property) { XDevice *xdev; xdev = open_device (device); device_set_property (xdev, gsd_wacom_device_get_tool_name (device), property); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev); } static void set_rotation (GsdWacomDevice *device, GsdWacomRotation 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 (GsdWacomDevice *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 (GsdWacomDevice *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 GsdWacomRotation get_relative_rotation (GsdWacomRotation device_rotation, GsdWacomRotation output_rotation) { GsdWacomRotation rotations[] = { GSD_WACOM_ROTATION_HALF, GSD_WACOM_ROTATION_CW, GSD_WACOM_ROTATION_NONE, GSD_WACOM_ROTATION_CCW }; guint i; if (device_rotation == output_rotation) return GSD_WACOM_ROTATION_NONE; if (output_rotation == GSD_WACOM_ROTATION_NONE) return device_rotation; for (i = 0; i < G_N_ELEMENTS (rotations); i++){ if (device_rotation == rotations[i]) break; } if (output_rotation == GSD_WACOM_ROTATION_HALF) return rotations[(i + G_N_ELEMENTS (rotations) - 2) % G_N_ELEMENTS (rotations)]; if (output_rotation == GSD_WACOM_ROTATION_CW) return rotations[(i + G_N_ELEMENTS (rotations) - 1) % G_N_ELEMENTS (rotations)]; if (output_rotation == GSD_WACOM_ROTATION_CCW) return rotations[(i + 1) % G_N_ELEMENTS (rotations)]; /* fallback */ return GSD_WACOM_ROTATION_NONE; } static void set_display (GsdWacomDevice *device, GVariant *value) { GsdWacomRotation device_rotation; GsdWacomRotation 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), }; gsd_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 = gsd_wacom_device_get_settings (device); device_rotation = g_settings_get_enum (settings, KEY_ROTATION); output_rotation = gsd_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 (GsdWacomDevice *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", gsd_wacom_device_get_tool_name (device)); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev); } static void compute_aspect_area (gint monitor, gint *area, GsdWacomRotation 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 == GSD_WACOM_ROTATION_CW || rotation == GSD_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 GSD_WACOM_ROTATION_NONE: area[2] = area[0] + width; area[3] = area[1] + height; break; case GSD_WACOM_ROTATION_CW: area[0] = area[2] - width; area[3] = area[1] + height; break; case GSD_WACOM_ROTATION_HALF: area[0] = area[2] - width; area[1] = area[3] - height; break; case GSD_WACOM_ROTATION_CCW: area[2] = area[0] + width; area[1] = area[3] - height; break; default: break; } } static void set_keep_aspect (GsdWacomDevice *device, gboolean keep_aspect) { GVariant *values[4], *variant; guint i; gint *area; gint monitor = GSD_WACOM_SET_ALL_MONITORS; GsdWacomRotation rotation; GSettings *settings; settings = gsd_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 = gsd_wacom_device_get_area (device); if (!area) { g_warning("Device area not available.\n"); return; } /* Get corresponding monitor size */ monitor = gsd_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 (GsdWacomDevice *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\"", gsd_wacom_device_get_tool_name (device)); g_free (map); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev); } static void set_touch (GsdWacomDevice *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 (GsdWacomDevice *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 (GsdWacomDevice *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 (GsdWacomDevice *device) { GSettings *stylus_settings; GsdWacomStylus *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'", gsd_wacom_stylus_get_name (stylus), gsd_wacom_device_get_name (device)); stylus_settings = gsd_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 (GsdWacomDevice *device, GsdWacomTabletButton *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 = gsd_wacom_device_get_path (device); status_led = button->status_led; if (status_led == GSD_WACOM_NO_LED) { g_debug ("Ignoring unhandled group ID %d for device %s", button->group_id, gsd_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 "/usd-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 (GsdWacomDevice *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)", gsd_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 (); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdev); /* Reset all the LEDs */ buttons = gsd_wacom_device_get_buttons (device); for (l = buttons; l != NULL; l = l->next) { GsdWacomTabletButton *button = l->data; if (button->type == WACOM_TABLET_BUTTON_TYPE_HARDCODED && button->status_led != GSD_WACOM_NO_LED) { set_led (device, button, 1); } } g_list_free (buttons); } static void set_wacom_settings (GsdWacomManager *manager, GsdWacomDevice *device) { GsdWacomDeviceType type; GSettings *settings; g_debug ("Applying settings for device '%s' (type: %s)", gsd_wacom_device_get_tool_name (device), gsd_wacom_device_type_to_string (gsd_wacom_device_get_device_type (device))); settings = gsd_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 = gsd_wacom_device_get_device_type (device); if (type == WACOM_TYPE_TOUCH && gsd_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 (gsd_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, GsdWacomDevice *device) { GsdWacomDeviceType type; type = gsd_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 && !gsd_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, GsdWacomStylus *stylus) { GsdWacomDevice *device; GsdWacomStylus *last_stylus; device = gsd_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 ? gsd_wacom_stylus_get_name (last_stylus) : "NONE", gsd_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 (GsdWacomDevice *device, GParamSpec *pspec, GsdWacomManager *manager) { g_debug ("Stylus for device '%s' changed, applying settings", gsd_wacom_device_get_name (device)); apply_stylus_settings (device); } static void osd_window_destroy (GsdWacomManager *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, GsdWacomManager *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, GsdWacomManager *manager) { /* If the OSD window loses focus, hide it */ osd_window_destroy (manager); return FALSE; } static gboolean osd_window_toggle_visibility (GsdWacomManager *manager, GsdWacomDevice *device) { GtkWidget *widget; const gchar *layout_path; if (manager->priv->osd_window) { osd_window_destroy (manager); return FALSE; } layout_path = gsd_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", gsd_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 = gsd_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 (GsdWacomManager *manager, GsdWacomTabletButton *button, GtkDirectionType dir, XIEvent *xiev) { if (manager->priv->osd_window == NULL) return FALSE; gsd_wacom_osd_window_set_active (GSD_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, GsdWacomManager *manager) { GsdWacomDevice *device; GSettings *settings; device = gsd_wacom_device_new (gdk_device); if (gsd_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", gsd_wacom_device_get_tool_name (device), gsd_wacom_device_type_to_string (gsd_wacom_device_get_device_type (device))); g_hash_table_insert (manager->priv->devices, (gpointer) gdk_device, device); settings = gsd_wacom_device_get_settings (device); g_signal_connect (G_OBJECT (settings), "changed", G_CALLBACK (wacom_settings_changed), device); if (gsd_wacom_device_get_device_type (device) == WACOM_TYPE_STYLUS || gsd_wacom_device_get_device_type (device) == WACOM_TYPE_ERASER) { GList *styli, *l; styli = gsd_wacom_device_list_styli (device); for (l = styli ; l ; l = l->next) { settings = gsd_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, GsdWacomManager *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 GsdWacomDevice * device_id_to_device (GsdWacomManager *manager, int deviceid) { GList *devices, *l; GsdWacomDevice *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 (GsdWacomTabletButton *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 (GsdWacomDevice *device) { gint current_monitor, n_monitors; /* We dont; do that for screen tablets, sorry... */ if (gsd_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 = gsd_wacom_device_get_display_monitor (device); /* Select next monitor */ current_monitor++; if (current_monitor >= n_monitors) current_monitor = GSD_WACOM_SET_ALL_MONITORS; gsd_wacom_device_set_display (device, current_monitor); } static const char* get_direction_name (GsdWacomTabletButtonType 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, GsdWacomManager *manager) { XIEvent *xiev; XIDeviceEvent *xev; XGenericEventCookie *cookie; guint deviceid; GsdWacomDevice *device; int button; GsdWacomTabletButton *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 (gsd_wacom_device_get_device_type (device) != WACOM_TYPE_PAD) return GDK_FILTER_CONTINUE; if ((manager->priv->osd_window != NULL) && (device != gsd_wacom_osd_window_get_device (GSD_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 = gsd_wacom_device_get_button (device, button, &dir); if (wbutton == NULL) { g_warning ("Could not find matching button for '%d' on '%s'", button, gsd_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, gsd_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 = gsd_wacom_device_set_next_mode (device, wbutton); if (manager->priv->osd_window != NULL) { gsd_wacom_osd_window_set_mode (GSD_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) == GSD_WACOM_ACTION_TYPE_NONE) return GDK_FILTER_REMOVE; /* Show OSD window when requested */ if (g_settings_get_enum (wbutton->settings, KEY_ACTION_TYPE) == GSD_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) == GSD_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 (GsdWacomManager *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 gsd_wacom_manager_init (GsdWacomManager *manager) { manager->priv = GSD_WACOM_MANAGER_GET_PRIVATE (manager); } static gboolean gsd_wacom_manager_idle_cb (GsdWacomManager *manager) { GList *devices, *l; GSList *ls; gnome_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); } gnome_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, GsdWacomManager *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) { GsdWacomDevice *device = l->data; GsdWacomDeviceType type; GSettings *settings; type = gsd_wacom_device_get_device_type (device); if (type == WACOM_TYPE_CURSOR || type == WACOM_TYPE_PAD) continue; settings = gsd_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 (gsd_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 (GsdWacomManager *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 gsd_wacom_manager_start (GsdWacomManager *manager, GError **error) { gnome_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) gsd_wacom_manager_idle_cb, manager); gnome_settings_profile_end (NULL); return TRUE; } void gsd_wacom_manager_stop (GsdWacomManager *manager) { GsdWacomManagerPrivate *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) { GsdWacomDeviceType type; type = gsd_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 gsd_wacom_manager_finalize (GObject *object) { GsdWacomManager *wacom_manager; g_return_if_fail (object != NULL); g_return_if_fail (GSD_IS_WACOM_MANAGER (object)); wacom_manager = GSD_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); G_OBJECT_CLASS (gsd_wacom_manager_parent_class)->finalize (object); } GsdWacomManager * gsd_wacom_manager_new (void) { if (manager_object != NULL) { g_object_ref (manager_object); } else { manager_object = g_object_new (GSD_TYPE_WACOM_MANAGER, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); } return GSD_WACOM_MANAGER (manager_object); } unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/gsd-wacom-device.c0000644000015300001610000017114112567031542026550 0ustar pbuserpbgroup00000000000000/* * 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 "gsd-input-helper.h" #include "gsd-enums.h" #include "gsd-wacom-device.h" #define GSD_WACOM_STYLUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_WACOM_STYLUS, GsdWacomStylusPrivate)) #define WACOM_TABLET_SCHEMA "org.gnome.settings-daemon.peripherals.wacom" #define WACOM_DEVICE_CONFIG_BASE "/org/gnome/settings-daemon/peripherals/wacom/%s-%s/" #define WACOM_STYLUS_SCHEMA "org.gnome.settings-daemon.peripherals.wacom.stylus" #define WACOM_ERASER_SCHEMA "org.gnome.settings-daemon.peripherals.wacom.eraser" #define WACOM_BUTTON_SCHEMA "org.gnome.settings-daemon.peripherals.wacom.tablet-button" static struct { GnomeRRRotation rotation; GsdWacomRotation rotation_wacom; const gchar *rotation_string; } rotation_table[] = { { GNOME_RR_ROTATION_0, GSD_WACOM_ROTATION_NONE, "none" }, { GNOME_RR_ROTATION_90, GSD_WACOM_ROTATION_CCW, "ccw" }, { GNOME_RR_ROTATION_180, GSD_WACOM_ROTATION_HALF, "half" }, { GNOME_RR_ROTATION_270, GSD_WACOM_ROTATION_CW, "cw" } }; static WacomDeviceDatabase *db = NULL; struct GsdWacomStylusPrivate { GsdWacomDevice *device; int id; WacomStylusType type; char *name; const char *icon_name; GSettings *settings; gboolean has_eraser; int num_buttons; }; static void gsd_wacom_stylus_class_init (GsdWacomStylusClass *klass); static void gsd_wacom_stylus_init (GsdWacomStylus *wacom_stylus); static void gsd_wacom_stylus_finalize (GObject *object); G_DEFINE_TYPE (GsdWacomStylus, gsd_wacom_stylus, G_TYPE_OBJECT) static void gsd_wacom_stylus_class_init (GsdWacomStylusClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gsd_wacom_stylus_finalize; g_type_class_add_private (klass, sizeof (GsdWacomStylusPrivate)); } static void gsd_wacom_stylus_init (GsdWacomStylus *stylus) { stylus->priv = GSD_WACOM_STYLUS_GET_PRIVATE (stylus); } static void gsd_wacom_stylus_finalize (GObject *object) { GsdWacomStylus *stylus; GsdWacomStylusPrivate *p; g_return_if_fail (object != NULL); g_return_if_fail (GSD_IS_WACOM_STYLUS (object)); stylus = GSD_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 (gsd_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 GsdWacomStylus * gsd_wacom_stylus_new (GsdWacomDevice *device, const WacomStylus *wstylus, GSettings *settings) { GsdWacomStylus *stylus; g_return_val_if_fail (G_IS_SETTINGS (settings), NULL); g_return_val_if_fail (wstylus != NULL, NULL); stylus = GSD_WACOM_STYLUS (g_object_new (GSD_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 * gsd_wacom_stylus_get_settings (GsdWacomStylus *stylus) { g_return_val_if_fail (GSD_IS_WACOM_STYLUS (stylus), NULL); return stylus->priv->settings; } const char * gsd_wacom_stylus_get_name (GsdWacomStylus *stylus) { g_return_val_if_fail (GSD_IS_WACOM_STYLUS (stylus), NULL); return stylus->priv->name; } const char * gsd_wacom_stylus_get_icon_name (GsdWacomStylus *stylus) { g_return_val_if_fail (GSD_IS_WACOM_STYLUS (stylus), NULL); return stylus->priv->icon_name; } GsdWacomDevice * gsd_wacom_stylus_get_device (GsdWacomStylus *stylus) { g_return_val_if_fail (GSD_IS_WACOM_STYLUS (stylus), NULL); return stylus->priv->device; } gboolean gsd_wacom_stylus_get_has_eraser (GsdWacomStylus *stylus) { g_return_val_if_fail (GSD_IS_WACOM_STYLUS (stylus), FALSE); return stylus->priv->has_eraser; } guint gsd_wacom_stylus_get_num_buttons (GsdWacomStylus *stylus) { g_return_val_if_fail (GSD_IS_WACOM_STYLUS (stylus), -1); return stylus->priv->num_buttons; } GsdWacomStylusType gsd_wacom_stylus_get_stylus_type (GsdWacomStylus *stylus) { g_return_val_if_fail (GSD_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 gsd_wacom_stylus_get_id (GsdWacomStylus *stylus) { g_return_val_if_fail (GSD_IS_WACOM_STYLUS (stylus), -1); return stylus->priv->id; } /* Tablet buttons */ static GsdWacomTabletButton * gsd_wacom_tablet_button_new (const char *name, const char *id, const char *settings_path, GsdWacomTabletButtonType type, GsdWacomTabletButtonPos pos, int group_id, int idx, int status_led) { GsdWacomTabletButton *ret; ret = g_new0 (GsdWacomTabletButton, 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 gsd_wacom_tablet_button_free (GsdWacomTabletButton *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); } GsdWacomTabletButton * gsd_wacom_tablet_button_copy (GsdWacomTabletButton *button) { GsdWacomTabletButton *ret; g_return_val_if_fail (button != NULL, NULL); ret = g_new0 (GsdWacomTabletButton, 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 GSD_WACOM_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_WACOM_DEVICE, GsdWacomDevicePrivate)) /* 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.gnome.settings-daemon.peripherals.wacom" #define SETTINGS_STYLUS_DIR "stylus" #define SETTINGS_ERASER_DIR "eraser" struct GsdWacomDevicePrivate { GdkDevice *gdk_device; int device_id; int opcode; GsdWacomDeviceType 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; GsdWacomStylus *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 gsd_wacom_device_class_init (GsdWacomDeviceClass *klass); static void gsd_wacom_device_init (GsdWacomDevice *wacom_device); static void gsd_wacom_device_finalize (GObject *object); G_DEFINE_TYPE (GsdWacomDevice, gsd_wacom_device, G_TYPE_OBJECT) static GdkFilterReturn filter_events (XEvent *xevent, GdkEvent *event, GsdWacomDevice *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; } gsd_wacom_device_set_current_stylus (device, tool_id); return GDK_FILTER_CONTINUE; } static gboolean setup_property_notify (GsdWacomDevice *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; } gsd_wacom_device_set_current_stylus (device, tool_id); return TRUE; } static GsdWacomDeviceType get_device_type (XDeviceInfo *dev) { GsdWacomDeviceType 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); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), 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, GsdWacomDevice *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, GsdWacomDevice *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 (GsdWacomDevice *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]; tablet = gsd_wacom_device_get_settings (device); c_array = g_settings_get_value (tablet, "display"); g_variant_get_strv (c_array, &nvalues); 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 GsdWacomRotation 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 gsd_wacom_device_set_display (GsdWacomDevice *device, int monitor) { GError *error = NULL; GnomeRRScreen *rr_screen; GnomeRROutput *output = NULL; g_return_if_fail (GSD_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 > GSD_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, GsdWacomDevice *device) { GnomeRROutput *rr_output; rr_output = find_output_by_display (rr_screen, device); if (rr_output == NULL) { if (gsd_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 gsd_wacom_device_get_display_monitor (GsdWacomDevice *device) { GError *error = NULL; GnomeRRScreen *rr_screen; GnomeRROutput *rr_output; GnomeRRMode *mode; GnomeRRCrtc *crtc; gint area[4]; g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), GSD_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 GSD_WACOM_SET_ALL_MONITORS; } rr_output = find_output (rr_screen, device); if (rr_output == NULL) { g_object_unref (rr_screen); return GSD_WACOM_SET_ALL_MONITORS; } if (!is_on (rr_output)) { g_warning ("Output is not active."); g_object_unref (rr_screen); return GSD_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 GSD_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 gsd_wacom_device_get_display_matrix (GsdWacomDevice *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 = gsd_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; } GsdWacomRotation gsd_wacom_device_get_display_rotation (GsdWacomDevice *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 GSD_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 (GsdWacomDevice *device, const char *settings_path, int id) { const WacomStylus *wstylus; wstylus = libwacom_stylus_get_for_id (db, id); if (wstylus) { GsdWacomStylus *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 = gsd_wacom_stylus_new (device, wstylus, settings); } else { settings = g_settings_new_with_path (WACOM_ERASER_SCHEMA, stylus_settings_path); stylus = gsd_wacom_stylus_new (device, wstylus, settings); } g_free (stylus_settings_path); device->priv->styli = g_list_prepend (device->priv->styli, stylus); } } int gsd_wacom_device_get_num_modes (GsdWacomDevice *device, int group_id) { int num_modes; g_return_val_if_fail (GSD_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 gsd_wacom_device_get_current_mode (GsdWacomDevice *device, int group_id) { int current_idx; g_return_val_if_fail (GSD_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 gsd_wacom_device_add_modes() */ g_return_val_if_fail (current_idx != 0, -1); return current_idx; } int gsd_wacom_device_set_next_mode (GsdWacomDevice *device, GsdWacomTabletButton *button) { GList *l; int current_idx; int num_modes; int num_switches; int group_id; g_return_val_if_fail (GSD_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) { GsdWacomTabletButton *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 = gsd_wacom_device_get_current_mode (device, group_id); /* gsd_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 * gsd_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, gsd_wacom_tablet_button_new (_("Left Ring"), "left-ring-mode-1", settings_path, WACOM_TABLET_BUTTON_TYPE_RING, WACOM_TABLET_BUTTON_POS_LEFT, group, 0, GSD_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, gsd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_RING, WACOM_TABLET_BUTTON_POS_LEFT, group, i - 1, GSD_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, gsd_wacom_tablet_button_new (_("Right Ring"), "right-ring-mode-1", settings_path, WACOM_TABLET_BUTTON_TYPE_RING, WACOM_TABLET_BUTTON_POS_RIGHT, group, 0, GSD_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, gsd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_RING, WACOM_TABLET_BUTTON_POS_RIGHT, group, i - 1, GSD_WACOM_NO_LED)); g_free (name); g_free (id); } } } return l; } static GList * gsd_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, gsd_wacom_tablet_button_new (_("Left Touchstrip"), "left-strip-mode-1", settings_path, WACOM_TABLET_BUTTON_TYPE_STRIP, WACOM_TABLET_BUTTON_POS_LEFT, group, 0, GSD_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, gsd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_STRIP, WACOM_TABLET_BUTTON_POS_LEFT, group, i - 1, GSD_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, gsd_wacom_tablet_button_new (_("Right Touchstrip"), "right-strip-mode-1", settings_path, WACOM_TABLET_BUTTON_TYPE_STRIP, WACOM_TABLET_BUTTON_POS_RIGHT, group, 0, GSD_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, gsd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_STRIP, WACOM_TABLET_BUTTON_POS_RIGHT, group, i - 1, GSD_WACOM_NO_LED)); g_free (name); g_free (id); } } } return l; } static char * gsd_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 GsdWacomTabletButtonType gsd_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 * gsd_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, gsd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_NORMAL, gsd_wacom_device_button_pos (flags), flags_to_group (flags), -1, GSD_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 = gsd_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, gsd_wacom_tablet_button_new (name, id, settings_path, WACOM_TABLET_BUTTON_TYPE_HARDCODED, gsd_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, gsd_wacom_device_add_ring_modes (wacom_device, settings_path, direction)); if (libwacom_get_num_strips (wacom_device) > 0) l = g_list_concat (l, gsd_wacom_device_add_strip_modes (wacom_device, settings_path, direction)); return l; } static void gsd_wacom_device_add_buttons (GsdWacomDevice *device, WacomDevice *wacom_device, const char *settings_path) { GList *l, *ret; ret = NULL; l = gsd_wacom_device_add_buttons_dir (wacom_device, settings_path, WACOM_BUTTON_POSITION_LEFT, _("Left Button #%d"), "button"); if (l) ret = l; l = gsd_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 = gsd_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 = gsd_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 gsd_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 gsd_wacom_device_add_modes (GsdWacomDevice *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) { GsdWacomTabletButton *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 gsd_wacom_device_update_from_db (GsdWacomDevice *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) { gsd_wacom_device_get_modeswitches (wacom_device, &device->priv->num_rings, &device->priv->num_strips); gsd_wacom_device_add_buttons (device, wacom_device, settings_path); gsd_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 * gsd_wacom_device_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GsdWacomDevice *device; GdkDeviceManager *device_manager; XDeviceInfo *device_info; WacomDevice *wacom_device; int n_devices; guint i; device = GSD_WACOM_DEVICE (G_OBJECT_CLASS (gsd_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; } } gsd_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 gsd_wacom_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GsdWacomDevice *device; device = GSD_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 gsd_wacom_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GsdWacomDevice *device; device = GSD_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 gsd_wacom_device_class_init (GsdWacomDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = gsd_wacom_device_constructor; object_class->finalize = gsd_wacom_device_finalize; object_class->set_property = gsd_wacom_device_set_property; object_class->get_property = gsd_wacom_device_get_property; g_type_class_add_private (klass, sizeof (GsdWacomDevicePrivate)); 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 gsd_wacom_device_init (GsdWacomDevice *device) { device->priv = GSD_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 gsd_wacom_device_finalize (GObject *object) { GsdWacomDevice *device; GsdWacomDevicePrivate *p; g_return_if_fail (object != NULL); g_return_if_fail (GSD_IS_WACOM_DEVICE (object)); device = GSD_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) gsd_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 (gsd_wacom_device_parent_class)->finalize (object); } GsdWacomDevice * gsd_wacom_device_new (GdkDevice *device) { return GSD_WACOM_DEVICE (g_object_new (GSD_TYPE_WACOM_DEVICE, "gdk-device", device, NULL)); } GList * gsd_wacom_device_list_styli (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), NULL); return g_list_copy (device->priv->styli); } GsdWacomStylus * gsd_wacom_device_get_stylus_for_type (GsdWacomDevice *device, GsdWacomStylusType type) { GList *l; g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), NULL); for (l = device->priv->styli; l != NULL; l = l->next) { GsdWacomStylus *stylus = l->data; if (gsd_wacom_stylus_get_stylus_type (stylus) == type) return stylus; } return NULL; } const char * gsd_wacom_device_get_name (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), NULL); return device->priv->name; } const char * gsd_wacom_device_get_layout_path (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), NULL); return device->priv->layout_path; } const char * gsd_wacom_device_get_path (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), NULL); return device->priv->path; } const char * gsd_wacom_device_get_icon_name (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), NULL); return device->priv->icon_name; } const char * gsd_wacom_device_get_tool_name (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), NULL); return device->priv->tool_name; } gboolean gsd_wacom_device_reversible (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), FALSE); return device->priv->reversible; } gboolean gsd_wacom_device_is_screen_tablet (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), FALSE); return device->priv->is_screen_tablet; } gboolean gsd_wacom_device_is_isd (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), FALSE); return device->priv->is_isd; } gboolean gsd_wacom_device_is_fallback (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), FALSE); return device->priv->is_fallback; } gint gsd_wacom_device_get_num_strips (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), 0); return device->priv->num_strips; } gint gsd_wacom_device_get_num_rings (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), 0); return device->priv->num_rings; } GSettings * gsd_wacom_device_get_settings (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), NULL); return device->priv->wacom_settings; } void gsd_wacom_device_set_current_stylus (GsdWacomDevice *device, int stylus_id) { GList *l; GsdWacomStylus *stylus; g_return_if_fail (GSD_IS_WACOM_DEVICE (device)); /* Don't change anything if the stylus is already set */ if (device->priv->last_stylus != NULL) { GsdWacomStylus *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); } GsdWacomDeviceType gsd_wacom_device_get_device_type (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), WACOM_TYPE_INVALID); return device->priv->type; } gint * gsd_wacom_device_get_area (GsdWacomDevice *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 (GSD_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) { XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice); return NULL; } device_area = g_new0 (int, nitems); for (i = 0; i < nitems; i++) device_area[i] = ((long *)data)[i]; XFree (data); XCloseDevice (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xdevice); return device_area; } const char * gsd_wacom_device_type_to_string (GsdWacomDeviceType 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 * gsd_wacom_device_get_buttons (GsdWacomDevice *device) { g_return_val_if_fail (GSD_IS_WACOM_DEVICE (device), NULL); return g_list_copy (device->priv->buttons); } static GsdWacomTabletButton * find_button_with_id (GsdWacomDevice *device, const char *id) { GList *l; for (l = device->priv->buttons; l != NULL; l = l->next) { GsdWacomTabletButton *button = l->data; if (g_strcmp0 (button->id, id) == 0) return button; } return NULL; } static GsdWacomTabletButton * find_button_with_index (GsdWacomDevice *device, const char *id, int index) { GsdWacomTabletButton *button; char *str; str = g_strdup_printf ("%s-mode-%d", id, index); button = find_button_with_id (device, str); g_free (str); return button; } GsdWacomTabletButton * gsd_wacom_device_get_button (GsdWacomDevice *device, int button, GtkDirectionType *dir) { int index; if (button <= 26) { char *id; GsdWacomTabletButton *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; } } GsdWacomRotation gsd_wacom_device_rotation_name_to_type (const char *rotation) { guint i; g_return_val_if_fail (rotation != NULL, GSD_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 GSD_WACOM_ROTATION_NONE; } const char * gsd_wacom_device_rotation_type_to_name (GsdWacomRotation 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"; } GsdWacomDevice * gsd_wacom_device_create_fake (GsdWacomDeviceType type, const char *name, const char *tool_name) { GsdWacomDevice *device; GsdWacomDevicePrivate *priv; WacomDevice *wacom_device; device = GSD_WACOM_DEVICE (g_object_new (GSD_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); gsd_wacom_device_update_from_db (device, wacom_device, name); libwacom_destroy (wacom_device); return device; } GList * gsd_wacom_device_create_fake_cintiq (void) { GsdWacomDevice *device; GList *devices; device = gsd_wacom_device_create_fake (WACOM_TYPE_STYLUS, "Wacom Cintiq 21UX2", "Wacom Cintiq 21UX2 stylus"); devices = g_list_prepend (NULL, device); device = gsd_wacom_device_create_fake (WACOM_TYPE_ERASER, "Wacom Cintiq 21UX2", "Wacom Cintiq 21UX2 eraser"); devices = g_list_prepend (devices, device); device = gsd_wacom_device_create_fake (WACOM_TYPE_PAD, "Wacom Cintiq 21UX2", "Wacom Cintiq 21UX2 pad"); devices = g_list_prepend (devices, device); return devices; } GList * gsd_wacom_device_create_fake_bt (void) { GsdWacomDevice *device; GList *devices; device = gsd_wacom_device_create_fake (WACOM_TYPE_STYLUS, "Wacom Graphire Wireless", "Graphire Wireless stylus"); devices = g_list_prepend (NULL, device); device = gsd_wacom_device_create_fake (WACOM_TYPE_ERASER, "Wacom Graphire Wireless", "Graphire Wireless eraser"); devices = g_list_prepend (devices, device); device = gsd_wacom_device_create_fake (WACOM_TYPE_PAD, "Wacom Graphire Wireless", "Graphire Wireless pad"); devices = g_list_prepend (devices, device); device = gsd_wacom_device_create_fake (WACOM_TYPE_CURSOR, "Wacom Graphire Wireless", "Graphire Wireless cursor"); devices = g_list_prepend (devices, device); return devices; } GList * gsd_wacom_device_create_fake_x201 (void) { GsdWacomDevice *device; GList *devices; device = gsd_wacom_device_create_fake (WACOM_TYPE_STYLUS, "Wacom Serial Tablet WACf004", "Wacom Serial Tablet WACf004 stylus"); devices = g_list_prepend (NULL, device); device = gsd_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 * gsd_wacom_device_create_fake_intuos4 (void) { GsdWacomDevice *device; GList *devices; device = gsd_wacom_device_create_fake (WACOM_TYPE_STYLUS, "Wacom Intuos4 6x9", "Wacom Intuos4 6x9 stylus"); devices = g_list_prepend (NULL, device); device = gsd_wacom_device_create_fake (WACOM_TYPE_ERASER, "Wacom Intuos4 6x9", "Wacom Intuos4 6x9 eraser"); devices = g_list_prepend (devices, device); device = gsd_wacom_device_create_fake (WACOM_TYPE_PAD, "Wacom Intuos4 6x9", "Wacom Intuos4 6x9 pad"); devices = g_list_prepend (devices, device); device = gsd_wacom_device_create_fake (WACOM_TYPE_CURSOR, "Wacom Intuos4 6x9", "Wacom Intuos4 6x9 cursor"); devices = g_list_prepend (devices, device); return devices; } unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/wacom.gresource.xml0000644000015300001610000000026512567031542027111 0ustar pbuserpbgroup00000000000000 tablet-layout.css unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/gsd-wacom-led-helper.c0000644000015300001610000001132012567031542027322 0ustar pbuserpbgroup00000000000000/* * Copyright (C) 2010-2011 Richard Hughes * Copyright (C) 2012 Bastien Nocera * * 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 static gboolean gsd_wacom_led_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; } static char * get_led_sysfs_path (GUdevDevice *device, int group_num) { char *status; char *filename; status = g_strdup_printf ("status_led%d_select", group_num); filename = g_build_filename (g_udev_device_get_sysfs_path (device), "wacom_led", status, NULL); g_free (status); return filename; } static char *path = NULL; static int group_num = -1; static int led_num = -1; const GOptionEntry options[] = { { "path", '\0', 0, G_OPTION_ARG_FILENAME, &path, "Device path for the Wacom device", NULL }, { "group", '\0', 0, G_OPTION_ARG_INT, &group_num, "Which LED group to set", NULL }, { "led", '\0', 0, G_OPTION_ARG_INT, &led_num, "Which LED to set", NULL }, { NULL} }; int main (int argc, char **argv) { GOptionContext *context; GUdevClient *client; GUdevDevice *device, *parent; int uid, euid; char *filename; GError *error = NULL; const char * const subsystems[] = { "input", NULL }; /* get calling process */ uid = getuid (); euid = geteuid (); if (uid != 0 || euid != 0) { g_print ("This program can only be used by the root user\n"); return 1; } context = g_option_context_new (NULL); g_option_context_set_summary (context, "GNOME Settings Daemon Wacom LED Helper"); g_option_context_add_main_entries (context, options, NULL); g_option_context_parse (context, &argc, &argv, NULL); if (path == NULL || group_num < 0 || led_num < 0) { char *txt; txt = g_option_context_get_help (context, FALSE, NULL); g_print ("%s", txt); g_free (txt); g_option_context_free (context); return 1; } g_option_context_free (context); client = g_udev_client_new (subsystems); device = g_udev_client_query_by_device_file (client, path); if (device == NULL) { g_debug ("Could not find device '%s' in udev database", path); goto bail; } if (g_udev_device_get_property_as_boolean (device, "ID_INPUT_TABLET") == FALSE && g_udev_device_get_property_as_boolean (device, "ID_INPUT_TOUCHPAD") == FALSE) { g_debug ("Device '%s' is not a Wacom tablet", path); goto bail; } if (g_strcmp0 (g_udev_device_get_property (device, "ID_BUS"), "usb") != 0) { /* FIXME handle Bluetooth LEDs too */ g_debug ("Non-USB LEDs setting is not supported"); goto bail; } parent = g_udev_device_get_parent_with_subsystem (device, "usb", "usb_interface"); if (parent == NULL) { g_debug ("Could not find parent USB device for '%s'", path); goto bail; } g_object_unref (device); device = parent; filename = get_led_sysfs_path (device, group_num); if (gsd_wacom_led_helper_write (filename, led_num, &error) == FALSE) { g_debug ("Could not set LED status for '%s': %s", path, error->message); g_error_free (error); g_free (filename); goto bail; } g_free (filename); g_debug ("Successfully set LED status for '%s', group %d to %d", path, group_num, led_num); g_object_unref (device); g_object_unref (client); return 0; bail: if (device != NULL) g_object_unref (device); if (client != NULL) g_object_unref (client); return 1; } unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/gsd-wacom-plugin.c0000644000015300001610000000206112567031542026601 0ustar pbuserpbgroup00000000000000/* -*- 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 "gnome-settings-plugin.h" #include "gsd-wacom-manager.h" GNOME_SETTINGS_PLUGIN_REGISTER (GsdWacom, gsd_wacom) ././@LongLink0000000000000000000000000000016700000000000011221 Lustar 00000000000000unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/com.ubuntu.unity-settings-daemon.plugins.wacom.policy.in.inunity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/com.ubuntu.unity-settings-daemon.plugins.0000644000015300001610000000216712567031542033315 0ustar pbuserpbgroup00000000000000 Unity 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@/usd-wacom-led-helper unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/gsd-wacom-manager.h0000644000015300001610000000443412567031542026730 0ustar pbuserpbgroup00000000000000/* -*- 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 __GSD_WACOM_MANAGER_H #define __GSD_WACOM_MANAGER_H #include G_BEGIN_DECLS #define GSD_TYPE_WACOM_MANAGER (gsd_wacom_manager_get_type ()) #define GSD_WACOM_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_WACOM_MANAGER, GsdWacomManager)) #define GSD_WACOM_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_WACOM_MANAGER, GsdWacomManagerClass)) #define GSD_IS_WACOM_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_WACOM_MANAGER)) #define GSD_IS_WACOM_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_WACOM_MANAGER)) #define GSD_WACOM_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_WACOM_MANAGER, GsdWacomManagerClass)) typedef struct GsdWacomManagerPrivate GsdWacomManagerPrivate; typedef struct { GObject parent; GsdWacomManagerPrivate *priv; } GsdWacomManager; typedef struct { GObjectClass parent_class; } GsdWacomManagerClass; GType gsd_wacom_manager_get_type (void); GsdWacomManager * gsd_wacom_manager_new (void); gboolean gsd_wacom_manager_start (GsdWacomManager *manager, GError **error); void gsd_wacom_manager_stop (GsdWacomManager *manager); G_END_DECLS #endif /* __GSD_WACOM_MANAGER_H */ unity-settings-daemon-14.04.0+14.04.20150825/plugins/wacom/README.config-storage0000644000015300001610000000323512567031542027052 0ustar pbuserpbgroup00000000000000Configuration 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.gnome.settings-daemon.peripherals.wacom path: /org/gnome/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.gnome.settings-daemon.peripherals.wacom.stylus or: org.gnome.settings-daemon.peripherals.wacom.eraser path: /org/gnome/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.gnome.settings-daemon.peripherals.wacom.tablet-button path: /org/gnome/settings-daemon/peripherals/wacom//