cinnamon-session-3.6.1/0000755000175000017500000000000013205266677013540 5ustar maxymaxycinnamon-session-3.6.1/.github/0000755000175000017500000000000013205266677015100 5ustar maxymaxycinnamon-session-3.6.1/.github/ISSUE_TEMPLATE.md0000644000175000017500000000041113205266677017601 0ustar maxymaxy ``` * cinnamon-session version (cinnamon-session --version) * Distribution - (Mint 17.2, Arch, Fedora 25, etc...) * Graphics hardware *and* driver used * 32 or 64 bit ``` **Issue** **Steps to reproduce** **Expected behaviour** **Other information** cinnamon-session-3.6.1/.gitignore0000644000175000017500000000064113205266677015531 0ustar maxymaxy## autogenerated files ## /m4/ /autom4te.cache/ /aclocal.m4 /compile /config.guess /config.h* /config.sub /configure /depcomp /HACKING /INSTALL /install-sh /ltmain.sh /MAINTAINERS /missing /mkinstalldirs /cinnamon-session/csm-marshal.c /cinnamon-session/csm-marshal.h /omf.make /xmldocs.make Makefile.in ## binaries ## *.so *.so.* *.a ## backup files ## *~ *.old *.bak ## IDE files ## .idea CMakeLists.txt cinnamon-session-3.6.1/AUTHORS0000644000175000017500000000067313205266677014616 0ustar maxymaxyhttps://github.com/linuxmint/cinnamon-session/contributors original gnome-session authors ------------------------------ Dan Winship Lucas Rocha William Jon McCann Tom Tromey Felix Bellaby smproxy authors --------------- Ralph Mor, X Consortium with modifications from Tom Tromey Felix Bellaby cinnamon-session-3.6.1/COPYING0000644000175000017500000004325413205266677014603 0ustar maxymaxy GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. cinnamon-session-3.6.1/ChangeLog0000644000175000017500000000000013205266677015300 0ustar maxymaxycinnamon-session-3.6.1/Makefile.am0000644000175000017500000000213213205266677015572 0ustar maxymaxySUBDIRS = \ egg \ cinnamon-session \ tools \ data \ doc \ po ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} EXTRA_DIST = \ HACKING \ MAINTAINERS MAINTAINERCLEANFILES = \ $(srcdir)/INSTALL \ $(srcdir)/aclocal.m4 \ $(srcdir)/config.guess \ $(srcdir)/config.h.in \ $(srcdir)/config.sub \ $(srcdir)/depcomp \ $(srcdir)/install-sh \ $(srcdir)/ltmain.sh \ $(srcdir)/missing \ $(srcdir)/mkinstalldirs \ $(srcdir)/configure \ $(srcdir)/m4/intltool.m4 \ `find "$(srcdir)" -type f -name Makefile.in -print` CHANGELOG_GIT_RANGE = CINNAMON_SESSION_2_26_1.. dist-hook: $(AM_V_GEN)if test -d "$(srcdir)/.git"; then \ ( echo '# Generated by Makefile. Do not edit.'; echo; \ GIT_DIR="$(top_srcdir)/.git" ./missing --run \ git log $(CHANGELOG_GIT_RANGE) --no-color -M -C --name-status ) \ > ChangeLog.tmp \ && mv -f ChangeLog.tmp $(distdir)/ChangeLog \ || ( rm -f ChangeLog.tmp ; echo Failed to generate ChangeLog >&2 ); \ else \ echo A git checkout is required to generate ChangeLog >&2; \ fi GITIGNOREFILES = $(PACKAGE)-\*.tar.{gz,bz2,xz} -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/NEWS0000644000175000017500000000000013205266677014225 0ustar maxymaxycinnamon-session-3.6.1/README0000644000175000017500000000052013205266677014415 0ustar maxymaxyDesign notes for the original gnome-session =========================================== See http://live.gnome.org/SessionManagement Installation ============ See the file 'INSTALL'. If you are not using a released version of gnome-session (for example, if you checked out the code from git), you first need to run './autogen.sh'. cinnamon-session-3.6.1/README.md0000644000175000017500000000015013205266677015013 0ustar maxymaxyTODO ____ - Check for regression on power-down sequence (no dialog when laptop power button pressed) cinnamon-session-3.6.1/autogen.sh0000755000175000017500000000175513205266677015551 0ustar maxymaxy#!/bin/sh # Run this to generate all the initial makefiles, etc. test -n "$srcdir" || srcdir=$(dirname "$0") test -n "$srcdir" || srcdir=. olddir=$(pwd) cd $srcdir (test -f configure.ac) || { echo "*** ERROR: Directory '$srcdir' does not look like the top-level project directory ***" exit 1 } # shellcheck disable=SC2016 PKG_NAME=$(autoconf --trace 'AC_INIT:$1' configure.ac) if [ "$#" = 0 -a "x$NOCONFIGURE" = "x" ]; then echo "*** WARNING: I am going to run 'configure' with no arguments." >&2 echo "*** If you wish to pass any to it, please specify them on the" >&2 echo "*** '$0' command line." >&2 echo "" >&2 fi mkdir -p m4 intltoolize --force --copy --automake || exit 1 autoreconf --verbose --force --install || exit 1 cd "$olddir" if [ "$NOCONFIGURE" = "" ]; then $srcdir/configure "$@" || exit 1 if [ "$1" = "--help" ]; then exit 0 else echo "Now type 'make' to compile $PKG_NAME" || exit 1 fi else echo "Skipping configure process." fi cinnamon-session-3.6.1/cinnamon-session.pot0000644000175000017500000001570413205266677017556 0ustar maxymaxy# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-10-23 14:05+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: cinnamon-session/csm-inhibit-dialog.c:251 #, c-format msgid "Icon '%s' not found" msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:586 msgid "Unknown" msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:637 msgid "A program is still running:" msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:638 data/csm-inhibit-dialog.glade.h:2 msgid "" "Waiting for the program to finish. Interrupting the program may cause you " "to lose work." msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:641 data/csm-inhibit-dialog.glade.h:1 msgid "Some programs are still running:" msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:642 msgid "" "Waiting for programs to finish. Interrupting these programs may cause you " "to lose work." msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:872 msgid "Switch User Anyway" msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:875 msgid "Log Out Anyway" msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:878 msgid "Suspend Anyway" msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:881 msgid "Hibernate Anyway" msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:884 msgid "Shut Down Anyway" msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:887 msgid "Restart Anyway" msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:895 msgid "Lock Screen" msgstr "" #: cinnamon-session/csm-inhibit-dialog.c:898 msgid "Cancel" msgstr "" #: cinnamon-session/csm-logout-dialog.c:257 #, c-format msgid "You will be automatically logged out in %d second." msgid_plural "You will be logged out in %d seconds." msgstr[0] "" msgstr[1] "" #: cinnamon-session/csm-logout-dialog.c:265 #, c-format msgid "This system will be automatically shut down in %d second." msgid_plural "This system will be shut down in %d seconds." msgstr[0] "" msgstr[1] "" #: cinnamon-session/csm-logout-dialog.c:273 #, c-format msgid "This system will be automatically restarted in %d second." msgid_plural "This system will be restarted in %d seconds." msgstr[0] "" msgstr[1] "" #: cinnamon-session/csm-logout-dialog.c:297 #, c-format msgid "You are currently logged in as \"%s\"." msgstr "" #: cinnamon-session/csm-logout-dialog.c:359 msgid "Session" msgstr "" #: cinnamon-session/csm-logout-dialog.c:374 msgid "Log out of this system now?" msgstr "" #: cinnamon-session/csm-logout-dialog.c:380 msgid "_Switch User" msgstr "" #: cinnamon-session/csm-logout-dialog.c:385 #: cinnamon-session/csm-logout-dialog.c:418 #: cinnamon-session/csm-logout-dialog.c:434 msgid "_Cancel" msgstr "" #: cinnamon-session/csm-logout-dialog.c:389 cinnamon-session/csm-util.c:429 msgid "_Log Out" msgstr "" #: cinnamon-session/csm-logout-dialog.c:395 msgid "Shut down this system now?" msgstr "" #: cinnamon-session/csm-logout-dialog.c:401 msgid "S_uspend" msgstr "" #: cinnamon-session/csm-logout-dialog.c:407 msgid "_Hibernate" msgstr "" #: cinnamon-session/csm-logout-dialog.c:413 #: cinnamon-session/csm-logout-dialog.c:439 msgid "_Restart" msgstr "" #: cinnamon-session/csm-logout-dialog.c:423 msgid "_Shut Down" msgstr "" #: cinnamon-session/csm-logout-dialog.c:429 msgid "Restart this system now?" msgstr "" #: cinnamon-session/csm-manager.c:1490 cinnamon-session/csm-manager.c:2271 msgid "Not responding" msgstr "" #: cinnamon-session/csm-process-helper.c:123 #, c-format msgid "Exited with code %d" msgstr "" #: cinnamon-session/csm-process-helper.c:128 #, c-format msgid "Killed by signal %d" msgstr "" #: cinnamon-session/csm-process-helper.c:133 #, c-format msgid "Stopped by signal %d" msgstr "" #: cinnamon-session/csm-util.c:413 msgid "Unable to start login session (and unable to connect to the X server)" msgstr "" #: cinnamon-session/csm-xsmp-client.c:559 msgid "Remembered Application" msgstr "" #: cinnamon-session/csm-xsmp-client.c:1198 msgid "This program is blocking logout." msgstr "" #: cinnamon-session/csm-xsmp-server.c:340 msgid "" "Refusing new client connection because the session is currently being shut " "down\n" msgstr "" #: cinnamon-session/csm-xsmp-server.c:609 #, c-format msgid "Could not create ICE listening socket: %s" msgstr "" #: cinnamon-session/main.c:243 msgid "Override standard autostart directories" msgstr "" #: cinnamon-session/main.c:243 msgid "AUTOSTART_DIR" msgstr "" #: cinnamon-session/main.c:244 msgid "Session to use" msgstr "" #: cinnamon-session/main.c:244 msgid "SESSION_NAME" msgstr "" #: cinnamon-session/main.c:245 msgid "Enable debugging code" msgstr "" #: cinnamon-session/main.c:246 msgid "Do not load user-specified applications" msgstr "" #: cinnamon-session/main.c:247 msgid "Version of this application" msgstr "" #: cinnamon-session/main.c:249 msgid "Show the fail whale dialog for testing" msgstr "" #: cinnamon-session/main.c:278 msgid " - the Cinnamon session manager" msgstr "" #: tools/cinnamon-session-quit.c:53 msgid "Log out" msgstr "" #: tools/cinnamon-session-quit.c:54 msgid "Power off" msgstr "" #: tools/cinnamon-session-quit.c:55 msgid "Reboot" msgstr "" #: tools/cinnamon-session-quit.c:56 msgid "Ignoring any existing inhibitors" msgstr "" #: tools/cinnamon-session-quit.c:57 msgid "Don't prompt for user confirmation" msgstr "" #: tools/cinnamon-session-quit.c:91 tools/cinnamon-session-quit.c:101 msgid "Could not connect to the session manager" msgstr "" #: tools/cinnamon-session-quit.c:203 msgid "Program called with conflicting options" msgstr "" #: egg/eggdesktopfile.c:165 msgid "File is not a valid .desktop file" msgstr "" #: egg/eggdesktopfile.c:191 #, c-format msgid "Unrecognized desktop file Version '%s'" msgstr "" #: egg/eggdesktopfile.c:973 #, c-format msgid "Starting %s" msgstr "" #: egg/eggdesktopfile.c:1114 msgid "Application does not accept documents on command line" msgstr "" #: egg/eggdesktopfile.c:1182 #, c-format msgid "Unrecognized launch option: %d" msgstr "" #: egg/eggdesktopfile.c:1383 msgid "Can't pass document URIs to a 'Type=Link' desktop entry" msgstr "" #: egg/eggdesktopfile.c:1404 msgid "Not a launchable item" msgstr "" #: egg/eggsmclient.c:226 msgid "Disable connection to session manager" msgstr "" #: egg/eggsmclient.c:229 msgid "Specify file containing saved configuration" msgstr "" #: egg/eggsmclient.c:229 msgid "FILE" msgstr "" #: egg/eggsmclient.c:232 msgid "Specify session management ID" msgstr "" #: egg/eggsmclient.c:232 msgid "ID" msgstr "" #: egg/eggsmclient.c:253 msgid "Session management options:" msgstr "" #: egg/eggsmclient.c:254 msgid "Show session management options" msgstr "" cinnamon-session-3.6.1/cinnamon-session/0000755000175000017500000000000013205266677017023 5ustar maxymaxycinnamon-session-3.6.1/cinnamon-session/Makefile.am0000644000175000017500000001045313205266677021062 0ustar maxymaxybin_PROGRAMS = cinnamon-session noinst_LTLIBRARIES = libcsmutil.la noinst_PROGRAMS = \ test-client-dbus \ test-inhibit \ test-process-helper AM_CPPFLAGS = \ $(CINNAMON_SESSION_CFLAGS) \ $(UPOWER_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) AM_CFLAGS = $(WARN_CFLAGS) cinnamon_session_SOURCES = \ csm-app.h \ csm-app.c \ csm-autostart-app.h \ csm-autostart-app.c \ csm-client.c \ csm-client.h \ csm-xsmp-client.h \ csm-xsmp-client.c \ csm-dbus-client.h \ csm-dbus-client.c \ csm-fail-whale-dialog.h \ csm-fail-whale-dialog.c \ csm-marshal.h \ csm-marshal.c \ csm-system.h \ csm-system.c \ csm-systemd.h \ csm-systemd.c \ csm-logout-dialog.h \ csm-logout-dialog.c \ csm-icon-names.h \ csm-inhibit-dialog.h \ csm-inhibit-dialog.c \ cs-idle-monitor.h \ cs-idle-monitor.c \ csm-presence.h \ csm-presence.c \ mdm.h \ mdm.c \ mdm-signal-handler.h \ mdm-signal-handler.c \ mdm-log.h \ mdm-log.c \ main.c \ csm-store.h \ csm-store.c \ csm-inhibitor.h \ csm-inhibitor.c \ csm-manager.c \ csm-manager.h \ csm-process-helper.c \ csm-process-helper.h \ csm-session-fill.c \ csm-session-fill.h \ csm-session-save.c \ csm-session-save.h \ csm-xsmp-server.c \ csm-xsmp-server.h cinnamon_session_SOURCES += csm-consolekit.c csm-consolekit.h cinnamon_session_CPPFLAGS = \ $(AM_CPPFLAGS) \ $(SM_CFLAGS) \ $(ICE_CFLAGS) \ $(XEXT_CFLAGS) \ $(GCONF_CFLAGS) \ $(LOGIND_CFLAGS) \ -I$(top_srcdir)/egg \ -DLOCALE_DIR=\""$(datadir)/locale"\" \ -DDATA_DIR=\""$(datadir)/cinnamon-session"\" \ -DLIBEXECDIR=\"$(libexecdir)\" \ -DGTKBUILDER_DIR=\""$(pkgdatadir)"\" \ -DGCONF_SANITY_CHECK=\""$(GCONF_SANITY_CHECK)"\" \ -DGCONFTOOL_CMD=\"$(GCONFTOOL)\" cinnamon_session_LDADD = \ libcsmutil.la \ $(top_builddir)/egg/libeggdesktopfile.la \ $(SM_LIBS) \ $(ICE_LIBS) \ $(XRENDER_LIBS) \ $(XTEST_LIBS) \ $(XEXT_LIBS) \ $(CINNAMON_SESSION_LIBS) \ $(UPOWER_LIBS) \ $(GCONF_LIBS) \ $(LOGIND_LIBS) \ $(EXECINFO_LIBS) libcsmutil_la_SOURCES = \ csm-util.c \ csm-util.h libcsmutil_la_LIBADD = \ $(CINNAMON_SESSION_LIBS) test_inhibit_SOURCES = test-inhibit.c test_inhibit_LDADD = $(CINNAMON_SESSION_LIBS) test_client_dbus_SOURCES = test-client-dbus.c test_client_dbus_LDADD = $(DBUS_GLIB_LIBS) test_process_helper_SOURCES = test-process-helper.c csm-process-helper.c csm-process-helper.h test_process_helper_LDADD = $(DBUS_GLIB_LIBS) csm-marshal.c: csm-marshal.list $(AM_V_GEN)echo "#include \"csm-marshal.h\"" > $@ && \ $(GLIB_GENMARSHAL) $< --prefix=csm_marshal --body >> $@ csm-marshal.h: csm-marshal.list $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --prefix=csm_marshal --header > $@ csm-manager-glue.h: org.gnome.SessionManager.xml Makefile.am $(AM_V_GEN)dbus-binding-tool --prefix=csm_manager --mode=glib-server --output=csm-manager-glue.h $(srcdir)/org.gnome.SessionManager.xml csm-client-glue.h: org.gnome.SessionManager.Client.xml Makefile.am $(AM_V_GEN)dbus-binding-tool --prefix=csm_client --mode=glib-server --output=csm-client-glue.h $(srcdir)/org.gnome.SessionManager.Client.xml csm-app-glue.h: org.gnome.SessionManager.App.xml Makefile.am $(AM_V_GEN)dbus-binding-tool --prefix=csm_app --mode=glib-server --output=csm-app-glue.h $(srcdir)/org.gnome.SessionManager.App.xml csm-inhibitor-glue.h: org.gnome.SessionManager.Inhibitor.xml Makefile.am $(AM_V_GEN)dbus-binding-tool --prefix=csm_inhibitor --mode=glib-server --output=csm-inhibitor-glue.h $(srcdir)/org.gnome.SessionManager.Inhibitor.xml csm-presence-glue.h: org.gnome.SessionManager.Presence.xml Makefile.am $(AM_V_GEN)dbus-binding-tool --prefix=csm_presence --mode=glib-server --output=csm-presence-glue.h $(srcdir)/org.gnome.SessionManager.Presence.xml BUILT_SOURCES = \ csm-marshal.c \ csm-marshal.h \ csm-manager-glue.h \ csm-presence-glue.h \ csm-inhibitor-glue.h \ csm-client-glue.h \ csm-app-glue.h EXTRA_DIST = \ README \ csm-marshal.list \ org.gnome.SessionManager.xml \ org.gnome.SessionManager.App.xml \ org.gnome.SessionManager.Client.xml \ org.gnome.SessionManager.ClientPrivate.xml \ org.gnome.SessionManager.Inhibitor.xml \ org.gnome.SessionManager.Presence.xml CLEANFILES = \ $(BUILT_SOURCES) -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/cinnamon-session/README0000644000175000017500000000615013205266677017705 0ustar maxymaxySee also http://live.gnome.org/SessionManagement/NewGnomeSession Startup ------- main() creates the CsmSession object representing the session (either failsafe or normal). csm_session_new() reads the appropriate autostart and session files to create a list of CsmApps to be started. (CsmAppAutostart represents an autostarted app, and CsmAppResumed represents an app resumed from the previous saved session.) Startup is divided into 7 phases (CsmSessionPhase): * CSM_SESSION_PHASE_STARTUP covers cinnamon-session's internal startup, which also includes starting gconfd and dbus-daemon (if it's not already running). Gnome-session starts up those explicitly because it needs them for its own purposes. * CSM_SESSION_PHASE_EARLY_INITIALIZATION is the first phase of "normal" startup (ie, startup controlled by .desktop files rather than hardcoding). It covers the possible installation of files in $HOME by cinnamon-initial-setup and must be done before other components such as gnome-keyring use those files. * CSM_SESSION_PHASE_INITIALIZATION covers low-level stuff like startup (ie, startup controlled by .desktop files rather than hardcoding). It covers low-level stuff like gnome-settings-daemon and at-spi-registryd, that need to be running very early (before any windows are displayed). Apps in this phase can make use of a D-Bus interface (org.gnome.SessionManager.Setenv) to set environment variables in cinnamon-session's environment. This can be used for things like $GTK_MODULES, $GNOME_KEYRING_SOCKET, etc * CSM_SESSION_PHASE_WINDOW_MANAGER includes window managers and compositing managers, and anything else that has to be running before any windows are mapped * CSM_SESSION_PHASE_PANEL includes anything that permanently takes up screen real estate (via EWMH struts). This is the first phase where things actually appear on the screen. * CSM_SESSION_PHASE_DESKTOP includes anything that draws directly on the desktop (eg, nautilus). * CSM_SESSION_PHASE_APPLICATION is everything else (normal apps, tray icons, etc) For each startup phase, CsmSession launches the appropriate CsmApps. When apps connect to the XSMP or D-Bus servers, CsmClients are created and added to the session. The session tries to map these clients to CsmApps. CsmApps signal when they register (via XSMP or SN) or exit, and CsmSession uses this to decide when the phase is complete. FIXME: after starting the session, we need to run the DiscardCommands of resumed apps. Running/Shutdown ---------------- CSM_SESSION_PHASE_RUNNING is pretty similar to the old cinnamon-session; mostly it just tracks XSMP clients, and watches for SmRestartImmediately clients exiting (NOTE: THIS DOESN'T HAPPEN YET). CsmClient is in theory not XSMP-specific, but it's very very XSMP-like, and the shutdown procedure is also very XSMP-like. This is just because there's no way to do XSMP shutdown correctly otherwise. However, CsmClientDBus will still be able to present a more sane protocol to its clients than CsmClient presents to it. cinnamon-session-3.6.1/cinnamon-session/cs-idle-monitor.c0000644000175000017500000003723213205266677022203 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Authors: William Jon McCann * */ #include "config.h" #include #include #include #include #ifdef HAVE_XTEST #include #include #endif /* HAVE_XTEST */ #include #include #include #include "cs-idle-monitor.h" static void cs_idle_monitor_finalize (GObject *object); #define CS_IDLE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CS_TYPE_IDLE_MONITOR, CSIdleMonitorPrivate)) struct CSIdleMonitorPrivate { Display *display; GHashTable *watches; int sync_event_base; XSyncCounter counter; /* For use with XTest */ int *keycode; int keycode1; int keycode2; gboolean have_xtest; }; typedef struct { Display *display; guint id; XSyncValue interval; CSIdleMonitorWatchFunc callback; gpointer user_data; XSyncAlarm xalarm_positive; XSyncAlarm xalarm_negative; } CSIdleMonitorWatch; static guint32 watch_serial = 1; G_DEFINE_TYPE (CSIdleMonitor, cs_idle_monitor, G_TYPE_OBJECT) static gint64 _xsyncvalue_to_int64 (XSyncValue value) { return ((guint64) XSyncValueHigh32 (value)) << 32 | (guint64) XSyncValueLow32 (value); } static XSyncValue _int64_to_xsyncvalue (gint64 value) { XSyncValue ret; XSyncIntsToValue (&ret, value, ((guint64)value) >> 32); return ret; } static void cs_idle_monitor_dispose (GObject *object) { CSIdleMonitor *monitor; g_return_if_fail (CS_IS_IDLE_MONITOR (object)); monitor = CS_IDLE_MONITOR (object); if (monitor->priv->watches != NULL) { g_hash_table_destroy (monitor->priv->watches); monitor->priv->watches = NULL; } G_OBJECT_CLASS (cs_idle_monitor_parent_class)->dispose (object); } static gboolean _find_alarm (gpointer key, CSIdleMonitorWatch *watch, XSyncAlarm *alarm) { g_debug ("Searching for %d in %d,%d", (int)*alarm, (int)watch->xalarm_positive, (int)watch->xalarm_negative); if (watch->xalarm_positive == *alarm || watch->xalarm_negative == *alarm) { return TRUE; } return FALSE; } static CSIdleMonitorWatch * find_watch_for_alarm (CSIdleMonitor *monitor, XSyncAlarm alarm) { CSIdleMonitorWatch *watch; watch = g_hash_table_find (monitor->priv->watches, (GHRFunc)_find_alarm, &alarm); return watch; } #ifdef HAVE_XTEST static gboolean send_fake_event (CSIdleMonitor *monitor) { if (! monitor->priv->have_xtest) { return FALSE; } g_debug ("CSIdleMonitor: sending fake key"); XLockDisplay (monitor->priv->display); XTestFakeKeyEvent (monitor->priv->display, *monitor->priv->keycode, True, CurrentTime); XTestFakeKeyEvent (monitor->priv->display, *monitor->priv->keycode, False, CurrentTime); XUnlockDisplay (monitor->priv->display); /* Swap the keycode */ if (monitor->priv->keycode == &monitor->priv->keycode1) { monitor->priv->keycode = &monitor->priv->keycode2; } else { monitor->priv->keycode = &monitor->priv->keycode1; } return TRUE; } #endif /* HAVE_XTEST */ void cs_idle_monitor_reset (CSIdleMonitor *monitor) { g_return_if_fail (CS_IS_IDLE_MONITOR (monitor)); #ifdef HAVE_XTEST /* FIXME: is there a better way to reset the IDLETIME? */ send_fake_event (monitor); #endif } static void handle_alarm_notify_event (CSIdleMonitor *monitor, XSyncAlarmNotifyEvent *alarm_event) { CSIdleMonitorWatch *watch; gboolean res; gboolean condition; if (alarm_event->state == XSyncAlarmDestroyed) { return; } watch = find_watch_for_alarm (monitor, alarm_event->alarm); if (watch == NULL) { g_debug ("Unable to find watch for alarm %d", (int)alarm_event->alarm); return; } g_debug ("Watch %d fired, idle time = %" G_GINT64_FORMAT, watch->id, _xsyncvalue_to_int64 (alarm_event->counter_value)); if (alarm_event->alarm == watch->xalarm_positive) { condition = TRUE; } else { condition = FALSE; } res = TRUE; if (watch->callback != NULL) { res = watch->callback (monitor, watch->id, condition, watch->user_data); } if (! res) { /* reset all timers */ g_debug ("CSIdleMonitor: callback returned FALSE; resetting idle time"); cs_idle_monitor_reset (monitor); } } static GdkFilterReturn xevent_filter (GdkXEvent *xevent, GdkEvent *event, CSIdleMonitor *monitor) { XEvent *ev; XSyncAlarmNotifyEvent *alarm_event; ev = xevent; if (ev->xany.type != monitor->priv->sync_event_base + XSyncAlarmNotify) { return GDK_FILTER_CONTINUE; } alarm_event = xevent; handle_alarm_notify_event (monitor, alarm_event); return GDK_FILTER_CONTINUE; } static gboolean init_xsync (CSIdleMonitor *monitor) { int sync_error_base; int res; int major; int minor; int i; int ncounters; XSyncSystemCounter *counters; res = XSyncQueryExtension (monitor->priv->display, &monitor->priv->sync_event_base, &sync_error_base); if (! res) { g_warning ("CSIdleMonitor: Sync extension not present"); return FALSE; } res = XSyncInitialize (monitor->priv->display, &major, &minor); if (! res) { g_warning ("CSIdleMonitor: Unable to initialize Sync extension"); return FALSE; } counters = XSyncListSystemCounters (monitor->priv->display, &ncounters); for (i = 0; i < ncounters; i++) { if (counters[i].name != NULL && strcmp (counters[i].name, "IDLETIME") == 0) { monitor->priv->counter = counters[i].counter; break; } } XSyncFreeSystemCounterList (counters); if (monitor->priv->counter == None) { g_warning ("CSIdleMonitor: IDLETIME counter not found"); return FALSE; } gdk_window_add_filter (NULL, (GdkFilterFunc)xevent_filter, monitor); return TRUE; } static void _init_xtest (CSIdleMonitor *monitor) { #ifdef HAVE_XTEST int a, b, c, d; XLockDisplay (monitor->priv->display); monitor->priv->have_xtest = (XTestQueryExtension (monitor->priv->display, &a, &b, &c, &d) == True); if (monitor->priv->have_xtest) { monitor->priv->keycode1 = XKeysymToKeycode (monitor->priv->display, XK_Alt_L); if (monitor->priv->keycode1 == 0) { g_warning ("keycode1 not existent"); } monitor->priv->keycode2 = XKeysymToKeycode (monitor->priv->display, XK_Alt_R); if (monitor->priv->keycode2 == 0) { monitor->priv->keycode2 = XKeysymToKeycode (monitor->priv->display, XK_Alt_L); if (monitor->priv->keycode2 == 0) { g_warning ("keycode2 not existent"); } } monitor->priv->keycode = &monitor->priv->keycode1; } XUnlockDisplay (monitor->priv->display); #endif /* HAVE_XTEST */ } static GObject * cs_idle_monitor_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CSIdleMonitor *monitor; monitor = CS_IDLE_MONITOR (G_OBJECT_CLASS (cs_idle_monitor_parent_class)->constructor (type, n_construct_properties, construct_properties)); monitor->priv->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); _init_xtest (monitor); if (! init_xsync (monitor)) { g_object_unref (monitor); return NULL; } return G_OBJECT (monitor); } static void cs_idle_monitor_class_init (CSIdleMonitorClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = cs_idle_monitor_finalize; object_class->dispose = cs_idle_monitor_dispose; object_class->constructor = cs_idle_monitor_constructor; g_type_class_add_private (klass, sizeof (CSIdleMonitorPrivate)); } static guint32 get_next_watch_serial (void) { guint32 serial; serial = watch_serial++; if ((gint32)watch_serial < 0) { watch_serial = 1; } /* FIXME: make sure it isn't in the hash */ return serial; } static CSIdleMonitorWatch * idle_monitor_watch_new (guint interval) { CSIdleMonitorWatch *watch; watch = g_slice_new0 (CSIdleMonitorWatch); watch->interval = _int64_to_xsyncvalue ((gint64)interval); watch->id = get_next_watch_serial (); watch->xalarm_positive = None; watch->xalarm_negative = None; return watch; } static void idle_monitor_watch_free (CSIdleMonitorWatch *watch) { if (watch == NULL) { return; } if (watch->xalarm_positive != None) { XSyncDestroyAlarm (watch->display, watch->xalarm_positive); } if (watch->xalarm_negative != None) { XSyncDestroyAlarm (watch->display, watch->xalarm_negative); } g_slice_free (CSIdleMonitorWatch, watch); } static void cs_idle_monitor_init (CSIdleMonitor *monitor) { monitor->priv = CS_IDLE_MONITOR_GET_PRIVATE (monitor); monitor->priv->watches = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)idle_monitor_watch_free); monitor->priv->counter = None; } static void cs_idle_monitor_finalize (GObject *object) { CSIdleMonitor *idle_monitor; g_return_if_fail (object != NULL); g_return_if_fail (CS_IS_IDLE_MONITOR (object)); idle_monitor = CS_IDLE_MONITOR (object); g_return_if_fail (idle_monitor->priv != NULL); G_OBJECT_CLASS (cs_idle_monitor_parent_class)->finalize (object); } CSIdleMonitor * cs_idle_monitor_new (void) { GObject *idle_monitor; idle_monitor = g_object_new (CS_TYPE_IDLE_MONITOR, NULL); return CS_IDLE_MONITOR (idle_monitor); } static gboolean _xsync_alarm_set (CSIdleMonitor *monitor, CSIdleMonitorWatch *watch) { XSyncAlarmAttributes attr; XSyncValue delta; guint flags; flags = XSyncCACounter | XSyncCAValueType | XSyncCATestType | XSyncCAValue | XSyncCADelta | XSyncCAEvents; XSyncIntToValue (&delta, 0); attr.trigger.counter = monitor->priv->counter; attr.trigger.value_type = XSyncAbsolute; attr.trigger.wait_value = watch->interval; attr.delta = delta; attr.events = TRUE; attr.trigger.test_type = XSyncPositiveTransition; if (watch->xalarm_positive != None) { g_debug ("CSIdleMonitor: updating alarm for positive transition wait=%" G_GINT64_FORMAT, _xsyncvalue_to_int64 (attr.trigger.wait_value)); XSyncChangeAlarm (monitor->priv->display, watch->xalarm_positive, flags, &attr); } else { g_debug ("CSIdleMonitor: creating new alarm for positive transition wait=%" G_GINT64_FORMAT, _xsyncvalue_to_int64 (attr.trigger.wait_value)); watch->xalarm_positive = XSyncCreateAlarm (monitor->priv->display, flags, &attr); } attr.trigger.wait_value = _int64_to_xsyncvalue (_xsyncvalue_to_int64 (watch->interval) - 1); attr.trigger.test_type = XSyncNegativeTransition; if (watch->xalarm_negative != None) { g_debug ("CSIdleMonitor: updating alarm for negative transition wait=%" G_GINT64_FORMAT, _xsyncvalue_to_int64 (attr.trigger.wait_value)); XSyncChangeAlarm (monitor->priv->display, watch->xalarm_negative, flags, &attr); } else { g_debug ("CSIdleMonitor: creating new alarm for negative transition wait=%" G_GINT64_FORMAT, _xsyncvalue_to_int64 (attr.trigger.wait_value)); watch->xalarm_negative = XSyncCreateAlarm (monitor->priv->display, flags, &attr); } return TRUE; } guint cs_idle_monitor_add_watch (CSIdleMonitor *monitor, guint interval, CSIdleMonitorWatchFunc callback, gpointer user_data) { CSIdleMonitorWatch *watch; g_return_val_if_fail (CS_IS_IDLE_MONITOR (monitor), 0); g_return_val_if_fail (callback != NULL, 0); watch = idle_monitor_watch_new (interval); watch->display = monitor->priv->display; watch->callback = callback; watch->user_data = user_data; _xsync_alarm_set (monitor, watch); g_hash_table_insert (monitor->priv->watches, GUINT_TO_POINTER (watch->id), watch); return watch->id; } void cs_idle_monitor_remove_watch (CSIdleMonitor *monitor, guint id) { g_return_if_fail (CS_IS_IDLE_MONITOR (monitor)); g_hash_table_remove (monitor->priv->watches, GUINT_TO_POINTER (id)); } cinnamon-session-3.6.1/cinnamon-session/cs-idle-monitor.h0000644000175000017500000000541013205266677022201 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Authors: William Jon McCann * */ #ifndef __CS_IDLE_MONITOR_H #define __CS_IDLE_MONITOR_H #include G_BEGIN_DECLS #define CS_TYPE_IDLE_MONITOR (cs_idle_monitor_get_type ()) #define CS_IDLE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CS_TYPE_IDLE_MONITOR, CSIdleMonitor)) #define CS_IDLE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CS_TYPE_IDLE_MONITOR, CSIdleMonitorClass)) #define CS_IS_IDLE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CS_TYPE_IDLE_MONITOR)) #define CS_IS_IDLE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CS_TYPE_IDLE_MONITOR)) #define CS_IDLE_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CS_TYPE_IDLE_MONITOR, CSIdleMonitorClass)) typedef struct CSIdleMonitorPrivate CSIdleMonitorPrivate; typedef struct { GObject parent; CSIdleMonitorPrivate *priv; } CSIdleMonitor; typedef struct { GObjectClass parent_class; } CSIdleMonitorClass; typedef gboolean (*CSIdleMonitorWatchFunc) (CSIdleMonitor *monitor, guint id, gboolean condition, gpointer user_data); GType cs_idle_monitor_get_type (void); CSIdleMonitor * cs_idle_monitor_new (void); guint cs_idle_monitor_add_watch (CSIdleMonitor *monitor, guint interval, CSIdleMonitorWatchFunc callback, gpointer user_data); void cs_idle_monitor_remove_watch (CSIdleMonitor *monitor, guint id); void cs_idle_monitor_reset (CSIdleMonitor *monitor); G_END_DECLS #endif /* __CS_IDLE_MONITOR_H */ cinnamon-session-3.6.1/cinnamon-session/csm-app.c0000644000175000017500000003551613205266677020541 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Novell, Inc. * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "csm-app.h" #include "csm-app-glue.h" #define CSM_APP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_APP, CsmAppPrivate)) /* If a component crashes twice within a minute, we count that as a fatal error */ #define _CSM_APP_RESPAWN_RATELIMIT_SECONDS 60 struct _CsmAppPrivate { char *id; char *app_id; int phase; char *startup_id; gboolean ever_started; GTimeVal last_restart_time; DBusGConnection *connection; }; enum { EXITED, DIED, REGISTERED, LAST_SIGNAL }; static guint32 app_serial = 1; static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, PROP_ID, PROP_STARTUP_ID, PROP_PHASE, LAST_PROP }; G_DEFINE_TYPE (CsmApp, csm_app, G_TYPE_OBJECT) GQuark csm_app_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("csm_app_error"); } return ret; } static guint32 get_next_app_serial (void) { guint32 serial; serial = app_serial++; if ((gint32)app_serial < 0) { app_serial = 1; } return serial; } static gboolean register_app (CsmApp *app) { GError *error; error = NULL; app->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (app->priv->connection == NULL) { if (error != NULL) { g_critical ("error getting session bus: %s", error->message); g_error_free (error); } return FALSE; } dbus_g_connection_register_g_object (app->priv->connection, app->priv->id, G_OBJECT (app)); return TRUE; } static GObject * csm_app_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsmApp *app; gboolean res; app = CSM_APP (G_OBJECT_CLASS (csm_app_parent_class)->constructor (type, n_construct_properties, construct_properties)); g_free (app->priv->id); app->priv->id = g_strdup_printf ("/org/gnome/SessionManager/App%u", get_next_app_serial ()); res = register_app (app); if (! res) { g_warning ("Unable to register app with session bus"); } return G_OBJECT (app); } static void csm_app_init (CsmApp *app) { app->priv = CSM_APP_GET_PRIVATE (app); } static void csm_app_set_phase (CsmApp *app, int phase) { g_return_if_fail (CSM_IS_APP (app)); app->priv->phase = phase; } static void csm_app_set_id (CsmApp *app, const char *id) { g_return_if_fail (CSM_IS_APP (app)); g_free (app->priv->id); app->priv->id = g_strdup (id); g_object_notify (G_OBJECT (app), "id"); } static void csm_app_set_startup_id (CsmApp *app, const char *startup_id) { g_return_if_fail (CSM_IS_APP (app)); g_free (app->priv->startup_id); app->priv->startup_id = g_strdup (startup_id); g_object_notify (G_OBJECT (app), "startup-id"); } static void csm_app_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsmApp *app = CSM_APP (object); switch (prop_id) { case PROP_STARTUP_ID: csm_app_set_startup_id (app, g_value_get_string (value)); break; case PROP_ID: csm_app_set_id (app, g_value_get_string (value)); break; case PROP_PHASE: csm_app_set_phase (app, g_value_get_int (value)); break; default: break; } } static void csm_app_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsmApp *app = CSM_APP (object); switch (prop_id) { case PROP_STARTUP_ID: g_value_set_string (value, app->priv->startup_id); break; case PROP_ID: g_value_set_string (value, app->priv->id); break; case PROP_PHASE: g_value_set_int (value, app->priv->phase); break; default: break; } } static void csm_app_dispose (GObject *object) { CsmApp *app = CSM_APP (object); g_free (app->priv->startup_id); app->priv->startup_id = NULL; g_free (app->priv->id); app->priv->id = NULL; G_OBJECT_CLASS (csm_app_parent_class)->dispose (object); } static void csm_app_class_init (CsmAppClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = csm_app_set_property; object_class->get_property = csm_app_get_property; object_class->dispose = csm_app_dispose; object_class->constructor = csm_app_constructor; klass->impl_start = NULL; klass->impl_get_app_id = NULL; klass->impl_get_autorestart = NULL; klass->impl_provides = NULL; klass->impl_get_provides = NULL; klass->impl_is_running = NULL; klass->impl_peek_autostart_delay = NULL; g_object_class_install_property (object_class, PROP_PHASE, g_param_spec_int ("phase", "Phase", "Phase", -1, G_MAXINT, -1, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_ID, g_param_spec_string ("id", "ID", "ID", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_STARTUP_ID, g_param_spec_string ("startup-id", "startup ID", "Session management startup ID", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); signals[EXITED] = g_signal_new ("exited", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmAppClass, exited), NULL, NULL, g_cclosure_marshal_VOID__UCHAR, G_TYPE_NONE, 1, G_TYPE_UCHAR); signals[DIED] = g_signal_new ("died", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmAppClass, died), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); signals[REGISTERED] = g_signal_new ("registered", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmAppClass, registered), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); g_type_class_add_private (klass, sizeof (CsmAppPrivate)); dbus_g_object_type_install_info (CSM_TYPE_APP, &dbus_glib_csm_app_object_info); } const char * csm_app_peek_id (CsmApp *app) { return app->priv->id; } const char * csm_app_peek_app_id (CsmApp *app) { return CSM_APP_GET_CLASS (app)->impl_get_app_id (app); } const char * csm_app_peek_startup_id (CsmApp *app) { return app->priv->startup_id; } /** * csm_app_peek_phase: * @app: a %CsmApp * * Returns @app's startup phase. * * Return value: @app's startup phase **/ CsmManagerPhase csm_app_peek_phase (CsmApp *app) { g_return_val_if_fail (CSM_IS_APP (app), CSM_MANAGER_PHASE_APPLICATION); return app->priv->phase; } gboolean csm_app_peek_is_disabled (CsmApp *app) { g_return_val_if_fail (CSM_IS_APP (app), FALSE); if (CSM_APP_GET_CLASS (app)->impl_is_disabled) { return CSM_APP_GET_CLASS (app)->impl_is_disabled (app); } else { return FALSE; } } gboolean csm_app_peek_is_conditionally_disabled (CsmApp *app) { g_return_val_if_fail (CSM_IS_APP (app), FALSE); if (CSM_APP_GET_CLASS (app)->impl_is_conditionally_disabled) { return CSM_APP_GET_CLASS (app)->impl_is_conditionally_disabled (app); } else { return FALSE; } } gboolean csm_app_is_running (CsmApp *app) { g_return_val_if_fail (CSM_IS_APP (app), FALSE); if (CSM_APP_GET_CLASS (app)->impl_is_running) { return CSM_APP_GET_CLASS (app)->impl_is_running (app); } else { return FALSE; } } gboolean csm_app_peek_autorestart (CsmApp *app) { g_return_val_if_fail (CSM_IS_APP (app), FALSE); if (CSM_APP_GET_CLASS (app)->impl_get_autorestart) { return CSM_APP_GET_CLASS (app)->impl_get_autorestart (app); } else { return FALSE; } } gboolean csm_app_provides (CsmApp *app, const char *service) { if (CSM_APP_GET_CLASS (app)->impl_provides) { return CSM_APP_GET_CLASS (app)->impl_provides (app, service); } else { return FALSE; } } char ** csm_app_get_provides (CsmApp *app) { if (CSM_APP_GET_CLASS (app)->impl_get_provides) { return CSM_APP_GET_CLASS (app)->impl_get_provides (app); } else { return NULL; } } gboolean csm_app_has_autostart_condition (CsmApp *app, const char *condition) { if (CSM_APP_GET_CLASS (app)->impl_has_autostart_condition) { return CSM_APP_GET_CLASS (app)->impl_has_autostart_condition (app, condition); } else { return FALSE; } } gboolean csm_app_start (CsmApp *app, GError **error) { g_debug ("Starting app: %s", app->priv->id); return CSM_APP_GET_CLASS (app)->impl_start (app, error); } gboolean csm_app_restart (CsmApp *app, GError **error) { GTimeVal current_time; g_debug ("Re-starting app: %s", app->priv->id); g_get_current_time (¤t_time); if (app->priv->last_restart_time.tv_sec > 0 && (current_time.tv_sec - app->priv->last_restart_time.tv_sec) < _CSM_APP_RESPAWN_RATELIMIT_SECONDS) { g_warning ("App '%s' respawning too quickly", csm_app_peek_app_id (app)); g_set_error (error, CSM_APP_ERROR, CSM_APP_ERROR_RESTART_LIMIT, "Component '%s' crashing too quickly", csm_app_peek_app_id (app)); return FALSE; } app->priv->last_restart_time = current_time; return CSM_APP_GET_CLASS (app)->impl_restart (app, error); } gboolean csm_app_stop (CsmApp *app, GError **error) { return CSM_APP_GET_CLASS (app)->impl_stop (app, error); } void csm_app_registered (CsmApp *app) { g_return_if_fail (CSM_IS_APP (app)); g_signal_emit (app, signals[REGISTERED], 0); } int csm_app_peek_autostart_delay (CsmApp *app) { g_return_val_if_fail (CSM_IS_APP (app), FALSE); if (CSM_APP_GET_CLASS (app)->impl_peek_autostart_delay) { return CSM_APP_GET_CLASS (app)->impl_peek_autostart_delay (app); } else { return 0; } } void csm_app_exited (CsmApp *app, guchar exit_code) { g_return_if_fail (CSM_IS_APP (app)); g_signal_emit (app, signals[EXITED], 0, exit_code); } void csm_app_died (CsmApp *app, int signal) { g_return_if_fail (CSM_IS_APP (app)); g_signal_emit (app, signals[DIED], 0, signal); } gboolean csm_app_get_app_id (CsmApp *app, char **id, GError **error) { g_return_val_if_fail (CSM_IS_APP (app), FALSE); *id = g_strdup (CSM_APP_GET_CLASS (app)->impl_get_app_id (app)); return TRUE; } gboolean csm_app_get_startup_id (CsmApp *app, char **id, GError **error) { g_return_val_if_fail (CSM_IS_APP (app), FALSE); *id = g_strdup (app->priv->startup_id); return TRUE; } gboolean csm_app_get_phase (CsmApp *app, guint *phase, GError **error) { g_return_val_if_fail (CSM_IS_APP (app), FALSE); *phase = app->priv->phase; return TRUE; } cinnamon-session-3.6.1/cinnamon-session/csm-app.h0000644000175000017500000001442313205266677020540 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Novell, Inc. * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_APP_H__ #define __CSM_APP_H__ #include #include #include "eggdesktopfile.h" #include "csm-manager.h" #include "csm-client.h" G_BEGIN_DECLS #define CSM_TYPE_APP (csm_app_get_type ()) #define CSM_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSM_TYPE_APP, CsmApp)) #define CSM_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSM_TYPE_APP, CsmAppClass)) #define CSM_IS_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSM_TYPE_APP)) #define CSM_IS_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSM_TYPE_APP)) #define CSM_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CSM_TYPE_APP, CsmAppClass)) typedef struct _CsmApp CsmApp; typedef struct _CsmAppClass CsmAppClass; typedef struct _CsmAppPrivate CsmAppPrivate; struct _CsmApp { GObject parent; CsmAppPrivate *priv; }; struct _CsmAppClass { GObjectClass parent_class; /* signals */ void (*exited) (CsmApp *app, guchar exit_code); void (*died) (CsmApp *app, int signal); void (*registered) (CsmApp *app); /* virtual methods */ gboolean (*impl_start) (CsmApp *app, GError **error); gboolean (*impl_restart) (CsmApp *app, GError **error); gboolean (*impl_stop) (CsmApp *app, GError **error); int (*impl_peek_autostart_delay) (CsmApp *app); gboolean (*impl_provides) (CsmApp *app, const char *service); char ** (*impl_get_provides) (CsmApp *app); gboolean (*impl_has_autostart_condition) (CsmApp *app, const char *service); gboolean (*impl_is_running) (CsmApp *app); gboolean (*impl_get_autorestart) (CsmApp *app); const char *(*impl_get_app_id) (CsmApp *app); gboolean (*impl_is_disabled) (CsmApp *app); gboolean (*impl_is_conditionally_disabled) (CsmApp *app); }; typedef enum { CSM_APP_ERROR_GENERAL = 0, CSM_APP_ERROR_RESTART_LIMIT, CSM_APP_ERROR_START, CSM_APP_ERROR_STOP, CSM_APP_NUM_ERRORS } CsmAppError; #define CSM_APP_ERROR csm_app_error_quark () GQuark csm_app_error_quark (void); GType csm_app_get_type (void) G_GNUC_CONST; gboolean csm_app_peek_autorestart (CsmApp *app); const char *csm_app_peek_id (CsmApp *app); const char *csm_app_peek_app_id (CsmApp *app); const char *csm_app_peek_startup_id (CsmApp *app); CsmManagerPhase csm_app_peek_phase (CsmApp *app); gboolean csm_app_peek_is_disabled (CsmApp *app); gboolean csm_app_peek_is_conditionally_disabled (CsmApp *app); gboolean csm_app_start (CsmApp *app, GError **error); gboolean csm_app_restart (CsmApp *app, GError **error); gboolean csm_app_stop (CsmApp *app, GError **error); gboolean csm_app_is_running (CsmApp *app); void csm_app_exited (CsmApp *app, guchar exit_code); void csm_app_died (CsmApp *app, int signal); gboolean csm_app_provides (CsmApp *app, const char *service); char **csm_app_get_provides (CsmApp *app); gboolean csm_app_has_autostart_condition (CsmApp *app, const char *condition); void csm_app_registered (CsmApp *app); int csm_app_peek_autostart_delay (CsmApp *app); /* exported to bus */ gboolean csm_app_get_app_id (CsmApp *app, char **id, GError **error); gboolean csm_app_get_startup_id (CsmApp *app, char **id, GError **error); gboolean csm_app_get_phase (CsmApp *app, guint *phase, GError **error); G_END_DECLS #endif /* __CSM_APP_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-autostart-app.c0000644000175000017500000014076713205266677022572 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Novell, Inc. * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include #include #include #include #include #include #include #ifdef HAVE_GCONF #include #endif #include "csm-autostart-app.h" #include "csm-util.h" enum { AUTOSTART_LAUNCH_SPAWN = 0, AUTOSTART_LAUNCH_ACTIVATE }; enum { CSM_CONDITION_NONE = 0, CSM_CONDITION_IF_EXISTS = 1, CSM_CONDITION_UNLESS_EXISTS = 2, #ifdef HAVE_GCONF CSM_CONDITION_GNOME = 3, #endif CSM_CONDITION_GSETTINGS = 4, CSM_CONDITION_IF_SESSION = 5, CSM_CONDITION_UNLESS_SESSION = 6, CSM_CONDITION_UNKNOWN = 7 }; #define CSM_SESSION_CLIENT_DBUS_INTERFACE "org.cinnamon.SessionClient" struct _CsmAutostartAppPrivate { char *desktop_filename; char *desktop_id; char *startup_id; EggDesktopFile *desktop_file; /* provides defined in session definition */ GSList *session_provides; /* desktop file state */ char *condition_string; gboolean condition; gboolean autorestart; int autostart_delay; GFileMonitor *condition_monitor; guint condition_notify_id; GSettings *condition_settings; int launch_type; GPid pid; guint child_watch_id; DBusGProxy *proxy; DBusGProxyCall *proxy_call; }; enum { CONDITION_CHANGED, LAST_SIGNAL }; enum { PROP_0, PROP_DESKTOP_FILENAME }; static guint signals[LAST_SIGNAL] = { 0 }; #define CSM_AUTOSTART_APP_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), CSM_TYPE_AUTOSTART_APP, CsmAutostartAppPrivate)) G_DEFINE_TYPE (CsmAutostartApp, csm_autostart_app, CSM_TYPE_APP) static void csm_autostart_app_init (CsmAutostartApp *app) { app->priv = CSM_AUTOSTART_APP_GET_PRIVATE (app); app->priv->pid = -1; app->priv->condition_monitor = NULL; app->priv->condition = FALSE; app->priv->autostart_delay = -1; } static gboolean is_disabled (CsmApp *app) { CsmAutostartAppPrivate *priv; const char *current_desktop; CsmManager *manager; manager = csm_manager_get (); if (csm_manager_get_app_is_blacklisted (manager, csm_app_peek_id (app))) return TRUE; priv = CSM_AUTOSTART_APP (app)->priv; /* CSM_AUTOSTART_APP_ENABLED_KEY key, used by old */ if (egg_desktop_file_has_key (priv->desktop_file, CSM_AUTOSTART_APP_ENABLED_KEY, NULL) && !egg_desktop_file_get_boolean (priv->desktop_file, CSM_AUTOSTART_APP_ENABLED_KEY, NULL)) { g_debug ("app %s is disabled by " CSM_AUTOSTART_APP_ENABLED_KEY, csm_app_peek_id (app)); return TRUE; } /* Hidden key, used by autostart spec */ if (egg_desktop_file_get_boolean (priv->desktop_file, EGG_DESKTOP_FILE_KEY_HIDDEN, NULL)) { g_debug ("app %s is disabled by Hidden", csm_app_peek_id (app)); return TRUE; } /* Check OnlyShowIn/NotShowIn/TryExec */ current_desktop = csm_util_get_current_desktop (); if (!egg_desktop_file_can_launch (priv->desktop_file, current_desktop)) { if (current_desktop) { g_debug ("app %s not installed or not for %s", csm_app_peek_id (app), current_desktop); } else { g_debug ("app %s not installed", csm_app_peek_id (app)); } return TRUE; } /* Do not check AutostartCondition - this method is only to determine if the app is unconditionally disabled */ return FALSE; } static gboolean parse_condition_string (const char *condition_string, guint *condition_kindp, char **keyp) { const char *space; const char *key; int len; guint kind; space = condition_string + strcspn (condition_string, " "); len = space - condition_string; key = space; while (isspace ((unsigned char)*key)) { key++; } kind = CSM_CONDITION_UNKNOWN; if (!g_ascii_strncasecmp (condition_string, "if-exists", len) && key) { kind = CSM_CONDITION_IF_EXISTS; } else if (!g_ascii_strncasecmp (condition_string, "unless-exists", len) && key) { kind = CSM_CONDITION_UNLESS_EXISTS; #ifdef HAVE_GCONF } else if (!g_ascii_strncasecmp (condition_string, "GNOME", len)) { kind = CSM_CONDITION_GNOME; #endif } else if (!g_ascii_strncasecmp (condition_string, "GSettings", len)) { kind = CSM_CONDITION_GSETTINGS; } else if (!g_ascii_strncasecmp (condition_string, "GNOME3", len)) { condition_string = key; space = condition_string + strcspn (condition_string, " "); len = space - condition_string; key = space; while (isspace ((unsigned char)*key)) { key++; } if (!g_ascii_strncasecmp (condition_string, "if-session", len) && key) { kind = CSM_CONDITION_IF_SESSION; } else if (!g_ascii_strncasecmp (condition_string, "unless-session", len) && key) { kind = CSM_CONDITION_UNLESS_SESSION; } } if (kind == CSM_CONDITION_UNKNOWN) { key = NULL; } if (keyp != NULL) { *keyp = g_strdup (key); } if (condition_kindp != NULL) { *condition_kindp = kind; } return (kind != CSM_CONDITION_UNKNOWN); } static void if_exists_condition_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event, CsmApp *app) { CsmAutostartAppPrivate *priv; gboolean condition = FALSE; priv = CSM_AUTOSTART_APP (app)->priv; switch (event) { case G_FILE_MONITOR_EVENT_CREATED: condition = TRUE; break; case G_FILE_MONITOR_EVENT_DELETED: condition = FALSE; break; default: /* Ignore any other monitor event */ return; } /* Emit only if the condition actually changed */ if (condition != priv->condition) { priv->condition = condition; g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition); } } static void unless_exists_condition_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event, CsmApp *app) { CsmAutostartAppPrivate *priv; gboolean condition = FALSE; priv = CSM_AUTOSTART_APP (app)->priv; switch (event) { case G_FILE_MONITOR_EVENT_CREATED: condition = FALSE; break; case G_FILE_MONITOR_EVENT_DELETED: condition = TRUE; break; default: /* Ignore any other monitor event */ return; } /* Emit only if the condition actually changed */ if (condition != priv->condition) { priv->condition = condition; g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition); } } #ifdef HAVE_GCONF static void gconf_condition_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry, gpointer user_data) { CsmApp *app; CsmAutostartAppPrivate *priv; gboolean condition; g_return_if_fail (CSM_IS_APP (user_data)); app = CSM_APP (user_data); priv = CSM_AUTOSTART_APP (app)->priv; condition = FALSE; if (entry->value != NULL && entry->value->type == GCONF_VALUE_BOOL) { condition = gconf_value_get_bool (entry->value); } g_debug ("CsmAutostartApp: app:%s condition changed condition:%d", csm_app_peek_id (app), condition); /* Emit only if the condition actually changed */ if (condition != priv->condition) { priv->condition = condition; g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition); } } #endif static void gsettings_condition_cb (GSettings *settings, const char *key, gpointer user_data) { CsmApp *app; CsmAutostartAppPrivate *priv; gboolean condition; g_return_if_fail (CSM_IS_APP (user_data)); app = CSM_APP (user_data); priv = CSM_AUTOSTART_APP (app)->priv; condition = g_settings_get_boolean (settings, key); g_debug ("CsmAutostartApp: app:%s condition changed condition:%d", csm_app_peek_id (app), condition); /* Emit only if the condition actually changed */ if (condition != priv->condition) { priv->condition = condition; g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition); } } static gboolean setup_gsettings_condition_monitor (CsmAutostartApp *app, const char *key) { GSettingsSchemaSource *source; GSettingsSchema *schema; GSettings *settings; char **elems; gboolean retval = FALSE; char *signal; retval = FALSE; elems = g_strsplit (key, " ", 2); if (elems == NULL) goto out; if (elems[0] == NULL || elems[1] == NULL) goto out; source = g_settings_schema_source_get_default (); schema = g_settings_schema_source_lookup (source, elems[0], TRUE); if (schema == NULL) goto out; settings = g_settings_new_full (schema, NULL, NULL); retval = g_settings_get_boolean (settings, elems[1]); g_settings_schema_unref (schema); signal = g_strdup_printf ("changed::%s", elems[1]); g_signal_connect (G_OBJECT (settings), signal, G_CALLBACK (gsettings_condition_cb), app); g_free (signal); app->priv->condition_settings = settings; out: g_strfreev (elems); return retval; } static void if_session_condition_cb (GObject *object, GParamSpec *pspec, gpointer user_data) { CsmApp *app; CsmAutostartAppPrivate *priv; char *session_name; char *key; gboolean condition; g_return_if_fail (CSM_IS_APP (user_data)); app = CSM_APP (user_data); priv = CSM_AUTOSTART_APP (app)->priv; parse_condition_string (priv->condition_string, NULL, &key); g_object_get (object, "session-name", &session_name, NULL); condition = strcmp (session_name, key) == 0; g_free (session_name); g_free (key); g_debug ("CsmAutostartApp: app:%s condition changed condition:%d", csm_app_peek_id (app), condition); /* Emit only if the condition actually changed */ if (condition != priv->condition) { priv->condition = condition; g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition); } } static void unless_session_condition_cb (GObject *object, GParamSpec *pspec, gpointer user_data) { CsmApp *app; CsmAutostartAppPrivate *priv; char *session_name; char *key; gboolean condition; g_return_if_fail (CSM_IS_APP (user_data)); app = CSM_APP (user_data); priv = CSM_AUTOSTART_APP (app)->priv; parse_condition_string (priv->condition_string, NULL, &key); g_object_get (object, "session-name", &session_name, NULL); condition = strcmp (session_name, key) != 0; g_free (session_name); g_free (key); g_debug ("CsmAutostartApp: app:%s condition changed condition:%d", csm_app_peek_id (app), condition); /* Emit only if the condition actually changed */ if (condition != priv->condition) { priv->condition = condition; g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition); } } static void setup_condition_monitor (CsmAutostartApp *app) { guint kind; char *key; gboolean res; gboolean disabled; if (app->priv->condition_monitor != NULL) { g_file_monitor_cancel (app->priv->condition_monitor); } #ifdef HAVE_GCONF if (app->priv->condition_notify_id > 0) { GConfClient *client; client = gconf_client_get_default (); gconf_client_notify_remove (client, app->priv->condition_notify_id); app->priv->condition_notify_id = 0; } #endif if (app->priv->condition_string == NULL) { return; } /* if it is disabled outright there is no point in monitoring */ if (is_disabled (CSM_APP (app))) { return; } key = NULL; res = parse_condition_string (app->priv->condition_string, &kind, &key); if (! res) { g_free (key); return; } if (key == NULL) { return; } if (kind == CSM_CONDITION_IF_EXISTS) { char *file_path; GFile *file; file_path = g_build_filename (g_get_user_config_dir (), key, NULL); disabled = !g_file_test (file_path, G_FILE_TEST_EXISTS); file = g_file_new_for_path (file_path); app->priv->condition_monitor = g_file_monitor_file (file, 0, NULL, NULL); g_signal_connect (app->priv->condition_monitor, "changed", G_CALLBACK (if_exists_condition_cb), app); g_object_unref (file); g_free (file_path); } else if (kind == CSM_CONDITION_UNLESS_EXISTS) { char *file_path; GFile *file; file_path = g_build_filename (g_get_user_config_dir (), key, NULL); disabled = g_file_test (file_path, G_FILE_TEST_EXISTS); file = g_file_new_for_path (file_path); app->priv->condition_monitor = g_file_monitor_file (file, 0, NULL, NULL); g_signal_connect (app->priv->condition_monitor, "changed", G_CALLBACK (unless_exists_condition_cb), app); g_object_unref (file); g_free (file_path); #ifdef HAVE_GCONF } else if (kind == CSM_CONDITION_GNOME) { GConfClient *client; char *dir; client = gconf_client_get_default (); g_assert (GCONF_IS_CLIENT (client)); disabled = !gconf_client_get_bool (client, key, NULL); dir = g_path_get_dirname (key); gconf_client_add_dir (client, dir, GCONF_CLIENT_PRELOAD_NONE, NULL); g_free (dir); app->priv->condition_notify_id = gconf_client_notify_add (client, key, gconf_condition_cb, app, NULL, NULL); g_object_unref (client); #endif } else if (kind == CSM_CONDITION_GSETTINGS) { disabled = !setup_gsettings_condition_monitor (app, key); } else if (kind == CSM_CONDITION_IF_SESSION) { CsmManager *manager; char *session_name; /* get the singleton */ manager = csm_manager_get (); g_object_get (manager, "session-name", &session_name, NULL); disabled = strcmp (session_name, key) != 0; g_signal_connect (manager, "notify::session-name", G_CALLBACK (if_session_condition_cb), app); g_free (session_name); } else if (kind == CSM_CONDITION_UNLESS_SESSION) { CsmManager *manager; char *session_name; /* get the singleton */ manager = csm_manager_get (); g_object_get (manager, "session-name", &session_name, NULL); disabled = strcmp (session_name, key) == 0; g_signal_connect (manager, "notify::session-name", G_CALLBACK (unless_session_condition_cb), app); g_free (session_name); } else { disabled = TRUE; } g_free (key); /* FIXME: cache the disabled value? */ } static gboolean load_desktop_file (CsmAutostartApp *app) { char *dbus_name; char *startup_id; char *phase_str; int phase; gboolean res; if (app->priv->desktop_file == NULL) { return FALSE; } phase_str = egg_desktop_file_get_string (app->priv->desktop_file, CSM_AUTOSTART_APP_PHASE_KEY, NULL); if (phase_str != NULL) { if (strcmp (phase_str, "EarlyInitialization") == 0) { phase = CSM_MANAGER_PHASE_EARLY_INITIALIZATION; } else if (strcmp (phase_str, "PreDisplayServer") == 0) { phase = CSM_MANAGER_PHASE_PRE_DISPLAY_SERVER; } else if (strcmp (phase_str, "Initialization") == 0) { phase = CSM_MANAGER_PHASE_INITIALIZATION; } else if (strcmp (phase_str, "WindowManager") == 0) { phase = CSM_MANAGER_PHASE_WINDOW_MANAGER; } else if (strcmp (phase_str, "Panel") == 0) { phase = CSM_MANAGER_PHASE_PANEL; } else if (strcmp (phase_str, "Desktop") == 0) { phase = CSM_MANAGER_PHASE_DESKTOP; } else { phase = CSM_MANAGER_PHASE_APPLICATION; } g_free (phase_str); } else { phase = CSM_MANAGER_PHASE_APPLICATION; } dbus_name = egg_desktop_file_get_string (app->priv->desktop_file, CSM_AUTOSTART_APP_DBUS_NAME_KEY, NULL); if (dbus_name != NULL) { app->priv->launch_type = AUTOSTART_LAUNCH_ACTIVATE; } else { app->priv->launch_type = AUTOSTART_LAUNCH_SPAWN; } /* this must only be done on first load */ switch (app->priv->launch_type) { case AUTOSTART_LAUNCH_SPAWN: startup_id = egg_desktop_file_get_string (app->priv->desktop_file, CSM_AUTOSTART_APP_STARTUP_ID_KEY, NULL); if (startup_id == NULL) { startup_id = csm_util_generate_startup_id (); } break; case AUTOSTART_LAUNCH_ACTIVATE: startup_id = g_strdup (dbus_name); break; default: g_assert_not_reached (); } res = egg_desktop_file_has_key (app->priv->desktop_file, CSM_AUTOSTART_APP_AUTORESTART_KEY, NULL); if (res) { app->priv->autorestart = egg_desktop_file_get_boolean (app->priv->desktop_file, CSM_AUTOSTART_APP_AUTORESTART_KEY, NULL); } else { app->priv->autorestart = FALSE; } g_free (app->priv->condition_string); app->priv->condition_string = egg_desktop_file_get_string (app->priv->desktop_file, "AutostartCondition", NULL); setup_condition_monitor (app); if (phase == CSM_MANAGER_PHASE_APPLICATION) { /* Only accept an autostart delay for the application phase */ app->priv->autostart_delay = egg_desktop_file_get_integer (app->priv->desktop_file, CSM_AUTOSTART_APP_DELAY_KEY, NULL); if (app->priv->autostart_delay < 0) { g_warning ("Invalid autostart delay of %d for %s", app->priv->autostart_delay, csm_app_peek_id (CSM_APP (app))); app->priv->autostart_delay = -1; } } g_object_set (app, "phase", phase, "startup-id", startup_id, NULL); g_free (startup_id); g_free (dbus_name); return TRUE; } static void csm_autostart_app_set_desktop_filename (CsmAutostartApp *app, const char *desktop_filename) { GError *error; if (app->priv->desktop_file != NULL) { egg_desktop_file_free (app->priv->desktop_file); app->priv->desktop_file = NULL; g_free (app->priv->desktop_id); } if (desktop_filename == NULL) { return; } app->priv->desktop_id = g_path_get_basename (desktop_filename); error = NULL; app->priv->desktop_file = egg_desktop_file_new (desktop_filename, &error); if (app->priv->desktop_file == NULL) { g_warning ("Could not parse desktop file %s: %s", desktop_filename, error->message); g_error_free (error); return; } } static void csm_autostart_app_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsmAutostartApp *self; self = CSM_AUTOSTART_APP (object); switch (prop_id) { case PROP_DESKTOP_FILENAME: csm_autostart_app_set_desktop_filename (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_autostart_app_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsmAutostartApp *self; self = CSM_AUTOSTART_APP (object); switch (prop_id) { case PROP_DESKTOP_FILENAME: if (self->priv->desktop_file != NULL) { g_value_set_string (value, egg_desktop_file_get_source (self->priv->desktop_file)); } else { g_value_set_string (value, NULL); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_autostart_app_dispose (GObject *object) { CsmAutostartAppPrivate *priv; priv = CSM_AUTOSTART_APP (object)->priv; if (priv->startup_id) { g_free (priv->startup_id); priv->startup_id = NULL; } if (priv->session_provides) { g_slist_free_full (priv->session_provides, g_free); priv->session_provides = NULL; } if (priv->condition_string) { g_free (priv->condition_string); priv->condition_string = NULL; } if (priv->condition_settings) { g_object_unref (priv->condition_settings); priv->condition_settings = NULL; } if (priv->desktop_file) { egg_desktop_file_free (priv->desktop_file); priv->desktop_file = NULL; } if (priv->desktop_id) { g_free (priv->desktop_id); priv->desktop_id = NULL; } if (priv->child_watch_id > 0) { g_source_remove (priv->child_watch_id); priv->child_watch_id = 0; } if (priv->proxy_call != NULL) { dbus_g_proxy_cancel_call (priv->proxy, priv->proxy_call); priv->proxy_call = NULL; } if (priv->proxy != NULL) { g_object_unref (priv->proxy); priv->proxy = NULL; } if (priv->condition_monitor) { g_file_monitor_cancel (priv->condition_monitor); } G_OBJECT_CLASS (csm_autostart_app_parent_class)->dispose (object); } static gboolean is_running (CsmApp *app) { CsmAutostartAppPrivate *priv; gboolean is; priv = CSM_AUTOSTART_APP (app)->priv; /* is running if pid is still valid or * or a client is connected */ /* FIXME: check client */ is = (priv->pid != -1); return is; } static gboolean is_conditionally_disabled (CsmApp *app) { CsmAutostartAppPrivate *priv; gboolean res; gboolean disabled; char *key; guint kind; priv = CSM_AUTOSTART_APP (app)->priv; /* Check AutostartCondition */ if (priv->condition_string == NULL) { return FALSE; } key = NULL; res = parse_condition_string (priv->condition_string, &kind, &key); if (! res) { g_free (key); return TRUE; } if (key == NULL) { return TRUE; } if (kind == CSM_CONDITION_IF_EXISTS) { char *file_path; file_path = g_build_filename (g_get_user_config_dir (), key, NULL); disabled = !g_file_test (file_path, G_FILE_TEST_EXISTS); g_free (file_path); } else if (kind == CSM_CONDITION_UNLESS_EXISTS) { char *file_path; file_path = g_build_filename (g_get_user_config_dir (), key, NULL); disabled = g_file_test (file_path, G_FILE_TEST_EXISTS); g_free (file_path); #ifdef HAVE_GCONF } else if (kind == CSM_CONDITION_GNOME) { GConfClient *client; client = gconf_client_get_default (); g_assert (GCONF_IS_CLIENT (client)); disabled = !gconf_client_get_bool (client, key, NULL); g_object_unref (client); #endif } else if (kind == CSM_CONDITION_GSETTINGS && priv->condition_settings != NULL) { char **elems; elems = g_strsplit (key, " ", 2); disabled = !g_settings_get_boolean (priv->condition_settings, elems[1]); g_strfreev (elems); } else if (kind == CSM_CONDITION_IF_SESSION) { CsmManager *manager; char *session_name; /* get the singleton */ manager = csm_manager_get (); g_object_get (manager, "session-name", &session_name, NULL); disabled = strcmp (session_name, key) != 0; g_free (session_name); } else if (kind == CSM_CONDITION_UNLESS_SESSION) { CsmManager *manager; char *session_name; /* get the singleton */ manager = csm_manager_get (); g_object_get (manager, "session-name", &session_name, NULL); disabled = strcmp (session_name, key) == 0; g_free (session_name); } else { disabled = TRUE; } /* Set initial condition */ priv->condition = !disabled; g_free (key); return disabled; } static void app_exited (GPid pid, int status, CsmAutostartApp *app) { g_debug ("CsmAutostartApp: (pid:%d) done (%s:%d)", (int) pid, WIFEXITED (status) ? "status" : WIFSIGNALED (status) ? "signal" : "unknown", WIFEXITED (status) ? WEXITSTATUS (status) : WIFSIGNALED (status) ? WTERMSIG (status) : -1); g_spawn_close_pid (app->priv->pid); app->priv->pid = -1; app->priv->child_watch_id = 0; if (WIFEXITED (status)) { csm_app_exited (CSM_APP (app), WEXITSTATUS (status)); } else if (WIFSIGNALED (status)) { csm_app_died (CSM_APP (app), WTERMSIG (status)); } } static int _signal_pid (int pid, int signal) { int status = -1; /* perhaps block sigchld */ g_debug ("CsmAutostartApp: sending signal %d to process %d", signal, pid); errno = 0; status = kill (pid, signal); if (status < 0) { if (errno == ESRCH) { g_warning ("Child process %d was already dead.", (int)pid); } else { g_warning ("Couldn't kill child process %d: %s", pid, g_strerror (errno)); } } /* perhaps unblock sigchld */ return status; } static gboolean autostart_app_stop_spawn (CsmAutostartApp *app, GError **error) { int res; if (app->priv->pid < 1) { g_set_error (error, CSM_APP_ERROR, CSM_APP_ERROR_STOP, "Not running"); return FALSE; } res = _signal_pid (app->priv->pid, SIGTERM); if (res != 0) { g_set_error (error, CSM_APP_ERROR, CSM_APP_ERROR_STOP, "Unable to stop: %s", g_strerror (errno)); return FALSE; } return TRUE; } static gboolean autostart_app_stop_activate (CsmAutostartApp *app, GError **error) { return TRUE; } static gboolean csm_autostart_app_stop (CsmApp *app, GError **error) { CsmAutostartApp *aapp; gboolean ret; aapp = CSM_AUTOSTART_APP (app); g_return_val_if_fail (aapp->priv->desktop_file != NULL, FALSE); switch (aapp->priv->launch_type) { case AUTOSTART_LAUNCH_SPAWN: ret = autostart_app_stop_spawn (aapp, error); break; case AUTOSTART_LAUNCH_ACTIVATE: ret = autostart_app_stop_activate (aapp, error); break; default: g_assert_not_reached (); break; } return ret; } static gboolean autostart_app_start_spawn (CsmAutostartApp *app, GError **error) { char *env[2] = { NULL, NULL }; gboolean success; GError *local_error; const char *startup_id; char *command; startup_id = csm_app_peek_startup_id (CSM_APP (app)); g_assert (startup_id != NULL); env[0] = g_strdup_printf ("DESKTOP_AUTOSTART_ID=%s", startup_id); local_error = NULL; command = egg_desktop_file_parse_exec (app->priv->desktop_file, NULL, &local_error); if (command == NULL) { g_warning ("Unable to parse command from '%s': %s", egg_desktop_file_get_source (app->priv->desktop_file), local_error->message); g_error_free (local_error); } g_debug ("CsmAutostartApp: starting %s: command=%s startup-id=%s", app->priv->desktop_id, command, startup_id); g_free (command); g_free (app->priv->startup_id); local_error = NULL; success = egg_desktop_file_launch (app->priv->desktop_file, NULL, &local_error, EGG_DESKTOP_FILE_LAUNCH_PUTENV, env, EGG_DESKTOP_FILE_LAUNCH_FLAGS, G_SPAWN_DO_NOT_REAP_CHILD, EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, &app->priv->pid, EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID, &app->priv->startup_id, NULL); g_free (env[0]); if (success) { g_debug ("CsmAutostartApp: started pid:%d", app->priv->pid); app->priv->child_watch_id = g_child_watch_add (app->priv->pid, (GChildWatchFunc)app_exited, app); } else { g_set_error (error, CSM_APP_ERROR, CSM_APP_ERROR_START, "Unable to start application: %s", local_error->message); g_error_free (local_error); } return success; } static void start_notify (DBusGProxy *proxy, DBusGProxyCall *call, CsmAutostartApp *app) { gboolean res; GError *error; error = NULL; res = dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID); app->priv->proxy_call = NULL; if (! res) { g_warning ("CsmAutostartApp: Error starting application: %s", error->message); g_error_free (error); } else { g_debug ("CsmAutostartApp: Started application %s", app->priv->desktop_id); } } static gboolean autostart_app_start_activate (CsmAutostartApp *app, GError **error) { const char *name; char *path; char *arguments; DBusGConnection *bus; GError *local_error; local_error = NULL; bus = dbus_g_bus_get (DBUS_BUS_SESSION, &local_error); if (bus == NULL) { if (local_error != NULL) { g_warning ("error getting session bus: %s", local_error->message); } g_propagate_error (error, local_error); return FALSE; } name = csm_app_peek_startup_id (CSM_APP (app)); g_assert (name != NULL); path = egg_desktop_file_get_string (app->priv->desktop_file, CSM_AUTOSTART_APP_DBUS_PATH_KEY, NULL); if (path == NULL) { /* just pick one? */ path = g_strdup ("/"); } arguments = egg_desktop_file_get_string (app->priv->desktop_file, CSM_AUTOSTART_APP_DBUS_ARGS_KEY, NULL); app->priv->proxy = dbus_g_proxy_new_for_name (bus, name, path, CSM_SESSION_CLIENT_DBUS_INTERFACE); if (app->priv->proxy == NULL) { g_set_error (error, CSM_APP_ERROR, CSM_APP_ERROR_START, "Unable to start application: unable to create proxy for client"); return FALSE; } app->priv->proxy_call = dbus_g_proxy_begin_call (app->priv->proxy, "Start", (DBusGProxyCallNotify)start_notify, app, NULL, G_TYPE_STRING, arguments, G_TYPE_INVALID); if (app->priv->proxy_call == NULL) { g_object_unref (app->priv->proxy); app->priv->proxy = NULL; g_set_error (error, CSM_APP_ERROR, CSM_APP_ERROR_START, "Unable to start application: unable to call Start on client"); return FALSE; } return TRUE; } static gboolean csm_autostart_app_start (CsmApp *app, GError **error) { CsmAutostartApp *aapp; gboolean ret; aapp = CSM_AUTOSTART_APP (app); g_return_val_if_fail (aapp->priv->desktop_file != NULL, FALSE); switch (aapp->priv->launch_type) { case AUTOSTART_LAUNCH_SPAWN: ret = autostart_app_start_spawn (aapp, error); break; case AUTOSTART_LAUNCH_ACTIVATE: ret = autostart_app_start_activate (aapp, error); break; default: g_assert_not_reached (); break; } return ret; } static gboolean csm_autostart_app_restart (CsmApp *app, GError **error) { GError *local_error; gboolean res; /* ignore stop errors - it is fine if it is already stopped */ local_error = NULL; res = csm_app_stop (app, &local_error); if (! res) { g_debug ("CsmAutostartApp: Couldn't stop app: %s", local_error->message); g_error_free (local_error); } res = csm_app_start (app, &local_error); if (! res) { g_propagate_error (error, local_error); return FALSE; } return TRUE; } static gboolean csm_autostart_app_provides (CsmApp *app, const char *service) { char **provides; gsize len; gsize i; GSList *l; CsmAutostartApp *aapp; g_return_val_if_fail (CSM_IS_APP (app), FALSE); aapp = CSM_AUTOSTART_APP (app); if (aapp->priv->desktop_file == NULL) { return FALSE; } for (l = aapp->priv->session_provides; l != NULL; l = l->next) { if (!strcmp (l->data, service)) return TRUE; } provides = egg_desktop_file_get_string_list (aapp->priv->desktop_file, CSM_AUTOSTART_APP_PROVIDES_KEY, &len, NULL); if (!provides) { return FALSE; } for (i = 0; i < len; i++) { if (!strcmp (provides[i], service)) { g_strfreev (provides); return TRUE; } } g_strfreev (provides); return FALSE; } static char ** csm_autostart_app_get_provides (CsmApp *app) { CsmAutostartApp *aapp; char **provides; gsize provides_len; char **result; gsize result_len; int i; GSList *l; g_return_val_if_fail (CSM_IS_APP (app), NULL); aapp = CSM_AUTOSTART_APP (app); if (aapp->priv->desktop_file == NULL) { return NULL; } provides = egg_desktop_file_get_string_list (aapp->priv->desktop_file, CSM_AUTOSTART_APP_PROVIDES_KEY, &provides_len, NULL); if (!aapp->priv->session_provides) return provides; result_len = provides_len + g_slist_length (aapp->priv->session_provides); result = g_new (char *, result_len + 1); /* including last NULL */ for (i = 0; provides[i] != NULL; i++) result[i] = provides[i]; g_free (provides); for (l = aapp->priv->session_provides; l != NULL; l = l->next, i++) result[i] = g_strdup (l->data); result[i] = NULL; g_assert (i == result_len); return result; } void csm_autostart_app_add_provides (CsmAutostartApp *aapp, const char *provides) { g_return_if_fail (CSM_IS_AUTOSTART_APP (aapp)); aapp->priv->session_provides = g_slist_prepend (aapp->priv->session_provides, g_strdup (provides)); } static gboolean csm_autostart_app_has_autostart_condition (CsmApp *app, const char *condition) { CsmAutostartApp *aapp; g_return_val_if_fail (CSM_IS_APP (app), FALSE); g_return_val_if_fail (condition != NULL, FALSE); aapp = CSM_AUTOSTART_APP (app); if (aapp->priv->condition_string == NULL) { return FALSE; } if (strcmp (aapp->priv->condition_string, condition) == 0) { return TRUE; } return FALSE; } static gboolean csm_autostart_app_get_autorestart (CsmApp *app) { gboolean res; gboolean autorestart; if (CSM_AUTOSTART_APP (app)->priv->desktop_file == NULL) { return FALSE; } autorestart = FALSE; res = egg_desktop_file_has_key (CSM_AUTOSTART_APP (app)->priv->desktop_file, CSM_AUTOSTART_APP_AUTORESTART_KEY, NULL); if (res) { autorestart = egg_desktop_file_get_boolean (CSM_AUTOSTART_APP (app)->priv->desktop_file, CSM_AUTOSTART_APP_AUTORESTART_KEY, NULL); } return autorestart; } static const char * csm_autostart_app_get_app_id (CsmApp *app) { const char *location; const char *slash; if (CSM_AUTOSTART_APP (app)->priv->desktop_file == NULL) { return NULL; } location = egg_desktop_file_get_source (CSM_AUTOSTART_APP (app)->priv->desktop_file); slash = strrchr (location, '/'); if (slash != NULL) { return slash + 1; } else { return location; } } static int csm_autostart_app_peek_autostart_delay (CsmApp *app) { CsmAutostartApp *aapp = CSM_AUTOSTART_APP (app); return aapp->priv->autostart_delay; } static GObject * csm_autostart_app_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsmAutostartApp *app; app = CSM_AUTOSTART_APP (G_OBJECT_CLASS (csm_autostart_app_parent_class)->constructor (type, n_construct_properties, construct_properties)); if (! load_desktop_file (app)) { g_object_unref (app); app = NULL; } return G_OBJECT (app); } static void csm_autostart_app_class_init (CsmAutostartAppClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CsmAppClass *app_class = CSM_APP_CLASS (klass); object_class->set_property = csm_autostart_app_set_property; object_class->get_property = csm_autostart_app_get_property; object_class->dispose = csm_autostart_app_dispose; object_class->constructor = csm_autostart_app_constructor; app_class->impl_is_disabled = is_disabled; app_class->impl_is_conditionally_disabled = is_conditionally_disabled; app_class->impl_is_running = is_running; app_class->impl_start = csm_autostart_app_start; app_class->impl_restart = csm_autostart_app_restart; app_class->impl_stop = csm_autostart_app_stop; app_class->impl_provides = csm_autostart_app_provides; app_class->impl_get_provides = csm_autostart_app_get_provides; app_class->impl_has_autostart_condition = csm_autostart_app_has_autostart_condition; app_class->impl_get_app_id = csm_autostart_app_get_app_id; app_class->impl_get_autorestart = csm_autostart_app_get_autorestart; app_class->impl_peek_autostart_delay = csm_autostart_app_peek_autostart_delay; g_object_class_install_property (object_class, PROP_DESKTOP_FILENAME, g_param_spec_string ("desktop-filename", "Desktop filename", "Freedesktop .desktop file", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); signals[CONDITION_CHANGED] = g_signal_new ("condition-changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmAutostartAppClass, condition_changed), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); g_type_class_add_private (object_class, sizeof (CsmAutostartAppPrivate)); } CsmApp * csm_autostart_app_new (const char *desktop_file) { CsmAutostartApp *app; app = g_object_new (CSM_TYPE_AUTOSTART_APP, "desktop-filename", desktop_file, NULL); return CSM_APP (app); } cinnamon-session-3.6.1/cinnamon-session/csm-autostart-app.h0000644000175000017500000000612013205266677022557 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Novell, Inc. * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_AUTOSTART_APP_H__ #define __CSM_AUTOSTART_APP_H__ #include "csm-app.h" #include G_BEGIN_DECLS #define CSM_TYPE_AUTOSTART_APP (csm_autostart_app_get_type ()) #define CSM_AUTOSTART_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSM_TYPE_AUTOSTART_APP, CsmAutostartApp)) #define CSM_AUTOSTART_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSM_TYPE_AUTOSTART_APP, CsmAutostartAppClass)) #define CSM_IS_AUTOSTART_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSM_TYPE_AUTOSTART_APP)) #define CSM_IS_AUTOSTART_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSM_TYPE_AUTOSTART_APP)) #define CSM_AUTOSTART_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CSM_TYPE_AUTOSTART_APP, CsmAutostartAppClass)) typedef struct _CsmAutostartApp CsmAutostartApp; typedef struct _CsmAutostartAppClass CsmAutostartAppClass; typedef struct _CsmAutostartAppPrivate CsmAutostartAppPrivate; struct _CsmAutostartApp { CsmApp parent; CsmAutostartAppPrivate *priv; }; struct _CsmAutostartAppClass { CsmAppClass parent_class; /* signals */ void (*condition_changed) (CsmApp *app, gboolean condition); }; GType csm_autostart_app_get_type (void) G_GNUC_CONST; CsmApp *csm_autostart_app_new (const char *desktop_file); void csm_autostart_app_add_provides (CsmAutostartApp *aapp, const char *provides); #define CSM_AUTOSTART_APP_ENABLED_KEY "X-GNOME-Autostart-enabled" #define CSM_AUTOSTART_APP_PHASE_KEY "X-GNOME-Autostart-Phase" #define CSM_AUTOSTART_APP_PROVIDES_KEY "X-GNOME-Provides" #define CSM_AUTOSTART_APP_STARTUP_ID_KEY "X-GNOME-Autostart-startup-id" #define CSM_AUTOSTART_APP_AUTORESTART_KEY "X-GNOME-AutoRestart" #define CSM_AUTOSTART_APP_DBUS_NAME_KEY "X-GNOME-DBus-Name" #define CSM_AUTOSTART_APP_DBUS_PATH_KEY "X-GNOME-DBus-Path" #define CSM_AUTOSTART_APP_DBUS_ARGS_KEY "X-GNOME-DBus-Start-Arguments" #define CSM_AUTOSTART_APP_DISCARD_KEY "X-GNOME-Autostart-discard-exec" #define CSM_AUTOSTART_APP_DELAY_KEY "X-GNOME-Autostart-Delay" G_END_DECLS #endif /* __CSM_AUTOSTART_APP_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-client.c0000644000175000017500000003752713205266677021243 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Novell, Inc. * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include "config.h" #include #include "eggdesktopfile.h" #include "csm-marshal.h" #include "csm-client.h" #include "csm-client-glue.h" static guint32 client_serial = 1; #define CSM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_CLIENT, CsmClientPrivate)) struct CsmClientPrivate { char *id; char *startup_id; char *app_id; guint status; DBusGConnection *connection; }; enum { PROP_0, PROP_ID, PROP_STARTUP_ID, PROP_APP_ID, PROP_STATUS }; enum { DISCONNECTED, END_SESSION_RESPONSE, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_ABSTRACT_TYPE (CsmClient, csm_client, G_TYPE_OBJECT) GQuark csm_client_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("csm_client_error"); } return ret; } #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } GType csm_client_error_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { ENUM_ENTRY (CSM_CLIENT_ERROR_GENERAL, "GeneralError"), ENUM_ENTRY (CSM_CLIENT_ERROR_NOT_REGISTERED, "NotRegistered"), { 0, 0, 0 } }; g_assert (CSM_CLIENT_NUM_ERRORS == G_N_ELEMENTS (values) - 1); etype = g_enum_register_static ("CsmClientError", values); } return etype; } static guint32 get_next_client_serial (void) { guint32 serial; serial = client_serial++; if ((gint32)client_serial < 0) { client_serial = 1; } return serial; } static gboolean register_client (CsmClient *client) { GError *error; error = NULL; client->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (client->priv->connection == NULL) { if (error != NULL) { g_critical ("error getting session bus: %s", error->message); g_error_free (error); } return FALSE; } dbus_g_connection_register_g_object (client->priv->connection, client->priv->id, G_OBJECT (client)); return TRUE; } static GObject * csm_client_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsmClient *client; gboolean res; client = CSM_CLIENT (G_OBJECT_CLASS (csm_client_parent_class)->constructor (type, n_construct_properties, construct_properties)); g_free (client->priv->id); client->priv->id = g_strdup_printf ("/org/gnome/SessionManager/Client%u", get_next_client_serial ()); res = register_client (client); if (! res) { g_warning ("Unable to register client with session bus"); } return G_OBJECT (client); } static void csm_client_init (CsmClient *client) { client->priv = CSM_CLIENT_GET_PRIVATE (client); } static void csm_client_finalize (GObject *object) { CsmClient *client; g_return_if_fail (object != NULL); g_return_if_fail (CSM_IS_CLIENT (object)); client = CSM_CLIENT (object); g_return_if_fail (client->priv != NULL); g_free (client->priv->id); g_free (client->priv->startup_id); g_free (client->priv->app_id); G_OBJECT_CLASS (csm_client_parent_class)->finalize (object); } void csm_client_set_status (CsmClient *client, guint status) { g_return_if_fail (CSM_IS_CLIENT (client)); if (client->priv->status != status) { client->priv->status = status; g_object_notify (G_OBJECT (client), "status"); } } static void csm_client_set_startup_id (CsmClient *client, const char *startup_id) { g_return_if_fail (CSM_IS_CLIENT (client)); g_free (client->priv->startup_id); if (startup_id != NULL) { client->priv->startup_id = g_strdup (startup_id); } else { client->priv->startup_id = g_strdup (""); } g_object_notify (G_OBJECT (client), "startup-id"); } void csm_client_set_app_id (CsmClient *client, const char *app_id) { g_return_if_fail (CSM_IS_CLIENT (client)); g_free (client->priv->app_id); if (app_id != NULL) { client->priv->app_id = g_strdup (app_id); } else { client->priv->app_id = g_strdup (""); } g_object_notify (G_OBJECT (client), "app-id"); } static void csm_client_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsmClient *self; self = CSM_CLIENT (object); switch (prop_id) { case PROP_STARTUP_ID: csm_client_set_startup_id (self, g_value_get_string (value)); break; case PROP_APP_ID: csm_client_set_app_id (self, g_value_get_string (value)); break; case PROP_STATUS: csm_client_set_status (self, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsmClient *self; self = CSM_CLIENT (object); switch (prop_id) { case PROP_STARTUP_ID: g_value_set_string (value, self->priv->startup_id); break; case PROP_APP_ID: g_value_set_string (value, self->priv->app_id); break; case PROP_STATUS: g_value_set_uint (value, self->priv->status); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean default_stop (CsmClient *client, GError **error) { g_return_val_if_fail (CSM_IS_CLIENT (client), FALSE); g_warning ("Stop not implemented"); return TRUE; } static void csm_client_dispose (GObject *object) { CsmClient *client; g_return_if_fail (object != NULL); g_return_if_fail (CSM_IS_CLIENT (object)); client = CSM_CLIENT (object); g_debug ("CsmClient: disposing %s", client->priv->id); G_OBJECT_CLASS (csm_client_parent_class)->dispose (object); } static void csm_client_class_init (CsmClientClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = csm_client_get_property; object_class->set_property = csm_client_set_property; object_class->constructor = csm_client_constructor; object_class->finalize = csm_client_finalize; object_class->dispose = csm_client_dispose; klass->impl_stop = default_stop; signals[DISCONNECTED] = g_signal_new ("disconnected", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmClientClass, disconnected), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[END_SESSION_RESPONSE] = g_signal_new ("end-session-response", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmClientClass, end_session_response), NULL, NULL, csm_marshal_VOID__BOOLEAN_BOOLEAN_BOOLEAN_STRING, G_TYPE_NONE, 4, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING); g_object_class_install_property (object_class, PROP_STARTUP_ID, g_param_spec_string ("startup-id", "startup-id", "startup-id", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_APP_ID, g_param_spec_string ("app-id", "app-id", "app-id", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_STATUS, g_param_spec_uint ("status", "status", "status", 0, G_MAXINT, CSM_CLIENT_UNREGISTERED, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (CsmClientPrivate)); dbus_g_object_type_install_info (CSM_TYPE_CLIENT, &dbus_glib_csm_client_object_info); } const char * csm_client_peek_id (CsmClient *client) { g_return_val_if_fail (CSM_IS_CLIENT (client), NULL); return client->priv->id; } /** * csm_client_peek_app_id: * @client: a #CsmClient. * * Note that the application ID might not be known; this happens when for XSMP * clients that we did not start ourselves, for instance. * * Returns: the application ID of the client, or %NULL if no such ID is * known. The string is owned by @client. **/ const char * csm_client_peek_app_id (CsmClient *client) { g_return_val_if_fail (CSM_IS_CLIENT (client), NULL); return client->priv->app_id; } const char * csm_client_peek_startup_id (CsmClient *client) { g_return_val_if_fail (CSM_IS_CLIENT (client), NULL); return client->priv->startup_id; } guint csm_client_peek_status (CsmClient *client) { g_return_val_if_fail (CSM_IS_CLIENT (client), CSM_CLIENT_UNREGISTERED); return client->priv->status; } guint csm_client_peek_restart_style_hint (CsmClient *client) { g_return_val_if_fail (CSM_IS_CLIENT (client), CSM_CLIENT_RESTART_NEVER); return CSM_CLIENT_GET_CLASS (client)->impl_get_restart_style_hint (client); } gboolean csm_client_get_startup_id (CsmClient *client, char **id, GError **error) { g_return_val_if_fail (CSM_IS_CLIENT (client), FALSE); *id = g_strdup (client->priv->startup_id); return TRUE; } gboolean csm_client_get_app_id (CsmClient *client, char **id, GError **error) { g_return_val_if_fail (CSM_IS_CLIENT (client), FALSE); *id = g_strdup (client->priv->app_id); return TRUE; } gboolean csm_client_get_restart_style_hint (CsmClient *client, guint *hint, GError **error) { g_return_val_if_fail (CSM_IS_CLIENT (client), FALSE); *hint = CSM_CLIENT_GET_CLASS (client)->impl_get_restart_style_hint (client); return TRUE; } gboolean csm_client_get_status (CsmClient *client, guint *status, GError **error) { g_return_val_if_fail (CSM_IS_CLIENT (client), FALSE); *status = client->priv->status; return TRUE; } gboolean csm_client_get_unix_process_id (CsmClient *client, guint *pid, GError **error) { g_return_val_if_fail (CSM_IS_CLIENT (client), FALSE); *pid = CSM_CLIENT_GET_CLASS (client)->impl_get_unix_process_id (client); return TRUE; } /** * csm_client_get_app_name: * @client: a #CsmClient. * * Returns: a copy of the application name of the client, or %NULL if no such * name is known. **/ char * csm_client_get_app_name (CsmClient *client) { g_return_val_if_fail (CSM_IS_CLIENT (client), NULL); return CSM_CLIENT_GET_CLASS (client)->impl_get_app_name (client); } gboolean csm_client_cancel_end_session (CsmClient *client, GError **error) { g_return_val_if_fail (CSM_IS_CLIENT (client), FALSE); return CSM_CLIENT_GET_CLASS (client)->impl_cancel_end_session (client, error); } gboolean csm_client_query_end_session (CsmClient *client, guint flags, GError **error) { g_return_val_if_fail (CSM_IS_CLIENT (client), FALSE); return CSM_CLIENT_GET_CLASS (client)->impl_query_end_session (client, flags, error); } gboolean csm_client_end_session (CsmClient *client, guint flags, GError **error) { g_return_val_if_fail (CSM_IS_CLIENT (client), FALSE); return CSM_CLIENT_GET_CLASS (client)->impl_end_session (client, flags, error); } gboolean csm_client_stop (CsmClient *client, GError **error) { g_return_val_if_fail (CSM_IS_CLIENT (client), FALSE); return CSM_CLIENT_GET_CLASS (client)->impl_stop (client, error); } void csm_client_disconnected (CsmClient *client) { g_signal_emit (client, signals[DISCONNECTED], 0); } GKeyFile * csm_client_save (CsmClient *client, GError **error) { g_return_val_if_fail (CSM_IS_CLIENT (client), FALSE); return CSM_CLIENT_GET_CLASS (client)->impl_save (client, error); } void csm_client_end_session_response (CsmClient *client, gboolean is_ok, gboolean do_last, gboolean cancel, const char *reason) { g_signal_emit (client, signals[END_SESSION_RESPONSE], 0, is_ok, do_last, cancel, reason); } cinnamon-session-3.6.1/cinnamon-session/csm-client.h0000644000175000017500000001775513205266677021251 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Novell, Inc. * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_CLIENT_H__ #define __CSM_CLIENT_H__ #include #include #include G_BEGIN_DECLS #define CSM_TYPE_CLIENT (csm_client_get_type ()) #define CSM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSM_TYPE_CLIENT, CsmClient)) #define CSM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSM_TYPE_CLIENT, CsmClientClass)) #define CSM_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSM_TYPE_CLIENT)) #define CSM_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSM_TYPE_CLIENT)) #define CSM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CSM_TYPE_CLIENT, CsmClientClass)) typedef struct _CsmClient CsmClient; typedef struct _CsmClientClass CsmClientClass; typedef struct CsmClientPrivate CsmClientPrivate; typedef enum { CSM_CLIENT_UNREGISTERED = 0, CSM_CLIENT_REGISTERED, CSM_CLIENT_FINISHED, CSM_CLIENT_FAILED } CsmClientStatus; typedef enum { CSM_CLIENT_RESTART_NEVER = 0, CSM_CLIENT_RESTART_IF_RUNNING, CSM_CLIENT_RESTART_ANYWAY, CSM_CLIENT_RESTART_IMMEDIATELY } CsmClientRestartStyle; typedef enum { CSM_CLIENT_END_SESSION_FLAG_FORCEFUL = 1 << 0, CSM_CLIENT_END_SESSION_FLAG_SAVE = 1 << 1, CSM_CLIENT_END_SESSION_FLAG_LAST = 1 << 2 } CsmClientEndSessionFlag; struct _CsmClient { GObject parent; CsmClientPrivate *priv; }; struct _CsmClientClass { GObjectClass parent_class; /* signals */ void (*disconnected) (CsmClient *client); void (*end_session_response) (CsmClient *client, gboolean ok, gboolean do_last, gboolean cancel, const char *reason); /* virtual methods */ char * (*impl_get_app_name) (CsmClient *client); CsmClientRestartStyle (*impl_get_restart_style_hint) (CsmClient *client); guint (*impl_get_unix_process_id) (CsmClient *client); gboolean (*impl_query_end_session) (CsmClient *client, guint flags, GError **error); gboolean (*impl_end_session) (CsmClient *client, guint flags, GError **error); gboolean (*impl_cancel_end_session) (CsmClient *client, GError **error); gboolean (*impl_stop) (CsmClient *client, GError **error); GKeyFile * (*impl_save) (CsmClient *client, GError **error); }; typedef enum { CSM_CLIENT_ERROR_GENERAL = 0, CSM_CLIENT_ERROR_NOT_REGISTERED, CSM_CLIENT_NUM_ERRORS } CsmClientError; #define CSM_CLIENT_ERROR csm_client_error_quark () #define CSM_CLIENT_TYPE_ERROR (csm_client_error_get_type ()) GType csm_client_error_get_type (void); GQuark csm_client_error_quark (void); GType csm_client_get_type (void) G_GNUC_CONST; const char *csm_client_peek_id (CsmClient *client); const char * csm_client_peek_startup_id (CsmClient *client); const char * csm_client_peek_app_id (CsmClient *client); guint csm_client_peek_restart_style_hint (CsmClient *client); guint csm_client_peek_status (CsmClient *client); char *csm_client_get_app_name (CsmClient *client); void csm_client_set_app_id (CsmClient *client, const char *app_id); void csm_client_set_status (CsmClient *client, guint status); gboolean csm_client_end_session (CsmClient *client, guint flags, GError **error); gboolean csm_client_query_end_session (CsmClient *client, guint flags, GError **error); gboolean csm_client_cancel_end_session (CsmClient *client, GError **error); void csm_client_disconnected (CsmClient *client); GKeyFile *csm_client_save (CsmClient *client, GError **error); /* exported to bus */ gboolean csm_client_stop (CsmClient *client, GError **error); gboolean csm_client_get_startup_id (CsmClient *client, char **startup_id, GError **error); gboolean csm_client_get_app_id (CsmClient *client, char **app_id, GError **error); gboolean csm_client_get_restart_style_hint (CsmClient *client, guint *hint, GError **error); gboolean csm_client_get_status (CsmClient *client, guint *status, GError **error); gboolean csm_client_get_unix_process_id (CsmClient *client, guint *pid, GError **error); /* private */ void csm_client_end_session_response (CsmClient *client, gboolean is_ok, gboolean do_last, gboolean cancel, const char *reason); G_END_DECLS #endif /* __CSM_CLIENT_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-consolekit.c0000644000175000017500000007076013205266677022133 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #ifdef HAVE_OLD_UPOWER #define UPOWER_ENABLE_DEPRECATED 1 #include #endif #include "csm-system.h" #include "csm-consolekit.h" #define CK_NAME "org.freedesktop.ConsoleKit" #define CK_PATH "/org/freedesktop/ConsoleKit" #define CK_INTERFACE "org.freedesktop.ConsoleKit" #define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager" #define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager" #define CK_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat" #define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session" #define CSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW "LoginWindow" #define CSM_CONSOLEKIT_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_CONSOLEKIT, CsmConsolekitPrivate)) struct _CsmConsolekitPrivate { DBusGConnection *dbus_connection; DBusGProxy *bus_proxy; DBusGProxy *ck_proxy; #ifdef HAVE_OLD_UPOWER UpClient *up_client; #endif }; static void csm_consolekit_finalize (GObject *object); static void csm_consolekit_free_dbus (CsmConsolekit *manager); static DBusHandlerResult csm_consolekit_dbus_filter (DBusConnection *connection, DBusMessage *message, void *user_data); static void csm_consolekit_on_name_owner_changed (DBusGProxy *bus_proxy, const char *name, const char *prev_owner, const char *new_owner, CsmConsolekit *manager); static void csm_consolekit_system_init (CsmSystemInterface *iface); G_DEFINE_TYPE_WITH_CODE (CsmConsolekit, csm_consolekit, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (CSM_TYPE_SYSTEM, csm_consolekit_system_init)) static void csm_consolekit_class_init (CsmConsolekitClass *manager_class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (manager_class); object_class->finalize = csm_consolekit_finalize; g_type_class_add_private (manager_class, sizeof (CsmConsolekitPrivate)); } static DBusHandlerResult csm_consolekit_dbus_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { CsmConsolekit *manager; manager = CSM_CONSOLEKIT (user_data); if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") && strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) { csm_consolekit_free_dbus (manager); /* let other filters get this disconnected signal, so that they * can handle it too */ } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static gboolean csm_consolekit_ensure_ck_connection (CsmConsolekit *manager, GError **error) { GError *connection_error; gboolean is_connected; connection_error = NULL; if (manager->priv->dbus_connection == NULL) { DBusConnection *connection; manager->priv->dbus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &connection_error); if (manager->priv->dbus_connection == NULL) { g_propagate_error (error, connection_error); is_connected = FALSE; goto out; } connection = dbus_g_connection_get_connection (manager->priv->dbus_connection); dbus_connection_set_exit_on_disconnect (connection, FALSE); dbus_connection_add_filter (connection, csm_consolekit_dbus_filter, manager, NULL); } if (manager->priv->bus_proxy == NULL) { manager->priv->bus_proxy = dbus_g_proxy_new_for_name_owner (manager->priv->dbus_connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, &connection_error); if (manager->priv->bus_proxy == NULL) { g_propagate_error (error, connection_error); is_connected = FALSE; goto out; } dbus_g_proxy_add_signal (manager->priv->bus_proxy, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal (manager->priv->bus_proxy, "NameOwnerChanged", G_CALLBACK (csm_consolekit_on_name_owner_changed), manager, NULL); } if (manager->priv->ck_proxy == NULL) { manager->priv->ck_proxy = dbus_g_proxy_new_for_name_owner (manager->priv->dbus_connection, "org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit.Manager", &connection_error); if (manager->priv->ck_proxy == NULL) { g_propagate_error (error, connection_error); is_connected = FALSE; goto out; } } #ifdef HAVE_OLD_UPOWER g_clear_object (&manager->priv->up_client); manager->priv->up_client = up_client_new (); #endif is_connected = TRUE; out: if (!is_connected) { if (manager->priv->dbus_connection == NULL) { if (manager->priv->bus_proxy != NULL) { g_object_unref (manager->priv->bus_proxy); manager->priv->bus_proxy = NULL; } if (manager->priv->ck_proxy != NULL) { g_object_unref (manager->priv->ck_proxy); manager->priv->ck_proxy = NULL; } } else if (manager->priv->bus_proxy == NULL) { if (manager->priv->ck_proxy != NULL) { g_object_unref (manager->priv->ck_proxy); manager->priv->ck_proxy = NULL; } } } return is_connected; } static void csm_consolekit_on_name_owner_changed (DBusGProxy *bus_proxy, const char *name, const char *prev_owner, const char *new_owner, CsmConsolekit *manager) { if (name != NULL && strcmp (name, "org.freedesktop.ConsoleKit") != 0) { return; } g_clear_object (&manager->priv->ck_proxy); csm_consolekit_ensure_ck_connection (manager, NULL); } static void csm_consolekit_init (CsmConsolekit *manager) { GError *error; manager->priv = CSM_CONSOLEKIT_GET_PRIVATE (manager); error = NULL; if (!csm_consolekit_ensure_ck_connection (manager, &error)) { g_warning ("Could not connect to ConsoleKit: %s", error->message); g_error_free (error); } } static void csm_consolekit_free_dbus (CsmConsolekit *manager) { g_clear_object (&manager->priv->bus_proxy); g_clear_object (&manager->priv->ck_proxy); #ifdef HAVE_OLD_UPOWER g_clear_object (&manager->priv->up_client); #endif if (manager->priv->dbus_connection != NULL) { DBusConnection *connection; connection = dbus_g_connection_get_connection (manager->priv->dbus_connection); dbus_connection_remove_filter (connection, csm_consolekit_dbus_filter, manager); dbus_g_connection_unref (manager->priv->dbus_connection); manager->priv->dbus_connection = NULL; } } static void csm_consolekit_finalize (GObject *object) { CsmConsolekit *manager; GObjectClass *parent_class; manager = CSM_CONSOLEKIT (object); parent_class = G_OBJECT_CLASS (csm_consolekit_parent_class); csm_consolekit_free_dbus (manager); if (parent_class->finalize != NULL) { parent_class->finalize (object); } } static void csm_consolekit_attempt_restart (CsmSystem *system) { CsmConsolekit *manager = CSM_CONSOLEKIT (system); gboolean res; GError *error; error = NULL; g_warning ("Attempting to restart using consolekit..."); if (!csm_consolekit_ensure_ck_connection (manager, &error)) { g_warning ("Could not connect to ConsoleKit: %s", error->message); g_signal_emit_by_name (G_OBJECT (manager), "request-failed", NULL); g_error_free (error); return; } res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy, "Restart", INT_MAX, &error, G_TYPE_INVALID, G_TYPE_INVALID); if (!res) { g_warning ("Unable to restart system via consolekit: %s", error->message); g_signal_emit_by_name (G_OBJECT (manager), "request-failed", NULL); g_error_free (error); } } static void csm_consolekit_attempt_stop (CsmSystem *system) { CsmConsolekit *manager = CSM_CONSOLEKIT (system); gboolean res; GError *error; error = NULL; g_warning ("Attempting to shutdown using consolekit..."); if (!csm_consolekit_ensure_ck_connection (manager, &error)) { g_warning ("Could not connect to ConsoleKit: %s", error->message); g_signal_emit_by_name (G_OBJECT (manager), "request-failed", NULL); g_error_free (error); return; } res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy, "Stop", INT_MAX, &error, G_TYPE_INVALID, G_TYPE_INVALID); if (!res) { g_warning ("Unable to stop system via consolekit: %s", error->message); g_signal_emit_by_name (G_OBJECT (manager), "request-failed", NULL); g_error_free (error); } } static gboolean get_current_session_id (DBusConnection *connection, char **session_id) { DBusError local_error; DBusMessage *message; DBusMessage *reply; gboolean ret; DBusMessageIter iter; const char *value; ret = FALSE; reply = NULL; dbus_error_init (&local_error); message = dbus_message_new_method_call (CK_NAME, CK_MANAGER_PATH, CK_MANAGER_INTERFACE, "GetCurrentSession"); if (message == NULL) { goto out; } dbus_error_init (&local_error); reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &local_error); if (reply == NULL) { if (dbus_error_is_set (&local_error)) { g_warning ("Unable to determine session: %s", local_error.message); dbus_error_free (&local_error); goto out; } } dbus_message_iter_init (reply, &iter); dbus_message_iter_get_basic (&iter, &value); if (session_id != NULL) { *session_id = g_strdup (value); } ret = TRUE; out: if (message != NULL) { dbus_message_unref (message); } if (reply != NULL) { dbus_message_unref (reply); } return ret; } static gboolean get_seat_id_for_session (DBusConnection *connection, const char *session_id, char **seat_id) { DBusError local_error; DBusMessage *message; DBusMessage *reply; gboolean ret; DBusMessageIter iter; const char *value; ret = FALSE; reply = NULL; dbus_error_init (&local_error); message = dbus_message_new_method_call (CK_NAME, session_id, CK_SESSION_INTERFACE, "GetSeatId"); if (message == NULL) { goto out; } dbus_error_init (&local_error); reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &local_error); if (reply == NULL) { if (dbus_error_is_set (&local_error)) { g_warning ("Unable to determine seat: %s", local_error.message); dbus_error_free (&local_error); goto out; } } dbus_message_iter_init (reply, &iter); dbus_message_iter_get_basic (&iter, &value); if (seat_id != NULL) { *seat_id = g_strdup (value); } ret = TRUE; out: if (message != NULL) { dbus_message_unref (message); } if (reply != NULL) { dbus_message_unref (reply); } return ret; } static char * get_current_seat_id (DBusConnection *connection) { gboolean res; char *session_id; char *seat_id; session_id = NULL; seat_id = NULL; res = get_current_session_id (connection, &session_id); if (res) { res = get_seat_id_for_session (connection, session_id, &seat_id); } g_free (session_id); return seat_id; } static void csm_consolekit_set_session_idle (CsmSystem *system, gboolean is_idle) { CsmConsolekit *manager = CSM_CONSOLEKIT (system); gboolean res; GError *error; char *session_id; DBusMessage *message; DBusMessage *reply; DBusError dbus_error; DBusMessageIter iter; error = NULL; if (!csm_consolekit_ensure_ck_connection (manager, &error)) { g_warning ("Could not connect to ConsoleKit: %s", error->message); g_error_free (error); return; } session_id = NULL; res = get_current_session_id (dbus_g_connection_get_connection (manager->priv->dbus_connection), &session_id); if (!res) { goto out; } g_debug ("Updating ConsoleKit idle status: %d", is_idle); message = dbus_message_new_method_call (CK_NAME, session_id, CK_SESSION_INTERFACE, "SetIdleHint"); if (message == NULL) { g_debug ("Couldn't allocate the D-Bus message"); return; } dbus_message_iter_init_append (message, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &is_idle); /* FIXME: use async? */ dbus_error_init (&dbus_error); reply = dbus_connection_send_with_reply_and_block (dbus_g_connection_get_connection (manager->priv->dbus_connection), message, -1, &dbus_error); dbus_message_unref (message); if (reply != NULL) { dbus_message_unref (reply); } if (dbus_error_is_set (&dbus_error)) { g_debug ("%s raised:\n %s\n\n", dbus_error.name, dbus_error.message); dbus_error_free (&dbus_error); } out: g_free (session_id); } static gboolean seat_can_activate_sessions (DBusConnection *connection, const char *seat_id) { DBusError local_error; DBusMessage *message; DBusMessage *reply; DBusMessageIter iter; gboolean can_activate; can_activate = FALSE; reply = NULL; dbus_error_init (&local_error); message = dbus_message_new_method_call (CK_NAME, seat_id, CK_SEAT_INTERFACE, "CanActivateSessions"); if (message == NULL) { goto out; } dbus_error_init (&local_error); reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &local_error); if (reply == NULL) { if (dbus_error_is_set (&local_error)) { g_warning ("Unable to activate session: %s", local_error.message); dbus_error_free (&local_error); goto out; } } dbus_message_iter_init (reply, &iter); dbus_message_iter_get_basic (&iter, &can_activate); out: if (message != NULL) { dbus_message_unref (message); } if (reply != NULL) { dbus_message_unref (reply); } return can_activate; } static gboolean csm_consolekit_can_switch_user (CsmSystem *system) { CsmConsolekit *manager = CSM_CONSOLEKIT (system); GError *error; char *seat_id; gboolean ret; error = NULL; if (!csm_consolekit_ensure_ck_connection (manager, &error)) { g_warning ("Could not connect to ConsoleKit: %s", error->message); g_error_free (error); return FALSE; } seat_id = get_current_seat_id (dbus_g_connection_get_connection (manager->priv->dbus_connection)); if (seat_id == NULL || seat_id[0] == '\0') { g_debug ("seat id is not set; can't switch sessions"); return FALSE; } ret = seat_can_activate_sessions (dbus_g_connection_get_connection (manager->priv->dbus_connection), seat_id); g_free (seat_id); return ret; } static gboolean csm_consolekit_can_restart (CsmSystem *system) { CsmConsolekit *manager = CSM_CONSOLEKIT (system); gboolean res; gboolean can_restart; GError *error; error = NULL; if (!csm_consolekit_ensure_ck_connection (manager, &error)) { g_warning ("Could not connect to ConsoleKit: %s", error->message); g_error_free (error); return FALSE; } res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy, "CanRestart", INT_MAX, &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &can_restart, G_TYPE_INVALID); if (!res) { g_warning ("Could not query CanRestart from ConsoleKit: %s", error->message); g_error_free (error); return FALSE; } return can_restart; } static gboolean csm_consolekit_can_stop (CsmSystem *system) { CsmConsolekit *manager = CSM_CONSOLEKIT (system); gboolean res; gboolean can_stop; GError *error; error = NULL; if (!csm_consolekit_ensure_ck_connection (manager, &error)) { g_warning ("Could not connect to ConsoleKit: %s", error->message); g_error_free (error); return FALSE; } res = dbus_g_proxy_call_with_timeout (manager->priv->ck_proxy, "CanStop", INT_MAX, &error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &can_stop, G_TYPE_INVALID); if (!res) { g_warning ("Could not query CanStop from ConsoleKit: %s", error->message); g_error_free (error); return FALSE; } return can_stop; } static gchar * csm_consolekit_get_current_session_type (CsmConsolekit *manager) { GError *gerror; DBusConnection *connection; DBusError error; DBusMessage *message = NULL; DBusMessage *reply = NULL; gchar *session_id; gchar *ret; DBusMessageIter iter; const char *value; session_id = NULL; ret = NULL; gerror = NULL; if (!csm_consolekit_ensure_ck_connection (manager, &gerror)) { g_warning ("Could not connect to ConsoleKit: %s", gerror->message); g_error_free (gerror); goto out; } connection = dbus_g_connection_get_connection (manager->priv->dbus_connection); if (!get_current_session_id (connection, &session_id)) { goto out; } dbus_error_init (&error); message = dbus_message_new_method_call (CK_NAME, session_id, CK_SESSION_INTERFACE, "GetSessionType"); if (message == NULL) { goto out; } reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); if (reply == NULL) { if (dbus_error_is_set (&error)) { g_warning ("Unable to determine session type: %s", error.message); dbus_error_free (&error); } goto out; } dbus_message_iter_init (reply, &iter); dbus_message_iter_get_basic (&iter, &value); ret = g_strdup (value); out: if (message != NULL) { dbus_message_unref (message); } if (reply != NULL) { dbus_message_unref (reply); } g_free (session_id); return ret; } static gboolean csm_consolekit_is_login_session (CsmSystem *system) { CsmConsolekit *consolekit = CSM_CONSOLEKIT (system); char *session_type; gboolean ret; session_type = csm_consolekit_get_current_session_type (consolekit); ret = (g_strcmp0 (session_type, CSM_CONSOLEKIT_SESSION_TYPE_LOGIN_WINDOW) == 0); g_free (session_type); return ret; } static gboolean csm_consolekit_can_hybrid_sleep (CsmSystem *system) { return FALSE; } static gboolean csm_consolekit_can_suspend (CsmSystem *system) { CsmConsolekit *consolekit = CSM_CONSOLEKIT (system); #ifdef HAVE_OLD_UPOWER return up_client_get_can_suspend (consolekit->priv->up_client); #else return FALSE; #endif } static gboolean csm_consolekit_can_hibernate (CsmSystem *system) { CsmConsolekit *consolekit = CSM_CONSOLEKIT (system); #ifdef HAVE_OLD_UPOWER return up_client_get_can_hibernate (consolekit->priv->up_client); #else return FALSE; #endif } static void csm_consolekit_hybrid_sleep (CsmSystem *system) { } static void csm_consolekit_suspend (CsmSystem *system) { #ifdef HAVE_OLD_UPOWER CsmConsolekit *consolekit = CSM_CONSOLEKIT (system); GError *error = NULL; gboolean ret; ret = up_client_suspend_sync (consolekit->priv->up_client, NULL, &error); if (!ret) { g_warning ("Unexpected suspend failure: %s", error->message); g_error_free (error); } #endif } static void csm_consolekit_hibernate (CsmSystem *system) { #ifdef HAVE_OLD_UPOWER CsmConsolekit *consolekit = CSM_CONSOLEKIT (system); GError *error = NULL; gboolean ret; ret = up_client_hibernate_sync (consolekit->priv->up_client, NULL, &error); if (!ret) { g_warning ("Unexpected hibernate failure: %s", error->message); g_error_free (error); } #endif } static void csm_consolekit_add_inhibitor (CsmSystem *system, const gchar *id, CsmInhibitorFlag flag) { } static void csm_consolekit_remove_inhibitor (CsmSystem *system, const gchar *id) { } static gboolean csm_consolekit_is_last_session_for_user (CsmSystem *system) { return FALSE; } static void csm_consolekit_system_init (CsmSystemInterface *iface) { iface->can_switch_user = csm_consolekit_can_switch_user; iface->can_stop = csm_consolekit_can_stop; iface->can_restart = csm_consolekit_can_restart; iface->can_hybrid_sleep = csm_consolekit_can_hybrid_sleep; iface->can_suspend = csm_consolekit_can_suspend; iface->can_hibernate = csm_consolekit_can_hibernate; iface->attempt_stop = csm_consolekit_attempt_stop; iface->attempt_restart = csm_consolekit_attempt_restart; iface->hybrid_sleep = csm_consolekit_hybrid_sleep; iface->suspend = csm_consolekit_suspend; iface->hibernate = csm_consolekit_hibernate; iface->set_session_idle = csm_consolekit_set_session_idle; iface->is_login_session = csm_consolekit_is_login_session; iface->add_inhibitor = csm_consolekit_add_inhibitor; iface->remove_inhibitor = csm_consolekit_remove_inhibitor; iface->is_last_session_for_user = csm_consolekit_is_last_session_for_user; } CsmConsolekit * csm_consolekit_new (void) { CsmConsolekit *manager; manager = g_object_new (CSM_TYPE_CONSOLEKIT, NULL); return manager; } cinnamon-session-3.6.1/cinnamon-session/csm-consolekit.h0000644000175000017500000000415213205266677022130 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Jon McCann * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Authors: * Jon McCann */ #ifndef __CSM_CONSOLEKIT_H__ #define __CSM_CONSOLEKIT_H__ #include #include G_BEGIN_DECLS #define CSM_TYPE_CONSOLEKIT (csm_consolekit_get_type ()) #define CSM_CONSOLEKIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSM_TYPE_CONSOLEKIT, CsmConsolekit)) #define CSM_CONSOLEKIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSM_TYPE_CONSOLEKIT, CsmConsolekitClass)) #define CSM_IS_CONSOLEKIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSM_TYPE_CONSOLEKIT)) #define CSM_IS_CONSOLEKIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSM_TYPE_CONSOLEKIT)) #define CSM_CONSOLEKIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), CSM_TYPE_CONSOLEKIT, CsmConsolekitClass)) typedef struct _CsmConsolekit CsmConsolekit; typedef struct _CsmConsolekitClass CsmConsolekitClass; typedef struct _CsmConsolekitPrivate CsmConsolekitPrivate; struct _CsmConsolekit { GObject parent; CsmConsolekitPrivate *priv; }; struct _CsmConsolekitClass { GObjectClass parent_class; }; GType csm_consolekit_get_type (void); CsmConsolekit *csm_consolekit_new (void) G_GNUC_MALLOC; G_END_DECLS #endif /* __CSM_CONSOLEKIT_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-dbus-client.c0000644000175000017500000005506713205266677022175 0ustar maxymaxy/* -*- 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "csm-dbus-client.h" #include "csm-marshal.h" #include "csm-manager.h" #include "csm-util.h" #define CSM_DBUS_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_DBUS_CLIENT, CsmDBusClientPrivate)) #define SM_DBUS_NAME "org.gnome.SessionManager" #define SM_DBUS_CLIENT_PRIVATE_INTERFACE "org.gnome.SessionManager.ClientPrivate" struct CsmDBusClientPrivate { char *bus_name; GPid caller_pid; CsmClientRestartStyle restart_style_hint; DBusConnection *connection; }; enum { PROP_0, PROP_BUS_NAME }; G_DEFINE_TYPE (CsmDBusClient, csm_dbus_client, CSM_TYPE_CLIENT) GQuark csm_dbus_client_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("csm_dbus_client_error"); } return ret; } #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } GType csm_dbus_client_error_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { ENUM_ENTRY (CSM_DBUS_CLIENT_ERROR_GENERAL, "GeneralError"), ENUM_ENTRY (CSM_DBUS_CLIENT_ERROR_NOT_CLIENT, "NotClient"), { 0, 0, 0 } }; g_assert (CSM_DBUS_CLIENT_NUM_ERRORS == G_N_ELEMENTS (values) - 1); etype = g_enum_register_static ("CsmDbusClientError", values); } return etype; } static gboolean setup_connection (CsmDBusClient *client) { DBusError error; dbus_error_init (&error); if (client->priv->connection == NULL) { client->priv->connection = dbus_bus_get (DBUS_BUS_SESSION, &error); if (client->priv->connection == NULL) { if (dbus_error_is_set (&error)) { g_debug ("CsmDbusClient: Couldn't connect to session bus: %s", error.message); dbus_error_free (&error); } return FALSE; } dbus_connection_setup_with_g_main (client->priv->connection, NULL); dbus_connection_set_exit_on_disconnect (client->priv->connection, FALSE); } return TRUE; } static void raise_error (DBusConnection *connection, DBusMessage *in_reply_to, const char *error_name, char *format, ...) { char buf[512]; DBusMessage *reply; va_list args; va_start (args, format); vsnprintf (buf, sizeof (buf), format, args); va_end (args); reply = dbus_message_new_error (in_reply_to, error_name, buf); if (reply == NULL) { g_error ("No memory"); } if (! dbus_connection_send (connection, reply, NULL)) { g_error ("No memory"); } dbus_message_unref (reply); } static void handle_end_session_response (CsmDBusClient *client, DBusMessage *message) { const char *sender; DBusMessage *reply; DBusError error; dbus_bool_t is_ok; const char *reason; dbus_error_init (&error); if (! dbus_message_get_args (message, &error, DBUS_TYPE_BOOLEAN, &is_ok, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID)) { if (dbus_error_is_set (&error)) { g_warning ("Invalid method call: %s", error.message); dbus_error_free (&error); } raise_error (client->priv->connection, message, DBUS_ERROR_FAILED, "There is a syntax error in the invocation of the method EndSessionResponse"); return; } g_debug ("CsmDBusClient: got EndSessionResponse is-ok:%d reason=%s", is_ok, reason); /* make sure it is from our client */ sender = dbus_message_get_sender (message); if (sender == NULL || IS_STRING_EMPTY (client->priv->bus_name) || strcmp (sender, client->priv->bus_name) != 0) { raise_error (client->priv->connection, message, DBUS_ERROR_FAILED, "Caller not recognized as the client"); return; } reply = dbus_message_new_method_return (message); if (reply == NULL) { g_error ("No memory"); } csm_client_end_session_response (CSM_CLIENT (client), is_ok, FALSE, FALSE, reason); if (! dbus_connection_send (client->priv->connection, reply, NULL)) { g_error ("No memory"); } dbus_message_unref (reply); } static DBusHandlerResult client_dbus_filter_function (DBusConnection *connection, DBusMessage *message, void *user_data) { CsmDBusClient *client = CSM_DBUS_CLIENT (user_data); const char *path; g_return_val_if_fail (connection != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED); path = dbus_message_get_path (message); // g_debug ("CsmDBusClient: obj_path=%s interface=%s method=%s", // dbus_message_get_path (message), // dbus_message_get_interface (message), // dbus_message_get_member (message)); if (dbus_message_is_method_call (message, SM_DBUS_CLIENT_PRIVATE_INTERFACE, "EndSessionResponse")) { g_assert (csm_client_peek_id (CSM_CLIENT (client)) != NULL); if (path != NULL && strcmp (path, csm_client_peek_id (CSM_CLIENT (client))) != 0) { /* Different object path */ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } handle_end_session_response (client, message); return DBUS_HANDLER_RESULT_HANDLED; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static GObject * csm_dbus_client_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsmDBusClient *client; client = CSM_DBUS_CLIENT (G_OBJECT_CLASS (csm_dbus_client_parent_class)->constructor (type, n_construct_properties, construct_properties)); if (! setup_connection (client)) { g_object_unref (client); return NULL; } /* Object path is already registered by base class */ dbus_connection_add_filter (client->priv->connection, client_dbus_filter_function, client, NULL); return G_OBJECT (client); } static void csm_dbus_client_init (CsmDBusClient *client) { client->priv = CSM_DBUS_CLIENT_GET_PRIVATE (client); } /* adapted from PolicyKit */ static gboolean get_caller_info (CsmDBusClient *client, const char *sender, uid_t *calling_uid, pid_t *calling_pid) { gboolean res; GError *error; DBusGConnection *connection; DBusGProxy *bus_proxy; res = FALSE; bus_proxy = NULL; if (sender == NULL) { goto out; } error = NULL; connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (connection == NULL) { if (error != NULL) { g_warning ("error getting session bus: %s", error->message); g_error_free (error); } goto out; } bus_proxy = dbus_g_proxy_new_for_name (connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); error = NULL; if (! dbus_g_proxy_call (bus_proxy, "GetConnectionUnixUser", &error, G_TYPE_STRING, sender, G_TYPE_INVALID, G_TYPE_UINT, calling_uid, G_TYPE_INVALID)) { g_debug ("GetConnectionUnixUser() failed: %s", error->message); g_error_free (error); goto out; } error = NULL; if (! dbus_g_proxy_call (bus_proxy, "GetConnectionUnixProcessID", &error, G_TYPE_STRING, sender, G_TYPE_INVALID, G_TYPE_UINT, calling_pid, G_TYPE_INVALID)) { g_debug ("GetConnectionUnixProcessID() failed: %s", error->message); g_error_free (error); goto out; } res = TRUE; g_debug ("uid = %d", *calling_uid); g_debug ("pid = %d", *calling_pid); out: if (bus_proxy != NULL) { g_object_unref (bus_proxy); } return res; } static void csm_dbus_client_set_bus_name (CsmDBusClient *client, const char *bus_name) { uid_t uid; pid_t pid; g_return_if_fail (CSM_IS_DBUS_CLIENT (client)); g_free (client->priv->bus_name); client->priv->bus_name = g_strdup (bus_name); g_object_notify (G_OBJECT (client), "bus-name"); if (client->priv->bus_name != NULL) { gboolean res; res = get_caller_info (client, bus_name, &uid, &pid); if (! res) { pid = 0; } } else { pid = 0; } client->priv->caller_pid = pid; } const char * csm_dbus_client_get_bus_name (CsmDBusClient *client) { g_return_val_if_fail (CSM_IS_DBUS_CLIENT (client), NULL); return client->priv->bus_name; } static void csm_dbus_client_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsmDBusClient *self; self = CSM_DBUS_CLIENT (object); switch (prop_id) { case PROP_BUS_NAME: csm_dbus_client_set_bus_name (self, g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_dbus_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsmDBusClient *self; self = CSM_DBUS_CLIENT (object); switch (prop_id) { case PROP_BUS_NAME: g_value_set_string (value, self->priv->bus_name); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_dbus_client_finalize (GObject *object) { CsmDBusClient *client = (CsmDBusClient *) object; g_free (client->priv->bus_name); G_OBJECT_CLASS (csm_dbus_client_parent_class)->finalize (object); } static GKeyFile * dbus_client_save (CsmClient *client, GError **error) { g_debug ("CsmDBusClient: saving client with id %s", csm_client_peek_id (client)); /* FIXME: We still don't support client saving for D-Bus * session clients */ return NULL; } static gboolean dbus_client_stop (CsmClient *client, GError **error) { CsmDBusClient *dbus_client = (CsmDBusClient *) client; DBusMessage *message; gboolean ret; ret = FALSE; /* unicast the signal to only the registered bus name */ message = dbus_message_new_signal (csm_client_peek_id (client), SM_DBUS_CLIENT_PRIVATE_INTERFACE, "Stop"); if (message == NULL) { goto out; } if (!dbus_message_set_destination (message, dbus_client->priv->bus_name)) { goto out; } if (!dbus_connection_send (dbus_client->priv->connection, message, NULL)) { goto out; } ret = TRUE; out: if (message != NULL) { dbus_message_unref (message); } return ret; } static char * dbus_client_get_app_name (CsmClient *client) { /* Always use app-id instead */ return NULL; } static CsmClientRestartStyle dbus_client_get_restart_style_hint (CsmClient *client) { return (CSM_DBUS_CLIENT (client)->priv->restart_style_hint); } static guint dbus_client_get_unix_process_id (CsmClient *client) { return (CSM_DBUS_CLIENT (client)->priv->caller_pid); } static gboolean dbus_client_query_end_session (CsmClient *client, guint flags, GError **error) { CsmDBusClient *dbus_client = (CsmDBusClient *) client; DBusMessage *message; DBusMessageIter iter; gboolean ret; ret = FALSE; if (dbus_client->priv->bus_name == NULL) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Client is not registered"); return FALSE; } g_debug ("CsmDBusClient: sending QueryEndSession signal to %s", dbus_client->priv->bus_name); /* unicast the signal to only the registered bus name */ message = dbus_message_new_signal (csm_client_peek_id (client), SM_DBUS_CLIENT_PRIVATE_INTERFACE, "QueryEndSession"); if (message == NULL) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Unable to send QueryEndSession message"); goto out; } if (!dbus_message_set_destination (message, dbus_client->priv->bus_name)) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Unable to send QueryEndSession message"); goto out; } dbus_message_iter_init_append (message, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &flags); if (!dbus_connection_send (dbus_client->priv->connection, message, NULL)) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Unable to send QueryEndSession message"); goto out; } ret = TRUE; out: if (message != NULL) { dbus_message_unref (message); } return ret; } static gboolean dbus_client_end_session (CsmClient *client, guint flags, GError **error) { CsmDBusClient *dbus_client = (CsmDBusClient *) client; DBusMessage *message; DBusMessageIter iter; gboolean ret; ret = FALSE; /* unicast the signal to only the registered bus name */ message = dbus_message_new_signal (csm_client_peek_id (client), SM_DBUS_CLIENT_PRIVATE_INTERFACE, "EndSession"); if (message == NULL) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Unable to send EndSession message"); goto out; } if (!dbus_message_set_destination (message, dbus_client->priv->bus_name)) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Unable to send EndSession message"); goto out; } dbus_message_iter_init_append (message, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &flags); if (!dbus_connection_send (dbus_client->priv->connection, message, NULL)) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Unable to send EndSession message"); goto out; } ret = TRUE; out: if (message != NULL) { dbus_message_unref (message); } return ret; } static gboolean dbus_client_cancel_end_session (CsmClient *client, GError **error) { CsmDBusClient *dbus_client = (CsmDBusClient *) client; DBusMessage *message; gboolean ret = FALSE; /* unicast the signal to only the registered bus name */ message = dbus_message_new_signal (csm_client_peek_id (client), SM_DBUS_CLIENT_PRIVATE_INTERFACE, "CancelEndSession"); if (message == NULL) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Unable to send CancelEndSession message"); goto out; } if (!dbus_message_set_destination (message, dbus_client->priv->bus_name)) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Unable to send CancelEndSession message"); goto out; } if (!dbus_connection_send (dbus_client->priv->connection, message, NULL)) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Unable to send CancelEndSession message"); goto out; } ret = TRUE; out: if (message != NULL) { dbus_message_unref (message); } return ret; } static void csm_dbus_client_dispose (GObject *object) { CsmDBusClient *client; g_return_if_fail (object != NULL); g_return_if_fail (CSM_IS_DBUS_CLIENT (object)); client = CSM_DBUS_CLIENT (object); dbus_connection_remove_filter (client->priv->connection, client_dbus_filter_function, client); G_OBJECT_CLASS (csm_dbus_client_parent_class)->dispose (object); } static void csm_dbus_client_class_init (CsmDBusClientClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CsmClientClass *client_class = CSM_CLIENT_CLASS (klass); object_class->finalize = csm_dbus_client_finalize; object_class->constructor = csm_dbus_client_constructor; object_class->get_property = csm_dbus_client_get_property; object_class->set_property = csm_dbus_client_set_property; object_class->dispose = csm_dbus_client_dispose; client_class->impl_save = dbus_client_save; client_class->impl_stop = dbus_client_stop; client_class->impl_query_end_session = dbus_client_query_end_session; client_class->impl_end_session = dbus_client_end_session; client_class->impl_cancel_end_session = dbus_client_cancel_end_session; client_class->impl_get_app_name = dbus_client_get_app_name; client_class->impl_get_restart_style_hint = dbus_client_get_restart_style_hint; client_class->impl_get_unix_process_id = dbus_client_get_unix_process_id; g_object_class_install_property (object_class, PROP_BUS_NAME, g_param_spec_string ("bus-name", "bus-name", "bus-name", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (CsmDBusClientPrivate)); } CsmClient * csm_dbus_client_new (const char *startup_id, const char *bus_name) { CsmDBusClient *client; client = g_object_new (CSM_TYPE_DBUS_CLIENT, "startup-id", startup_id, "bus-name", bus_name, NULL); return CSM_CLIENT (client); } cinnamon-session-3.6.1/cinnamon-session/csm-dbus-client.h0000644000175000017500000000516013205266677022167 0ustar maxymaxy/* -*- 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_DBUS_CLIENT_H__ #define __CSM_DBUS_CLIENT_H__ #include "csm-client.h" G_BEGIN_DECLS #define CSM_TYPE_DBUS_CLIENT (csm_dbus_client_get_type ()) #define CSM_DBUS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSM_TYPE_DBUS_CLIENT, CsmDBusClient)) #define CSM_DBUS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSM_TYPE_DBUS_CLIENT, CsmDBusClientClass)) #define CSM_IS_DBUS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSM_TYPE_DBUS_CLIENT)) #define CSM_IS_DBUS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSM_TYPE_DBUS_CLIENT)) #define CSM_DBUS_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CSM_TYPE_DBUS_CLIENT, CsmDBusClientClass)) typedef struct _CsmDBusClient CsmDBusClient; typedef struct _CsmDBusClientClass CsmDBusClientClass; typedef struct CsmDBusClientPrivate CsmDBusClientPrivate; struct _CsmDBusClient { CsmClient parent; CsmDBusClientPrivate *priv; }; struct _CsmDBusClientClass { CsmClientClass parent_class; }; typedef enum { CSM_DBUS_CLIENT_ERROR_GENERAL = 0, CSM_DBUS_CLIENT_ERROR_NOT_CLIENT, CSM_DBUS_CLIENT_NUM_ERRORS } CsmDBusClientError; #define CSM_DBUS_CLIENT_ERROR csm_dbus_client_error_quark () GType csm_dbus_client_error_get_type (void); #define CSM_DBUS_CLIENT_TYPE_ERROR (csm_dbus_client_error_get_type ()) GQuark csm_dbus_client_error_quark (void); GType csm_dbus_client_get_type (void) G_GNUC_CONST; CsmClient * csm_dbus_client_new (const char *startup_id, const char *bus_name); const char * csm_dbus_client_get_bus_name (CsmDBusClient *client); G_END_DECLS #endif /* __CSM_DBUS_CLIENT_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-fail-whale-dialog.c0000644000175000017500000002125713205266677023224 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2011 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Authors: * Colin Walters */ #include #include #include #include "csm-fail-whale-dialog.h" #include "csm-icon-names.h" #include "csm-manager.h" #include "csm-util.h" #define CSM_FAIL_WHALE_DIALOG_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_FAIL_WHALE_DIALOG, CsmFailWhaleDialogPrivate)) struct _CsmFailWhaleDialogPrivate { gboolean debug_mode; gboolean allow_logout; GdkRectangle geometry; }; G_DEFINE_TYPE (CsmFailWhaleDialog, csm_fail_whale_dialog, GTK_TYPE_WINDOW); /* derived from tomboy */ static void _window_override_user_time (CsmFailWhaleDialog *window) { guint32 ev_time = gtk_get_current_event_time (); if (ev_time == 0) { gint ev_mask = gtk_widget_get_events (GTK_WIDGET (window)); if (!(ev_mask & GDK_PROPERTY_CHANGE_MASK)) { gtk_widget_add_events (GTK_WIDGET (window), GDK_PROPERTY_CHANGE_MASK); } /* * NOTE: Last resort for D-BUS or other non-interactive * openings. Causes roundtrip to server. Lame. */ ev_time = gdk_x11_get_server_time (gtk_widget_get_window (GTK_WIDGET (window))); } gdk_x11_window_set_user_time (gtk_widget_get_window (GTK_WIDGET (window)), ev_time); } /* copied from panel-toplevel.c */ static void _window_move_resize_window (CsmFailWhaleDialog *window, gboolean move, gboolean resize) { GtkWidget *widget; widget = GTK_WIDGET (window); g_assert (gtk_widget_get_realized (widget)); if (window->priv->debug_mode) return; g_debug ("Move and/or resize window x=%d y=%d w=%d h=%d", window->priv->geometry.x, window->priv->geometry.y, window->priv->geometry.width, window->priv->geometry.height); if (move && resize) { gdk_window_move_resize (gtk_widget_get_window (widget), window->priv->geometry.x, window->priv->geometry.y, window->priv->geometry.width, window->priv->geometry.height); } else if (move) { gdk_window_move (gtk_widget_get_window (widget), window->priv->geometry.x, window->priv->geometry.y); } else if (resize) { gdk_window_resize (gtk_widget_get_window (widget), window->priv->geometry.width, window->priv->geometry.height); } } static void update_geometry (CsmFailWhaleDialog *fail_dialog) { int monitor; GdkScreen *screen; screen = gtk_widget_get_screen (GTK_WIDGET (fail_dialog)); monitor = gdk_screen_get_primary_monitor (screen); gdk_screen_get_monitor_geometry (screen, monitor, &fail_dialog->priv->geometry); } static void on_screen_size_changed (GdkScreen *screen, CsmFailWhaleDialog *fail_dialog) { gtk_widget_queue_resize (GTK_WIDGET (fail_dialog)); } static void csm_fail_whale_dialog_finalize (GObject *object) { CsmFailWhaleDialog *fail_dialog = CSM_FAIL_WHALE_DIALOG (object); G_OBJECT_CLASS (csm_fail_whale_dialog_parent_class)->finalize (object); } static void csm_fail_whale_dialog_realize (GtkWidget *widget) { if (GTK_WIDGET_CLASS (csm_fail_whale_dialog_parent_class)->realize) { GTK_WIDGET_CLASS (csm_fail_whale_dialog_parent_class)->realize (widget); } _window_override_user_time (CSM_FAIL_WHALE_DIALOG (widget)); update_geometry (CSM_FAIL_WHALE_DIALOG (widget)); _window_move_resize_window (CSM_FAIL_WHALE_DIALOG (widget), TRUE, TRUE); g_signal_connect (gtk_window_get_screen (GTK_WINDOW (widget)), "size_changed", G_CALLBACK (on_screen_size_changed), widget); } static void csm_fail_whale_dialog_unrealize (GtkWidget *widget) { g_signal_handlers_disconnect_by_func (gtk_window_get_screen (GTK_WINDOW (widget)), on_screen_size_changed, widget); if (GTK_WIDGET_CLASS (csm_fail_whale_dialog_parent_class)->unrealize) { GTK_WIDGET_CLASS (csm_fail_whale_dialog_parent_class)->unrealize (widget); } } static void csm_fail_whale_dialog_size_request (GtkWidget *widget, GtkRequisition *requisition) { CsmFailWhaleDialog *fail_dialog; GdkRectangle old_geometry; int position_changed = FALSE; int size_changed = FALSE; fail_dialog = CSM_FAIL_WHALE_DIALOG (widget); old_geometry = fail_dialog->priv->geometry; update_geometry (fail_dialog); requisition->width = fail_dialog->priv->geometry.width; requisition->height = fail_dialog->priv->geometry.height; if (!gtk_widget_get_realized (widget)) { return; } if (old_geometry.width != fail_dialog->priv->geometry.width || old_geometry.height != fail_dialog->priv->geometry.height) { size_changed = TRUE; } if (old_geometry.x != fail_dialog->priv->geometry.x || old_geometry.y != fail_dialog->priv->geometry.y) { position_changed = TRUE; } _window_move_resize_window (fail_dialog, position_changed, size_changed); } static void csm_fail_whale_dialog_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width) { GtkRequisition requisition; csm_fail_whale_dialog_size_request (widget, &requisition); *minimal_width = *natural_width = requisition.width; } static void csm_fail_whale_dialog_get_preferred_height (GtkWidget *widget, gint *minimal_height, gint *natural_height) { GtkRequisition requisition; csm_fail_whale_dialog_size_request (widget, &requisition); *minimal_height = *natural_height = requisition.height; } static void csm_fail_whale_dialog_class_init (CsmFailWhaleDialogClass *klass) { GObjectClass *object_class; GtkWidgetClass *widget_class; object_class = G_OBJECT_CLASS (klass); object_class->finalize = csm_fail_whale_dialog_finalize; widget_class = GTK_WIDGET_CLASS (klass); widget_class->realize = csm_fail_whale_dialog_realize; widget_class->unrealize = csm_fail_whale_dialog_unrealize; widget_class->get_preferred_width = csm_fail_whale_dialog_get_preferred_width; widget_class->get_preferred_height = csm_fail_whale_dialog_get_preferred_height; g_type_class_add_private (klass, sizeof (CsmFailWhaleDialogPrivate)); } static void csm_fail_whale_dialog_init (CsmFailWhaleDialog *fail_dialog) { fail_dialog->priv = CSM_FAIL_WHALE_DIALOG_GET_PRIVATE (fail_dialog); } void csm_fail_whale_dialog_we_failed (gboolean debug_mode, gboolean allow_logout) { static gboolean failed = FALSE; if (failed) { return; } g_critical ("We failed, but the fail whale is dead. Sorry...."); failed = TRUE; } cinnamon-session-3.6.1/cinnamon-session/csm-fail-whale-dialog.h0000644000175000017500000000446513205266677023233 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2011 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Authors: * Colin Walters */ #ifndef __CSM_FAIL_WHALE_DIALOG_H__ #define __CSM_FAIL_WHALE_DIALOG_H__ #include G_BEGIN_DECLS #define CSM_TYPE_FAIL_WHALE_DIALOG (csm_fail_whale_dialog_get_type ()) #define CSM_FAIL_WHALE_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSM_TYPE_FAIL_WHALE_DIALOG, CsmFailWhaleDialog)) #define CSM_FAIL_WHALE_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSM_TYPE_FAIL_WHALE_DIALOG, CsmFailWhaleDialogClass)) #define CSM_IS_FAIL_WHALE_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSM_TYPE_FAIL_WHALE_DIALOG)) #define CSM_IS_FAIL_WHALE_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSM_TYPE_FAIL_WHALE_DIALOG)) #define CSM_FAIL_WHALE_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSM_TYPE_FAIL_WHALE_DIALOG, CsmFailWhaleDialogClass)) typedef struct _CsmFailWhaleDialog CsmFailWhaleDialog; typedef struct _CsmFailWhaleDialogClass CsmFailWhaleDialogClass; typedef struct _CsmFailWhaleDialogPrivate CsmFailWhaleDialogPrivate; struct _CsmFailWhaleDialog { GtkWindow parent; CsmFailWhaleDialogPrivate *priv; }; struct _CsmFailWhaleDialogClass { GtkWindowClass parent_class; }; GType csm_fail_whale_dialog_get_type (void) G_GNUC_CONST; void csm_fail_whale_dialog_we_failed (gboolean debug_mode, gboolean allow_logout); G_END_DECLS #endif /* __CSM_FAIL_WHALE_DIALOG_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-icon-names.h0000644000175000017500000000226513205266677022012 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2011 Novell, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_ICON_NAMES_H__ #define __CSM_ICON_NAMES_H__ #define CSM_ICON_COMPUTER_FAIL "computer-fail" #define CSM_ICON_INHIBITOR_DEFAULT "gnome-windows" #define CSM_ICON_LOGOUT "system-log-out" #define CSM_ICON_SHUTDOWN "system-shutdown" #define CSM_ICON_XSMP_DEFAULT "system-run" #endif /*__CSM_ICON_NAMES_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-inhibit-dialog.c0000644000175000017500000011631313205266677022637 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "csm-inhibit-dialog.h" #include "csm-store.h" #include "csm-client.h" #include "csm-icon-names.h" #include "csm-inhibitor.h" #include "eggdesktopfile.h" #include "csm-util.h" #ifdef HAVE_XRENDER #include #endif #define CSM_INHIBIT_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_INHIBIT_DIALOG, CsmInhibitDialogPrivate)) #define GTKBUILDER_FILE "csm-inhibit-dialog.glade" #ifndef DEFAULT_ICON_SIZE #define DEFAULT_ICON_SIZE 32 #endif #ifndef DEFAULT_SNAPSHOT_SIZE #define DEFAULT_SNAPSHOT_SIZE 128 #endif #define DIALOG_RESPONSE_LOCK_SCREEN 1 struct CsmInhibitDialogPrivate { GtkBuilder *xml; int action; gboolean is_done; CsmStore *inhibitors; CsmStore *clients; GtkListStore *list_store; gboolean have_xrender; int xrender_event_base; int xrender_error_base; }; enum { PROP_0, PROP_ACTION, PROP_INHIBITOR_STORE, PROP_CLIENT_STORE }; enum { INHIBIT_IMAGE_COLUMN = 0, INHIBIT_NAME_COLUMN, INHIBIT_REASON_COLUMN, INHIBIT_ID_COLUMN, NUMBER_OF_COLUMNS }; static void csm_inhibit_dialog_finalize (GObject *object); G_DEFINE_TYPE (CsmInhibitDialog, csm_inhibit_dialog, GTK_TYPE_DIALOG) static void lock_screen (CsmInhibitDialog *dialog) { GError *error; error = NULL; g_spawn_command_line_async ("cinnamon-screensaver-command --lock", &error); if (error != NULL) { g_warning ("Couldn't lock screen: %s", error->message); g_error_free (error); } } static void on_response (CsmInhibitDialog *dialog, gint response_id) { if (dialog->priv->is_done) { g_signal_stop_emission_by_name (dialog, "response"); return; } switch (response_id) { case DIALOG_RESPONSE_LOCK_SCREEN: g_signal_stop_emission_by_name (dialog, "response"); lock_screen (dialog); break; default: dialog->priv->is_done = TRUE; break; } } static void csm_inhibit_dialog_set_action (CsmInhibitDialog *dialog, int action) { dialog->priv->action = action; } static gboolean find_inhibitor (CsmInhibitDialog *dialog, const char *id, GtkTreeIter *iter) { GtkTreeModel *model; gboolean found_item; g_assert (CSM_IS_INHIBIT_DIALOG (dialog)); found_item = FALSE; model = GTK_TREE_MODEL (dialog->priv->list_store); if (!gtk_tree_model_get_iter_first (model, iter)) { return FALSE; } do { char *item_id; gtk_tree_model_get (model, iter, INHIBIT_ID_COLUMN, &item_id, -1); if (item_id != NULL && id != NULL && strcmp (item_id, id) == 0) { found_item = TRUE; } g_free (item_id); } while (!found_item && gtk_tree_model_iter_next (model, iter)); return found_item; } /* copied from gnome-panel panel-util.c */ static char * _util_icon_remove_extension (const char *icon) { char *icon_no_extension; char *p; icon_no_extension = g_strdup (icon); p = strrchr (icon_no_extension, '.'); if (p && (strcmp (p, ".png") == 0 || strcmp (p, ".xpm") == 0 || strcmp (p, ".svg") == 0)) { *p = 0; } return icon_no_extension; } /* copied from gnome-panel panel-util.c */ static char * _find_icon (GtkIconTheme *icon_theme, const char *icon_name, gint size) { GtkIconInfo *info; char *retval; char *icon_no_extension; if (icon_name == NULL || strcmp (icon_name, "") == 0) return NULL; if (g_path_is_absolute (icon_name)) { if (g_file_test (icon_name, G_FILE_TEST_EXISTS)) { return g_strdup (icon_name); } else { char *basename; basename = g_path_get_basename (icon_name); retval = _find_icon (icon_theme, basename, size); g_free (basename); return retval; } } /* This is needed because some .desktop files have an icon name *and* * an extension as icon */ icon_no_extension = _util_icon_remove_extension (icon_name); info = gtk_icon_theme_lookup_icon (icon_theme, icon_no_extension, size, 0); g_free (icon_no_extension); if (info) { retval = g_strdup (gtk_icon_info_get_filename (info)); g_object_unref (info); } else retval = NULL; return retval; } /* copied from gnome-panel panel-util.c */ static GdkPixbuf * _load_icon (GtkIconTheme *icon_theme, const char *icon_name, int size, int desired_width, int desired_height, char **error_msg) { GdkPixbuf *retval; char *file; GError *error; g_return_val_if_fail (error_msg == NULL || *error_msg == NULL, NULL); file = _find_icon (icon_theme, icon_name, size); if (!file) { if (error_msg) *error_msg = g_strdup_printf (_("Icon '%s' not found"), icon_name); return NULL; } error = NULL; retval = gdk_pixbuf_new_from_file_at_size (file, desired_width, desired_height, &error); if (error) { if (error_msg) *error_msg = g_strdup (error->message); g_error_free (error); } g_free (file); return retval; } static GdkPixbuf * scale_pixbuf (GdkPixbuf *pixbuf, int max_width, int max_height, gboolean no_stretch_hint) { int pw; int ph; float scale_factor_x = 1.0; float scale_factor_y = 1.0; float scale_factor = 1.0; pw = gdk_pixbuf_get_width (pixbuf); ph = gdk_pixbuf_get_height (pixbuf); /* Determine which dimension requires the smallest scale. */ scale_factor_x = (float) max_width / (float) pw; scale_factor_y = (float) max_height / (float) ph; if (scale_factor_x > scale_factor_y) { scale_factor = scale_factor_y; } else { scale_factor = scale_factor_x; } /* always scale down, allow to disable scaling up */ if (scale_factor < 1.0 || !no_stretch_hint) { int scale_x = (int) (pw * scale_factor); int scale_y = (int) (ph * scale_factor); g_debug ("Scaling to %dx%d", scale_x, scale_y); return gdk_pixbuf_scale_simple (pixbuf, scale_x, scale_y, GDK_INTERP_BILINEAR); } else { return g_object_ref (pixbuf); } } #ifdef HAVE_XRENDER static GdkPixbuf * pixbuf_get_from_pixmap (Display *display, Pixmap xpixmap, int width, int height) { cairo_surface_t *surface; GdkPixbuf *retval; Visual *visual; retval = NULL; visual = DefaultVisual (display, 0); g_debug ("CsmInhibitDialog: getting foreign pixmap for %u", (guint)xpixmap); surface = cairo_xlib_surface_create (display, xpixmap, visual, width, height); if (surface != NULL) { g_debug ("CsmInhibitDialog: getting pixbuf w=%d h=%d", width, height); retval = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height); } if (surface) { cairo_surface_destroy (surface); } return retval; } static Pixmap get_pixmap_for_window (Display *display, Window window, int *widthp, int *heightp) { XWindowAttributes attr; XRenderPictureAttributes pa; Pixmap pixmap; XRenderPictFormat *format; Picture src_picture; Picture dst_picture; gboolean has_alpha; int width; int height; XGetWindowAttributes (display, window, &attr); format = XRenderFindVisualFormat (display, attr.visual); has_alpha = (format->type == PictTypeDirect && format->direct.alphaMask); width = attr.width; height = attr.height; pa.subwindow_mode = IncludeInferiors; /* Don't clip child widgets */ src_picture = XRenderCreatePicture (display, window, format, CPSubwindowMode, &pa); pixmap = XCreatePixmap (display, window, width, height, attr.depth); dst_picture = XRenderCreatePicture (display, pixmap, format, 0, 0); XRenderComposite (display, has_alpha ? PictOpOver : PictOpSrc, src_picture, None, dst_picture, 0, 0, 0, 0, 0, 0, width, height); if (widthp != NULL) { *widthp = width; } if (heightp != NULL) { *heightp = height; } return pixmap; } #endif /* HAVE_COMPOSITE */ static GdkPixbuf * get_pixbuf_for_window (GdkDisplay *gdkdisplay, guint xid, int thumb_width, int thumb_height) { GdkPixbuf *pixbuf = NULL; #ifdef HAVE_XRENDER Display *display; Window xwindow; Pixmap xpixmap; int width; int height; display = GDK_DISPLAY_XDISPLAY (gdkdisplay); xwindow = (Window) xid; xpixmap = get_pixmap_for_window (display, xwindow, &width, &height); if (xpixmap == None) { g_debug ("CsmInhibitDialog: Unable to get window snapshot for %u", xid); return NULL; } else { g_debug ("CsmInhibitDialog: Got xpixmap %u", (guint)xpixmap); } pixbuf = pixbuf_get_from_pixmap (display, xpixmap, width, height); if (xpixmap != None) { gdk_x11_display_error_trap_push (gdkdisplay); XFreePixmap (display, xpixmap); gdk_x11_display_error_trap_pop_ignored (gdkdisplay); } if (pixbuf != NULL) { GdkPixbuf *scaled; g_debug ("CsmInhibitDialog: scaling pixbuf to w=%d h=%d", width, height); scaled = scale_pixbuf (pixbuf, thumb_width, thumb_height, TRUE); g_object_unref (pixbuf); pixbuf = scaled; } #else g_debug ("CsmInhibitDialog: no support for getting window snapshot"); #endif return pixbuf; } static void add_inhibitor (CsmInhibitDialog *dialog, CsmInhibitor *inhibitor) { GdkDisplay *gdkdisplay; const char *name; const char *icon_name; const char *app_id; char *desktop_filename; GdkPixbuf *pixbuf; EggDesktopFile *desktop_file; GError *error; char **search_dirs; guint xid; char *freeme; gdkdisplay = gtk_widget_get_display (GTK_WIDGET (dialog)); /* FIXME: get info from xid */ desktop_file = NULL; name = NULL; pixbuf = NULL; freeme = NULL; app_id = csm_inhibitor_peek_app_id (inhibitor); if (IS_STRING_EMPTY (app_id)) { desktop_filename = NULL; } else if (! g_str_has_suffix (app_id, ".desktop")) { desktop_filename = g_strdup_printf ("%s.desktop", app_id); } else { desktop_filename = g_strdup (app_id); } xid = csm_inhibitor_peek_toplevel_xid (inhibitor); g_debug ("CsmInhibitDialog: inhibitor has XID %u", xid); if (xid > 0 && dialog->priv->have_xrender) { pixbuf = get_pixbuf_for_window (gdkdisplay, xid, DEFAULT_SNAPSHOT_SIZE, DEFAULT_SNAPSHOT_SIZE); if (pixbuf == NULL) { g_debug ("CsmInhibitDialog: unable to read pixbuf from %u", xid); } } if (desktop_filename != NULL) { search_dirs = csm_util_get_desktop_dirs (TRUE, FALSE); if (g_path_is_absolute (desktop_filename)) { char *basename; error = NULL; desktop_file = egg_desktop_file_new (desktop_filename, &error); if (desktop_file == NULL) { if (error) { g_warning ("Unable to load desktop file '%s': %s", desktop_filename, error->message); g_error_free (error); } else { g_warning ("Unable to load desktop file '%s'", desktop_filename); } basename = g_path_get_basename (desktop_filename); g_free (desktop_filename); desktop_filename = basename; } } if (desktop_file == NULL) { error = NULL; desktop_file = egg_desktop_file_new_from_dirs (desktop_filename, (const char **)search_dirs, &error); } /* look for a file with a vendor prefix */ if (desktop_file == NULL) { if (error) { g_warning ("Unable to find desktop file '%s': %s", desktop_filename, error->message); g_error_free (error); } else { g_warning ("Unable to find desktop file '%s'", desktop_filename); } g_free (desktop_filename); desktop_filename = g_strdup_printf ("gnome-%s.desktop", app_id); error = NULL; desktop_file = egg_desktop_file_new_from_dirs (desktop_filename, (const char **)search_dirs, &error); } g_strfreev (search_dirs); if (desktop_file == NULL) { if (error) { g_warning ("Unable to find desktop file '%s': %s", desktop_filename, error->message); g_error_free (error); } else { g_warning ("Unable to find desktop file '%s'", desktop_filename); } } else { name = egg_desktop_file_get_name (desktop_file); icon_name = egg_desktop_file_get_icon (desktop_file); if (pixbuf == NULL) { pixbuf = _load_icon (gtk_icon_theme_get_default (), icon_name, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, NULL); } } } /* try client info */ if (name == NULL) { const char *client_id; client_id = csm_inhibitor_peek_client_id (inhibitor); if (! IS_STRING_EMPTY (client_id)) { CsmClient *client; client = CSM_CLIENT (csm_store_lookup (dialog->priv->clients, client_id)); if (client != NULL) { freeme = csm_client_get_app_name (client); name = freeme; } } } if (name == NULL) { if (! IS_STRING_EMPTY (app_id)) { name = app_id; } else { name = _("Unknown"); } } if (pixbuf == NULL) { pixbuf = _load_icon (gtk_icon_theme_get_default (), CSM_ICON_INHIBITOR_DEFAULT, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, NULL); } gtk_list_store_insert_with_values (dialog->priv->list_store, NULL, 0, INHIBIT_IMAGE_COLUMN, pixbuf, INHIBIT_NAME_COLUMN, name, INHIBIT_REASON_COLUMN, csm_inhibitor_peek_reason (inhibitor), INHIBIT_ID_COLUMN, csm_inhibitor_peek_id (inhibitor), -1); g_free (desktop_filename); g_free (freeme); if (pixbuf != NULL) { g_object_unref (pixbuf); } if (desktop_file != NULL) { egg_desktop_file_free (desktop_file); } } static gboolean model_has_one_entry (GtkTreeModel *model) { guint n_rows; n_rows = gtk_tree_model_iter_n_children (model, NULL); g_debug ("Model has %d rows", n_rows); return (n_rows > 0 && n_rows < 2); } static void update_dialog_text (CsmInhibitDialog *dialog) { const char *description_text; const char *header_text; GtkWidget *widget; if (model_has_one_entry (GTK_TREE_MODEL (dialog->priv->list_store))) { g_debug ("Found one entry in model"); header_text = _("A program is still running:"); description_text = _("Waiting for the program to finish. Interrupting the program may cause you to lose work."); } else { g_debug ("Found multiple entries (or none) in model"); header_text = _("Some programs are still running:"); description_text = _("Waiting for programs to finish. Interrupting these programs may cause you to lose work."); } widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "header-label")); if (widget != NULL) { char *markup; markup = g_strdup_printf ("%s", header_text); gtk_label_set_markup (GTK_LABEL (widget), markup); g_free (markup); } widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "description-label")); if (widget != NULL) { gtk_label_set_text (GTK_LABEL (widget), description_text); } } static void on_store_inhibitor_added (CsmStore *store, const char *id, CsmInhibitDialog *dialog) { CsmInhibitor *inhibitor; GtkTreeIter iter; g_debug ("CsmInhibitDialog: inhibitor added: %s", id); if (dialog->priv->is_done) { return; } inhibitor = (CsmInhibitor *)csm_store_lookup (store, id); /* Add to model */ if (! find_inhibitor (dialog, id, &iter)) { add_inhibitor (dialog, inhibitor); update_dialog_text (dialog); } } static void on_store_inhibitor_removed (CsmStore *store, const char *id, CsmInhibitDialog *dialog) { GtkTreeIter iter; g_debug ("CsmInhibitDialog: inhibitor removed: %s", id); if (dialog->priv->is_done) { return; } /* Remove from model */ if (find_inhibitor (dialog, id, &iter)) { gtk_list_store_remove (dialog->priv->list_store, &iter); update_dialog_text (dialog); } /* if there are no inhibitors left then trigger response */ if (! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dialog->priv->list_store), &iter)) { gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); } } static void csm_inhibit_dialog_set_inhibitor_store (CsmInhibitDialog *dialog, CsmStore *store) { g_return_if_fail (CSM_IS_INHIBIT_DIALOG (dialog)); if (store != NULL) { g_object_ref (store); } if (dialog->priv->inhibitors != NULL) { g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors, on_store_inhibitor_added, dialog); g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors, on_store_inhibitor_removed, dialog); g_object_unref (dialog->priv->inhibitors); } g_debug ("CsmInhibitDialog: setting store %p", store); dialog->priv->inhibitors = store; if (dialog->priv->inhibitors != NULL) { g_signal_connect (dialog->priv->inhibitors, "added", G_CALLBACK (on_store_inhibitor_added), dialog); g_signal_connect (dialog->priv->inhibitors, "removed", G_CALLBACK (on_store_inhibitor_removed), dialog); } } static void csm_inhibit_dialog_set_client_store (CsmInhibitDialog *dialog, CsmStore *store) { g_return_if_fail (CSM_IS_INHIBIT_DIALOG (dialog)); if (store != NULL) { g_object_ref (store); } if (dialog->priv->clients != NULL) { g_object_unref (dialog->priv->clients); } dialog->priv->clients = store; } static void csm_inhibit_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsmInhibitDialog *dialog = CSM_INHIBIT_DIALOG (object); switch (prop_id) { case PROP_ACTION: csm_inhibit_dialog_set_action (dialog, g_value_get_int (value)); break; case PROP_INHIBITOR_STORE: csm_inhibit_dialog_set_inhibitor_store (dialog, g_value_get_object (value)); break; case PROP_CLIENT_STORE: csm_inhibit_dialog_set_client_store (dialog, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_inhibit_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsmInhibitDialog *dialog = CSM_INHIBIT_DIALOG (object); switch (prop_id) { case PROP_ACTION: g_value_set_int (value, dialog->priv->action); break; case PROP_INHIBITOR_STORE: g_value_set_object (value, dialog->priv->inhibitors); break; case PROP_CLIENT_STORE: g_value_set_object (value, dialog->priv->clients); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void name_cell_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, CsmInhibitDialog *dialog) { char *name; char *reason; char *markup; name = NULL; reason = NULL; gtk_tree_model_get (model, iter, INHIBIT_NAME_COLUMN, &name, INHIBIT_REASON_COLUMN, &reason, -1); markup = g_strdup_printf ("%s\n" "%s", name ? name : "(null)", reason ? reason : "(null)"); g_free (name); g_free (reason); g_object_set (cell, "markup", markup, NULL); g_free (markup); } static gboolean add_to_model (const char *id, CsmInhibitor *inhibitor, CsmInhibitDialog *dialog) { add_inhibitor (dialog, inhibitor); return FALSE; } static void populate_model (CsmInhibitDialog *dialog) { csm_store_foreach_remove (dialog->priv->inhibitors, (CsmStoreFunc)add_to_model, dialog); update_dialog_text (dialog); } static void setup_dialog (CsmInhibitDialog *dialog) { const char *button_text; GtkWidget *treeview; GtkTreeViewColumn *column; GtkCellRenderer *renderer; switch (dialog->priv->action) { case CSM_LOGOUT_ACTION_SWITCH_USER: button_text = _("Switch User Anyway"); break; case CSM_LOGOUT_ACTION_LOGOUT: button_text = _("Log Out Anyway"); break; case CSM_LOGOUT_ACTION_SLEEP: button_text = _("Suspend Anyway"); break; case CSM_LOGOUT_ACTION_HIBERNATE: button_text = _("Hibernate Anyway"); break; case CSM_LOGOUT_ACTION_SHUTDOWN: button_text = _("Shut Down Anyway"); break; case CSM_LOGOUT_ACTION_REBOOT: button_text = _("Restart Anyway"); break; default: g_assert_not_reached (); break; } gtk_dialog_add_button (GTK_DIALOG (dialog), _("Lock Screen"), DIALOG_RESPONSE_LOCK_SCREEN); gtk_dialog_add_button (GTK_DIALOG (dialog), _("Cancel"), GTK_RESPONSE_CANCEL); gtk_dialog_add_button (GTK_DIALOG (dialog), button_text, GTK_RESPONSE_ACCEPT); g_signal_connect (dialog, "response", G_CALLBACK (on_response), dialog); dialog->priv->list_store = gtk_list_store_new (NUMBER_OF_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); treeview = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "inhibitors-treeview")); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE); gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (dialog->priv->list_store)); /* IMAGE COLUMN */ renderer = gtk_cell_renderer_pixbuf_new (); column = gtk_tree_view_column_new (); gtk_tree_view_column_pack_start (column, renderer, FALSE); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); gtk_tree_view_column_set_attributes (column, renderer, "pixbuf", INHIBIT_IMAGE_COLUMN, NULL); g_object_set (renderer, "xalign", 1.0, NULL); /* NAME COLUMN */ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new (); gtk_tree_view_column_pack_start (column, renderer, FALSE); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); gtk_tree_view_column_set_cell_data_func (column, renderer, (GtkTreeCellDataFunc) name_cell_data_func, dialog, NULL); gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview), INHIBIT_REASON_COLUMN); populate_model (dialog); } static GObject * csm_inhibit_dialog_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsmInhibitDialog *dialog; #ifdef HAVE_XRENDER GdkDisplay *gdkdisplay; #endif /* HAVE_XRENDER */ dialog = CSM_INHIBIT_DIALOG (G_OBJECT_CLASS (csm_inhibit_dialog_parent_class)->constructor (type, n_construct_properties, construct_properties)); #ifdef HAVE_XRENDER gdkdisplay = gdk_display_get_default (); gdk_x11_display_error_trap_push (gdkdisplay); if (XRenderQueryExtension (GDK_DISPLAY_XDISPLAY (gdkdisplay), &dialog->priv->xrender_event_base, &dialog->priv->xrender_error_base)) { g_debug ("CsmInhibitDialog: Initialized XRender extension"); dialog->priv->have_xrender = TRUE; } else { g_debug ("CsmInhibitDialog: Unable to initialize XRender extension"); dialog->priv->have_xrender = FALSE; } gdk_display_sync (gdkdisplay); gdk_x11_display_error_trap_pop_ignored (gdkdisplay); #endif /* HAVE_XRENDER */ /* FIXME: turn this on when it is ready */ dialog->priv->have_xrender = FALSE; setup_dialog (dialog); gtk_widget_show_all (GTK_WIDGET (dialog)); return G_OBJECT (dialog); } static void csm_inhibit_dialog_dispose (GObject *object) { CsmInhibitDialog *dialog; g_return_if_fail (object != NULL); g_return_if_fail (CSM_IS_INHIBIT_DIALOG (object)); dialog = CSM_INHIBIT_DIALOG (object); g_debug ("CsmInhibitDialog: dispose called"); if (dialog->priv->list_store != NULL) { g_object_unref (dialog->priv->list_store); dialog->priv->list_store = NULL; } if (dialog->priv->inhibitors != NULL) { g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors, on_store_inhibitor_added, dialog); g_signal_handlers_disconnect_by_func (dialog->priv->inhibitors, on_store_inhibitor_removed, dialog); g_object_unref (dialog->priv->inhibitors); dialog->priv->inhibitors = NULL; } if (dialog->priv->xml != NULL) { g_object_unref (dialog->priv->xml); dialog->priv->xml = NULL; } G_OBJECT_CLASS (csm_inhibit_dialog_parent_class)->dispose (object); } static void csm_inhibit_dialog_class_init (CsmInhibitDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = csm_inhibit_dialog_get_property; object_class->set_property = csm_inhibit_dialog_set_property; object_class->constructor = csm_inhibit_dialog_constructor; object_class->dispose = csm_inhibit_dialog_dispose; object_class->finalize = csm_inhibit_dialog_finalize; g_object_class_install_property (object_class, PROP_ACTION, g_param_spec_int ("action", "action", "action", -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_INHIBITOR_STORE, g_param_spec_object ("inhibitor-store", NULL, NULL, CSM_TYPE_STORE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_CLIENT_STORE, g_param_spec_object ("client-store", NULL, NULL, CSM_TYPE_STORE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (CsmInhibitDialogPrivate)); } static void csm_inhibit_dialog_init (CsmInhibitDialog *dialog) { GtkWidget *content_area; GtkWidget *widget; GError *error; dialog->priv = CSM_INHIBIT_DIALOG_GET_PRIVATE (dialog); dialog->priv->xml = gtk_builder_new (); gtk_builder_set_translation_domain (dialog->priv->xml, GETTEXT_PACKAGE); error = NULL; if (!gtk_builder_add_from_file (dialog->priv->xml, GTKBUILDER_DIR "/" GTKBUILDER_FILE, &error)) { if (error) { g_warning ("Could not load inhibitor UI file: %s", error->message); g_error_free (error); } else { g_warning ("Could not load inhibitor UI file."); } } content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); widget = GTK_WIDGET (gtk_builder_get_object (dialog->priv->xml, "main-box")); gtk_container_add (GTK_CONTAINER (content_area), widget); gtk_container_set_border_width (GTK_CONTAINER (dialog), 6); gtk_window_set_icon_name (GTK_WINDOW (dialog), CSM_ICON_LOGOUT); gtk_window_set_title (GTK_WINDOW (dialog), ""); g_object_set (dialog, "resizable", FALSE, NULL); } static void csm_inhibit_dialog_finalize (GObject *object) { CsmInhibitDialog *dialog; g_return_if_fail (object != NULL); g_return_if_fail (CSM_IS_INHIBIT_DIALOG (object)); dialog = CSM_INHIBIT_DIALOG (object); g_return_if_fail (dialog->priv != NULL); g_debug ("CsmInhibitDialog: finalizing"); G_OBJECT_CLASS (csm_inhibit_dialog_parent_class)->finalize (object); } GtkWidget * csm_inhibit_dialog_new (CsmStore *inhibitors, CsmStore *clients, int action) { GObject *object; object = g_object_new (CSM_TYPE_INHIBIT_DIALOG, "action", action, "inhibitor-store", inhibitors, "client-store", clients, NULL); return GTK_WIDGET (object); } cinnamon-session-3.6.1/cinnamon-session/csm-inhibit-dialog.h0000644000175000017500000000511213205266677022636 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CSM_INHIBIT_DIALOG_H #define __CSM_INHIBIT_DIALOG_H #include #include #include "csm-store.h" G_BEGIN_DECLS #define CSM_TYPE_INHIBIT_DIALOG (csm_inhibit_dialog_get_type ()) #define CSM_INHIBIT_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSM_TYPE_INHIBIT_DIALOG, CsmInhibitDialog)) #define CSM_INHIBIT_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSM_TYPE_INHIBIT_DIALOG, CsmInhibitDialogClass)) #define CSM_IS_INHIBIT_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSM_TYPE_INHIBIT_DIALOG)) #define CSM_IS_INHIBIT_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSM_TYPE_INHIBIT_DIALOG)) #define CSM_INHIBIT_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSM_TYPE_INHIBIT_DIALOG, CsmInhibitDialogClass)) typedef struct CsmInhibitDialogPrivate CsmInhibitDialogPrivate; typedef enum { CSM_LOGOUT_ACTION_LOGOUT, CSM_LOGOUT_ACTION_SWITCH_USER, CSM_LOGOUT_ACTION_SHUTDOWN, CSM_LOGOUT_ACTION_REBOOT, CSM_LOGOUT_ACTION_HIBERNATE, CSM_LOGOUT_ACTION_SLEEP } CsmLogoutAction; typedef struct { GtkDialog parent; CsmInhibitDialogPrivate *priv; } CsmInhibitDialog; typedef struct { GtkDialogClass parent_class; } CsmInhibitDialogClass; GType csm_inhibit_dialog_get_type (void); GtkWidget * csm_inhibit_dialog_new (CsmStore *inhibitors, CsmStore *clients, int action); GtkTreeModel * csm_inhibit_dialog_get_model (CsmInhibitDialog *dialog); G_END_DECLS #endif /* __CSM_INHIBIT_DIALOG_H */ cinnamon-session-3.6.1/cinnamon-session/csm-inhibitor.c0000644000175000017500000004713013205266677021743 0ustar maxymaxy/* -*- 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include "config.h" #include #include #include #include #include #include #include "csm-inhibitor.h" #include "csm-inhibitor-glue.h" #include "csm-util.h" static guint32 inhibitor_serial = 1; #define CSM_INHIBITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_INHIBITOR, CsmInhibitorPrivate)) struct CsmInhibitorPrivate { char *id; char *bus_name; char *app_id; char *client_id; char *reason; guint flags; guint toplevel_xid; guint cookie; DBusGConnection *connection; }; enum { PROP_0, PROP_BUS_NAME, PROP_REASON, PROP_APP_ID, PROP_CLIENT_ID, PROP_FLAGS, PROP_TOPLEVEL_XID, PROP_COOKIE }; G_DEFINE_TYPE (CsmInhibitor, csm_inhibitor, G_TYPE_OBJECT) GQuark csm_inhibitor_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("csm_inhibitor_error"); } return ret; } #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } GType csm_inhibitor_error_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { ENUM_ENTRY (CSM_INHIBITOR_ERROR_GENERAL, "GeneralError"), ENUM_ENTRY (CSM_INHIBITOR_ERROR_NOT_SET, "NotSet"), { 0, 0, 0 } }; g_assert (CSM_INHIBITOR_NUM_ERRORS == G_N_ELEMENTS (values) - 1); etype = g_enum_register_static ("CsmInhibitorError", values); } return etype; } static guint32 get_next_inhibitor_serial (void) { guint32 serial; serial = inhibitor_serial++; if ((gint32)inhibitor_serial < 0) { inhibitor_serial = 1; } return serial; } static gboolean register_inhibitor (CsmInhibitor *inhibitor) { GError *error; error = NULL; inhibitor->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (inhibitor->priv->connection == NULL) { if (error != NULL) { g_critical ("error getting session bus: %s", error->message); g_error_free (error); } return FALSE; } dbus_g_connection_register_g_object (inhibitor->priv->connection, inhibitor->priv->id, G_OBJECT (inhibitor)); return TRUE; } static GObject * csm_inhibitor_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsmInhibitor *inhibitor; gboolean res; inhibitor = CSM_INHIBITOR (G_OBJECT_CLASS (csm_inhibitor_parent_class)->constructor (type, n_construct_properties, construct_properties)); g_free (inhibitor->priv->id); inhibitor->priv->id = g_strdup_printf ("/org/gnome/SessionManager/Inhibitor%u", get_next_inhibitor_serial ()); res = register_inhibitor (inhibitor); if (! res) { g_warning ("Unable to register inhibitor with session bus"); } return G_OBJECT (inhibitor); } static void csm_inhibitor_init (CsmInhibitor *inhibitor) { inhibitor->priv = CSM_INHIBITOR_GET_PRIVATE (inhibitor); } static void csm_inhibitor_set_bus_name (CsmInhibitor *inhibitor, const char *bus_name) { g_return_if_fail (CSM_IS_INHIBITOR (inhibitor)); g_free (inhibitor->priv->bus_name); if (bus_name != NULL) { inhibitor->priv->bus_name = g_strdup (bus_name); } else { inhibitor->priv->bus_name = g_strdup (""); } g_object_notify (G_OBJECT (inhibitor), "bus-name"); } static void csm_inhibitor_set_app_id (CsmInhibitor *inhibitor, const char *app_id) { g_return_if_fail (CSM_IS_INHIBITOR (inhibitor)); g_free (inhibitor->priv->app_id); inhibitor->priv->app_id = g_strdup (app_id); g_object_notify (G_OBJECT (inhibitor), "app-id"); } static void csm_inhibitor_set_client_id (CsmInhibitor *inhibitor, const char *client_id) { g_return_if_fail (CSM_IS_INHIBITOR (inhibitor)); g_free (inhibitor->priv->client_id); g_debug ("CsmInhibitor: setting client-id = %s", client_id); if (client_id != NULL) { inhibitor->priv->client_id = g_strdup (client_id); } else { inhibitor->priv->client_id = g_strdup (""); } g_object_notify (G_OBJECT (inhibitor), "client-id"); } static void csm_inhibitor_set_reason (CsmInhibitor *inhibitor, const char *reason) { g_return_if_fail (CSM_IS_INHIBITOR (inhibitor)); g_free (inhibitor->priv->reason); if (reason != NULL) { inhibitor->priv->reason = g_strdup (reason); } else { inhibitor->priv->reason = g_strdup (""); } g_object_notify (G_OBJECT (inhibitor), "reason"); } static void csm_inhibitor_set_cookie (CsmInhibitor *inhibitor, guint cookie) { g_return_if_fail (CSM_IS_INHIBITOR (inhibitor)); if (inhibitor->priv->cookie != cookie) { inhibitor->priv->cookie = cookie; g_object_notify (G_OBJECT (inhibitor), "cookie"); } } static void csm_inhibitor_set_flags (CsmInhibitor *inhibitor, guint flags) { g_return_if_fail (CSM_IS_INHIBITOR (inhibitor)); if (inhibitor->priv->flags != flags) { inhibitor->priv->flags = flags; g_object_notify (G_OBJECT (inhibitor), "flags"); } } static void csm_inhibitor_set_toplevel_xid (CsmInhibitor *inhibitor, guint xid) { g_return_if_fail (CSM_IS_INHIBITOR (inhibitor)); if (inhibitor->priv->toplevel_xid != xid) { inhibitor->priv->toplevel_xid = xid; g_object_notify (G_OBJECT (inhibitor), "toplevel-xid"); } } const char * csm_inhibitor_peek_bus_name (CsmInhibitor *inhibitor) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), NULL); return inhibitor->priv->bus_name; } gboolean csm_inhibitor_get_app_id (CsmInhibitor *inhibitor, char **id, GError **error) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), FALSE); if (inhibitor->priv->app_id != NULL) { *id = g_strdup (inhibitor->priv->app_id); } else { *id = g_strdup (""); } return TRUE; } gboolean csm_inhibitor_get_client_id (CsmInhibitor *inhibitor, char **id, GError **error) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), FALSE); /* object paths are not allowed to be NULL or blank */ if (IS_STRING_EMPTY (inhibitor->priv->client_id)) { g_set_error (error, CSM_INHIBITOR_ERROR, CSM_INHIBITOR_ERROR_NOT_SET, "Value is not set"); return FALSE; } *id = g_strdup (inhibitor->priv->client_id); g_debug ("CsmInhibitor: getting client-id = '%s'", *id); return TRUE; } gboolean csm_inhibitor_get_reason (CsmInhibitor *inhibitor, char **reason, GError **error) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), FALSE); if (inhibitor->priv->reason != NULL) { *reason = g_strdup (inhibitor->priv->reason); } else { *reason = g_strdup (""); } return TRUE; } gboolean csm_inhibitor_get_flags (CsmInhibitor *inhibitor, guint *flags, GError **error) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), FALSE); *flags = inhibitor->priv->flags; return TRUE; } gboolean csm_inhibitor_get_toplevel_xid (CsmInhibitor *inhibitor, guint *xid, GError **error) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), FALSE); *xid = inhibitor->priv->toplevel_xid; return TRUE; } const char * csm_inhibitor_peek_id (CsmInhibitor *inhibitor) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), NULL); return inhibitor->priv->id; } const char * csm_inhibitor_peek_app_id (CsmInhibitor *inhibitor) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), NULL); return inhibitor->priv->app_id; } const char * csm_inhibitor_peek_client_id (CsmInhibitor *inhibitor) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), NULL); return inhibitor->priv->client_id; } const char * csm_inhibitor_peek_reason (CsmInhibitor *inhibitor) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), NULL); return inhibitor->priv->reason; } guint csm_inhibitor_peek_flags (CsmInhibitor *inhibitor) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), 0); return inhibitor->priv->flags; } guint csm_inhibitor_peek_toplevel_xid (CsmInhibitor *inhibitor) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), 0); return inhibitor->priv->toplevel_xid; } guint csm_inhibitor_peek_cookie (CsmInhibitor *inhibitor) { g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), 0); return inhibitor->priv->cookie; } static void csm_inhibitor_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsmInhibitor *self; self = CSM_INHIBITOR (object); switch (prop_id) { case PROP_BUS_NAME: csm_inhibitor_set_bus_name (self, g_value_get_string (value)); break; case PROP_APP_ID: csm_inhibitor_set_app_id (self, g_value_get_string (value)); break; case PROP_CLIENT_ID: csm_inhibitor_set_client_id (self, g_value_get_string (value)); break; case PROP_REASON: csm_inhibitor_set_reason (self, g_value_get_string (value)); break; case PROP_FLAGS: csm_inhibitor_set_flags (self, g_value_get_uint (value)); break; case PROP_COOKIE: csm_inhibitor_set_cookie (self, g_value_get_uint (value)); break; case PROP_TOPLEVEL_XID: csm_inhibitor_set_toplevel_xid (self, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_inhibitor_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsmInhibitor *self; self = CSM_INHIBITOR (object); switch (prop_id) { case PROP_BUS_NAME: g_value_set_string (value, self->priv->bus_name); break; case PROP_APP_ID: g_value_set_string (value, self->priv->app_id); break; case PROP_CLIENT_ID: g_value_set_string (value, self->priv->client_id); break; case PROP_REASON: g_value_set_string (value, self->priv->reason); break; case PROP_FLAGS: g_value_set_uint (value, self->priv->flags); break; case PROP_COOKIE: g_value_set_uint (value, self->priv->cookie); break; case PROP_TOPLEVEL_XID: g_value_set_uint (value, self->priv->toplevel_xid); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_inhibitor_finalize (GObject *object) { CsmInhibitor *inhibitor = (CsmInhibitor *) object; g_free (inhibitor->priv->id); g_free (inhibitor->priv->bus_name); g_free (inhibitor->priv->app_id); g_free (inhibitor->priv->client_id); g_free (inhibitor->priv->reason); G_OBJECT_CLASS (csm_inhibitor_parent_class)->finalize (object); } static void csm_inhibitor_class_init (CsmInhibitorClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csm_inhibitor_finalize; object_class->constructor = csm_inhibitor_constructor; object_class->get_property = csm_inhibitor_get_property; object_class->set_property = csm_inhibitor_set_property; g_object_class_install_property (object_class, PROP_BUS_NAME, g_param_spec_string ("bus-name", "bus-name", "bus-name", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_APP_ID, g_param_spec_string ("app-id", "app-id", "app-id", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_CLIENT_ID, g_param_spec_string ("client-id", "client-id", "client-id", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_REASON, g_param_spec_string ("reason", "reason", "reason", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_FLAGS, g_param_spec_uint ("flags", "flags", "flags", 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_TOPLEVEL_XID, g_param_spec_uint ("toplevel-xid", "toplevel-xid", "toplevel-xid", 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_COOKIE, g_param_spec_uint ("cookie", "cookie", "cookie", 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); dbus_g_object_type_install_info (CSM_TYPE_INHIBITOR, &dbus_glib_csm_inhibitor_object_info); dbus_g_error_domain_register (CSM_INHIBITOR_ERROR, NULL, CSM_INHIBITOR_TYPE_ERROR); g_type_class_add_private (klass, sizeof (CsmInhibitorPrivate)); } CsmInhibitor * csm_inhibitor_new (const char *app_id, guint toplevel_xid, guint flags, const char *reason, const char *bus_name, guint cookie) { CsmInhibitor *inhibitor; inhibitor = g_object_new (CSM_TYPE_INHIBITOR, "app-id", app_id, "reason", reason, "bus-name", bus_name, "flags", flags, "toplevel-xid", toplevel_xid, "cookie", cookie, NULL); return inhibitor; } CsmInhibitor * csm_inhibitor_new_for_client (const char *client_id, const char *app_id, guint flags, const char *reason, const char *bus_name, guint cookie) { CsmInhibitor *inhibitor; inhibitor = g_object_new (CSM_TYPE_INHIBITOR, "client-id", client_id, "app-id", app_id, "reason", reason, "bus-name", bus_name, "flags", flags, "cookie", cookie, NULL); return inhibitor; } cinnamon-session-3.6.1/cinnamon-session/csm-inhibitor.h0000644000175000017500000001233513205266677021747 0ustar maxymaxy/* -*- 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_INHIBITOR_H__ #define __CSM_INHIBITOR_H__ #include #include G_BEGIN_DECLS #define CSM_TYPE_INHIBITOR (csm_inhibitor_get_type ()) #define CSM_INHIBITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSM_TYPE_INHIBITOR, CsmInhibitor)) #define CSM_INHIBITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSM_TYPE_INHIBITOR, CsmInhibitorClass)) #define CSM_IS_INHIBITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSM_TYPE_INHIBITOR)) #define CSM_IS_INHIBITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSM_TYPE_INHIBITOR)) #define CSM_INHIBITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CSM_TYPE_INHIBITOR, CsmInhibitorClass)) typedef struct _CsmInhibitor CsmInhibitor; typedef struct _CsmInhibitorClass CsmInhibitorClass; typedef struct CsmInhibitorPrivate CsmInhibitorPrivate; struct _CsmInhibitor { GObject parent; CsmInhibitorPrivate *priv; }; struct _CsmInhibitorClass { GObjectClass parent_class; }; typedef enum { CSM_INHIBITOR_FLAG_LOGOUT = 1 << 0, CSM_INHIBITOR_FLAG_SWITCH_USER = 1 << 1, CSM_INHIBITOR_FLAG_SUSPEND = 1 << 2, CSM_INHIBITOR_FLAG_IDLE = 1 << 3, CSM_INHIBITOR_FLAG_AUTOMOUNT = 1 << 4 } CsmInhibitorFlag; typedef enum { CSM_INHIBITOR_ERROR_GENERAL = 0, CSM_INHIBITOR_ERROR_NOT_SET, CSM_INHIBITOR_NUM_ERRORS } CsmInhibitorError; #define CSM_INHIBITOR_ERROR csm_inhibitor_error_quark () GType csm_inhibitor_error_get_type (void); #define CSM_INHIBITOR_TYPE_ERROR (csm_inhibitor_error_get_type ()) GQuark csm_inhibitor_error_quark (void); GType csm_inhibitor_get_type (void) G_GNUC_CONST; CsmInhibitor * csm_inhibitor_new (const char *app_id, guint toplevel_xid, guint flags, const char *reason, const char *bus_name, guint cookie); CsmInhibitor * csm_inhibitor_new_for_client (const char *client_id, const char *app_id, guint flags, const char *reason, const char *bus_name, guint cookie); const char * csm_inhibitor_peek_id (CsmInhibitor *inhibitor); const char * csm_inhibitor_peek_app_id (CsmInhibitor *inhibitor); const char * csm_inhibitor_peek_client_id (CsmInhibitor *inhibitor); const char * csm_inhibitor_peek_reason (CsmInhibitor *inhibitor); const char * csm_inhibitor_peek_bus_name (CsmInhibitor *inhibitor); guint csm_inhibitor_peek_cookie (CsmInhibitor *inhibitor); guint csm_inhibitor_peek_flags (CsmInhibitor *inhibitor); guint csm_inhibitor_peek_toplevel_xid (CsmInhibitor *inhibitor); /* exported to bus */ gboolean csm_inhibitor_get_app_id (CsmInhibitor *inhibitor, char **id, GError **error); gboolean csm_inhibitor_get_client_id (CsmInhibitor *inhibitor, char **id, GError **error); gboolean csm_inhibitor_get_reason (CsmInhibitor *inhibitor, char **reason, GError **error); gboolean csm_inhibitor_get_flags (CsmInhibitor *inhibitor, guint *flags, GError **error); gboolean csm_inhibitor_get_toplevel_xid (CsmInhibitor *inhibitor, guint *xid, GError **error); G_END_DECLS #endif /* __CSM_INHIBITOR_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-logout-dialog.c0000644000175000017500000004223413205266677022522 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006 Vincent Untz * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Authors: * Vincent Untz */ #include #include #include #ifdef HAVE_OLD_UPOWER #define UPOWER_ENABLE_DEPRECATED 1 #include #endif #include "csm-logout-dialog.h" #include "csm-system.h" #include "csm-icon-names.h" #include "mdm.h" #define CSM_LOGOUT_DIALOG_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_LOGOUT_DIALOG, CsmLogoutDialogPrivate)) #define LOCKDOWN_SCHEMA "org.cinnamon.desktop.lockdown" #define KEY_DISABLE_USER_SWITCHING "disable-user-switching" #define SESSION_SCHEMA "org.cinnamon.SessionManager" #define KEY_TOGGLE_DELAY "quit-delay-toggle" #define KEY_DELAY "quit-time-delay" struct _CsmLogoutDialogPrivate { CsmDialogLogoutType type; #ifdef HAVE_OLD_UPOWER UpClient *up_client; #endif CsmSystem *system; GtkWidget *progressbar; gboolean delay_toggle; int timeout; int delay; unsigned int timeout_id; unsigned int default_response; }; static CsmLogoutDialog *current_dialog = NULL; static void csm_logout_dialog_set_timeout (CsmLogoutDialog *logout_dialog); static void csm_logout_dialog_destroy (CsmLogoutDialog *logout_dialog, gpointer data); static void csm_logout_dialog_show (CsmLogoutDialog *logout_dialog, gpointer data); enum { PROP_0, PROP_MESSAGE_TYPE }; G_DEFINE_TYPE (CsmLogoutDialog, csm_logout_dialog, GTK_TYPE_MESSAGE_DIALOG); static void csm_logout_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { case PROP_MESSAGE_TYPE: break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_logout_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { case PROP_MESSAGE_TYPE: g_value_set_enum (value, GTK_MESSAGE_WARNING); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_logout_dialog_class_init (CsmLogoutDialogClass *klass) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); /* This is a workaround to avoid a stupid crash: libgnomeui * listens for the "show" signal on all GtkMessageDialog and * gets the "message-type" of the dialogs. We will crash when * it accesses this property if we don't override it since we * didn't define it. */ gobject_class->set_property = csm_logout_dialog_set_property; gobject_class->get_property = csm_logout_dialog_get_property; g_object_class_override_property (gobject_class, PROP_MESSAGE_TYPE, "message-type"); g_type_class_add_private (klass, sizeof (CsmLogoutDialogPrivate)); } static void csm_logout_dialog_init (CsmLogoutDialog *logout_dialog) { logout_dialog->priv = CSM_LOGOUT_DIALOG_GET_PRIVATE (logout_dialog); logout_dialog->priv->timeout_id = 0; logout_dialog->priv->timeout = 0; logout_dialog->priv->default_response = GTK_RESPONSE_CANCEL; gtk_window_set_skip_taskbar_hint (GTK_WINDOW (logout_dialog), TRUE); gtk_window_set_keep_above (GTK_WINDOW (logout_dialog), TRUE); gtk_window_stick (GTK_WINDOW (logout_dialog)); #ifdef HAVE_OLD_UPOWER logout_dialog->priv->up_client = up_client_new (); #endif logout_dialog->priv->system = csm_get_system (); g_signal_connect (logout_dialog, "destroy", G_CALLBACK (csm_logout_dialog_destroy), NULL); g_signal_connect (logout_dialog, "show", G_CALLBACK (csm_logout_dialog_show), NULL); } static void csm_logout_dialog_destroy (CsmLogoutDialog *logout_dialog, gpointer data) { if (logout_dialog->priv->timeout_id != 0) { g_source_remove (logout_dialog->priv->timeout_id); logout_dialog->priv->timeout_id = 0; } #ifdef HAVE_OLD_UPOWER if (logout_dialog->priv->up_client) { g_object_unref (logout_dialog->priv->up_client); logout_dialog->priv->up_client = NULL; } #endif g_clear_object (&logout_dialog->priv->system); current_dialog = NULL; } static gboolean csm_logout_supports_switch_user (CsmLogoutDialog *logout_dialog) { GSettings *settings; gboolean ret; settings = g_settings_new (LOCKDOWN_SCHEMA); ret = !g_settings_get_boolean (settings, KEY_DISABLE_USER_SWITCHING); g_object_unref (settings); return ret; } static gboolean csm_logout_supports_reboot (CsmLogoutDialog *logout_dialog) { gboolean ret; ret = csm_system_can_restart (logout_dialog->priv->system); if (!ret) { ret = mdm_supports_logout_action (MDM_LOGOUT_ACTION_REBOOT); } return ret; } static gboolean csm_logout_supports_shutdown (CsmLogoutDialog *logout_dialog) { gboolean ret; ret = csm_system_can_stop (logout_dialog->priv->system); if (!ret) { ret = mdm_supports_logout_action (MDM_LOGOUT_ACTION_SHUTDOWN); } return ret; } static void csm_logout_dialog_show (CsmLogoutDialog *logout_dialog, gpointer user_data) { GSettings *settings = g_settings_new (SESSION_SCHEMA); if (g_settings_get_boolean (settings, KEY_TOGGLE_DELAY)) { csm_logout_dialog_set_timeout (logout_dialog); } g_object_unref(settings); } static gboolean csm_logout_dialog_timeout (gpointer data) { CsmLogoutDialog *logout_dialog; char *seconds_warning; char *secondary_text; logout_dialog = (CsmLogoutDialog *) data; if (!logout_dialog->priv->timeout && logout_dialog->priv->delay_toggle) { gtk_dialog_response (GTK_DIALOG (logout_dialog), logout_dialog->priv->default_response); return FALSE; } switch (logout_dialog->priv->type) { case CSM_DIALOG_LOGOUT_TYPE_LOGOUT: /* This string is shared with csm-fail-whale-dialog.c */ seconds_warning = ngettext ("You will be automatically logged " "out in %d second.", "You will be logged " "out in %d seconds.", logout_dialog->priv->timeout); break; case CSM_DIALOG_LOGOUT_TYPE_SHUTDOWN: seconds_warning = ngettext ("This system will be automatically " "shut down in %d second.", "This system will be " "shut down in %d seconds.", logout_dialog->priv->timeout); break; case CSM_DIALOG_LOGOUT_TYPE_REBOOT: seconds_warning = ngettext ("This system will be automatically " "restarted in %d second.", "This system will be " "restarted in %d seconds.", logout_dialog->priv->timeout); break; default: g_assert_not_reached (); } if (!csm_system_is_login_session (logout_dialog->priv->system)) { char *name; name = g_locale_to_utf8 (g_get_real_name (), -1, NULL, NULL, NULL); if (!name || name[0] == '\0' || strcmp (name, "Unknown") == 0) { name = g_locale_to_utf8 (g_get_user_name (), -1 , NULL, NULL, NULL); } if (!name) { name = g_strdup (g_get_user_name ()); } secondary_text = g_strdup_printf (_("You are currently logged in as \"%s\"."), name); g_free (name); } gdouble delay; delay = (gdouble)logout_dialog->priv->delay; seconds_warning = g_strdup_printf (seconds_warning, logout_dialog->priv->timeout); gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (logout_dialog->priv->progressbar), logout_dialog->priv->timeout / delay); gtk_progress_bar_set_show_text( GTK_PROGRESS_BAR(logout_dialog->priv->progressbar), TRUE ); gtk_progress_bar_set_text (GTK_PROGRESS_BAR (logout_dialog->priv->progressbar), seconds_warning); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (logout_dialog), secondary_text, NULL); logout_dialog->priv->timeout--; g_free (secondary_text); g_free (seconds_warning); return TRUE; } static void csm_logout_dialog_set_timeout (CsmLogoutDialog *logout_dialog) { logout_dialog->priv->timeout = logout_dialog->priv->delay; /* Sets the secondary text */ csm_logout_dialog_timeout (logout_dialog); if (logout_dialog->priv->timeout_id != 0) { g_source_remove (logout_dialog->priv->timeout_id); logout_dialog->priv->timeout_id = 0; } logout_dialog->priv->timeout_id = g_timeout_add (1000, csm_logout_dialog_timeout, logout_dialog); } static GtkWidget * csm_get_dialog (CsmDialogLogoutType type, GdkScreen *screen, guint32 activate_time) { CsmLogoutDialog *logout_dialog; GtkWidget *hbox; const char *primary_text; const char *icon_name; if (current_dialog != NULL) { gtk_widget_destroy (GTK_WIDGET (current_dialog)); } logout_dialog = g_object_new (CSM_TYPE_LOGOUT_DIALOG, NULL); current_dialog = logout_dialog; gtk_window_set_title (GTK_WINDOW (logout_dialog), _("Session")); logout_dialog->priv->type = type; GSettings *settings = g_settings_new (SESSION_SCHEMA); logout_dialog->priv->delay_toggle = g_settings_get_boolean (settings, KEY_TOGGLE_DELAY); logout_dialog->priv->delay = g_settings_get_int (settings, KEY_DELAY); icon_name = NULL; primary_text = NULL; switch (type) { case CSM_DIALOG_LOGOUT_TYPE_LOGOUT: icon_name = CSM_ICON_LOGOUT; primary_text = _("Log out of this system now?"); logout_dialog->priv->default_response = CSM_LOGOUT_RESPONSE_LOGOUT; if (csm_logout_supports_switch_user (logout_dialog)) { gtk_dialog_add_button (GTK_DIALOG (logout_dialog), _("_Switch User"), CSM_LOGOUT_RESPONSE_SWITCH_USER); } gtk_dialog_add_button (GTK_DIALOG (logout_dialog), _("_Cancel"), GTK_RESPONSE_CANCEL); gtk_dialog_add_button (GTK_DIALOG (logout_dialog), _("_Log Out"), CSM_LOGOUT_RESPONSE_LOGOUT); break; case CSM_DIALOG_LOGOUT_TYPE_SHUTDOWN: icon_name = CSM_ICON_SHUTDOWN; primary_text = _("Shut down this system now?"); logout_dialog->priv->default_response = CSM_LOGOUT_RESPONSE_SHUTDOWN; if (csm_system_can_suspend (logout_dialog->priv->system)) { gtk_dialog_add_button (GTK_DIALOG (logout_dialog), _("S_uspend"), CSM_LOGOUT_RESPONSE_SLEEP); } if (csm_system_can_hibernate (logout_dialog->priv->system)) { gtk_dialog_add_button (GTK_DIALOG (logout_dialog), _("_Hibernate"), CSM_LOGOUT_RESPONSE_HIBERNATE); } if (csm_logout_supports_reboot (logout_dialog)) { gtk_dialog_add_button (GTK_DIALOG (logout_dialog), _("_Restart"), CSM_LOGOUT_RESPONSE_REBOOT); } gtk_dialog_add_button (GTK_DIALOG (logout_dialog), _("_Cancel"), GTK_RESPONSE_CANCEL); if (csm_logout_supports_shutdown (logout_dialog)) { gtk_dialog_add_button (GTK_DIALOG (logout_dialog), _("_Shut Down"), CSM_LOGOUT_RESPONSE_SHUTDOWN); } break; case CSM_DIALOG_LOGOUT_TYPE_REBOOT: icon_name = CSM_ICON_SHUTDOWN; primary_text = _("Restart this system now?"); logout_dialog->priv->default_response = CSM_LOGOUT_RESPONSE_REBOOT; gtk_dialog_add_button (GTK_DIALOG (logout_dialog), _("_Cancel"), GTK_RESPONSE_CANCEL); if (csm_logout_supports_reboot (logout_dialog)) { gtk_dialog_add_button (GTK_DIALOG (logout_dialog), _("_Restart"), CSM_LOGOUT_RESPONSE_REBOOT); } break; default: g_assert_not_reached (); } if (logout_dialog->priv->delay_toggle) { hbox = gtk_box_new (FALSE, 0); logout_dialog->priv->progressbar = gtk_progress_bar_new (); gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (logout_dialog->priv->progressbar), 1.0); gtk_box_pack_start (GTK_BOX (hbox), logout_dialog->priv->progressbar, TRUE, TRUE, 12); gtk_widget_show_all (hbox); gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (logout_dialog))), hbox); } gtk_window_set_icon_name (GTK_WINDOW (logout_dialog), icon_name); gtk_window_set_position (GTK_WINDOW (logout_dialog), GTK_WIN_POS_CENTER); gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (logout_dialog), primary_text); gtk_dialog_set_default_response (GTK_DIALOG (logout_dialog), logout_dialog->priv->default_response); gtk_window_set_screen (GTK_WINDOW (logout_dialog), screen); g_object_unref(settings); return GTK_WIDGET (logout_dialog); } GtkWidget * csm_get_shutdown_dialog (GdkScreen *screen, guint32 activate_time, CsmDialogLogoutType type) { return csm_get_dialog (type, screen, activate_time); } GtkWidget * csm_get_logout_dialog (GdkScreen *screen, guint32 activate_time) { return csm_get_dialog (CSM_DIALOG_LOGOUT_TYPE_LOGOUT, screen, activate_time); } cinnamon-session-3.6.1/cinnamon-session/csm-logout-dialog.h0000644000175000017500000000545513205266677022533 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006 Vincent Untz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Authors: * Vincent Untz */ #ifndef __CSM_LOGOUT_DIALOG_H__ #define __CSM_LOGOUT_DIALOG_H__ #include G_BEGIN_DECLS enum { CSM_LOGOUT_RESPONSE_LOGOUT, CSM_LOGOUT_RESPONSE_SWITCH_USER, CSM_LOGOUT_RESPONSE_SHUTDOWN, CSM_LOGOUT_RESPONSE_REBOOT, CSM_LOGOUT_RESPONSE_HIBERNATE, CSM_LOGOUT_RESPONSE_SLEEP }; typedef enum { CSM_DIALOG_LOGOUT_TYPE_LOGOUT, CSM_DIALOG_LOGOUT_TYPE_SHUTDOWN, CSM_DIALOG_LOGOUT_TYPE_REBOOT } CsmDialogLogoutType; #define CSM_TYPE_LOGOUT_DIALOG (csm_logout_dialog_get_type ()) #define CSM_LOGOUT_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSM_TYPE_LOGOUT_DIALOG, CsmLogoutDialog)) #define CSM_LOGOUT_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSM_TYPE_LOGOUT_DIALOG, CsmLogoutDialogClass)) #define CSM_IS_LOGOUT_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSM_TYPE_LOGOUT_DIALOG)) #define CSM_IS_LOGOUT_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSM_TYPE_LOGOUT_DIALOG)) #define CSM_LOGOUT_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSM_TYPE_LOGOUT_DIALOG, CsmLogoutDialogClass)) typedef struct _CsmLogoutDialog CsmLogoutDialog; typedef struct _CsmLogoutDialogClass CsmLogoutDialogClass; typedef struct _CsmLogoutDialogPrivate CsmLogoutDialogPrivate; struct _CsmLogoutDialog { GtkMessageDialog parent; CsmLogoutDialogPrivate *priv; }; struct _CsmLogoutDialogClass { GtkMessageDialogClass parent_class; }; GType csm_logout_dialog_get_type (void) G_GNUC_CONST; GtkWidget *csm_get_logout_dialog (GdkScreen *screen, guint32 activate_time); GtkWidget *csm_get_shutdown_dialog (GdkScreen *screen, guint32 activate_time, CsmDialogLogoutType type); G_END_DECLS #endif /* __CSM_LOGOUT_DIALOG_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-manager.c0000644000175000017500000043453213205266677021374 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Novell, Inc. * Copyright (C) 2008 Red Hat, Inc. * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for logout dialog */ #include #include "csm-manager.h" #include "csm-manager-glue.h" #include "csm-store.h" #include "csm-inhibitor.h" #include "csm-presence.h" #include "csm-xsmp-server.h" #include "csm-xsmp-client.h" #include "csm-dbus-client.h" #include "csm-autostart-app.h" #include "csm-util.h" #include "mdm.h" #include "csm-logout-dialog.h" #include "csm-fail-whale-dialog.h" #include "csm-icon-names.h" #include "csm-inhibit-dialog.h" #include "csm-system.h" #include "csm-session-save.h" #define CSM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_MANAGER, CsmManagerPrivate)) #define CSM_MANAGER_DBUS_PATH "/org/gnome/SessionManager" #define CSM_MANAGER_DBUS_NAME "org.gnome.SessionManager" /* Probably about the longest amount of time someone could reasonably * want to wait, at least for something happening more than once. * We can get deployed on very slow media though like CDROM devices, * often with complex stacking/compressing filesystems on top, which * is not a recipie for speed. Particularly now that we throw up * a fail whale if required components don't show up quickly enough, * let's make this fairly long. */ #define CSM_MANAGER_PHASE_TIMEOUT 30 /* seconds */ #define MDM_FLEXISERVER_COMMAND "mdmflexiserver" #define MDM_FLEXISERVER_ARGS "--startnew Standard" #define GDM_FLEXISERVER_COMMAND "gdmflexiserver" #define GDM_FLEXISERVER_ARGS "--startnew Standard" #define SESSION_SCHEMA "org.cinnamon.desktop.session" #define KEY_IDLE_DELAY "idle-delay" #define KEY_SESSION_NAME "session-name" #define CSM_MANAGER_SCHEMA "org.cinnamon.SessionManager" #define KEY_AUTOSAVE "auto-save-session" #define KEY_LOGOUT_PROMPT "logout-prompt" #define KEY_SHOW_FALLBACK_WARNING "show-fallback-warning" #define KEY_BLACKLIST "autostart-blacklist" #define KEY_PREFER_HYBRID_SLEEP "prefer-hybrid-sleep" #define POWER_SETTINGS_SCHEMA "org.cinnamon.settings-daemon.plugins.power" #define KEY_LOCK_ON_SUSPEND "lock-on-suspend" #define LOCKDOWN_SCHEMA "org.cinnamon.desktop.lockdown" #define KEY_DISABLE_LOG_OUT "disable-log-out" #define KEY_DISABLE_USER_SWITCHING "disable-user-switching" static void app_registered (CsmApp *app, CsmManager *manager); typedef enum { CSM_MANAGER_LOGOUT_NONE, CSM_MANAGER_LOGOUT_LOGOUT, CSM_MANAGER_LOGOUT_REBOOT, CSM_MANAGER_LOGOUT_REBOOT_INTERACT, CSM_MANAGER_LOGOUT_REBOOT_MDM, CSM_MANAGER_LOGOUT_SHUTDOWN, CSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT, CSM_MANAGER_LOGOUT_SHUTDOWN_MDM } CsmManagerLogoutType; struct CsmManagerPrivate { gboolean failsafe; CsmStore *clients; CsmStore *inhibitors; CsmInhibitorFlag inhibited_actions; CsmStore *apps; CsmPresence *presence; CsmXsmpServer *xsmp_server; char *session_name; gboolean is_fallback_session : 1; /* Current status */ CsmManagerPhase phase; guint phase_timeout_id; GSList *required_apps; GSList *pending_apps; CsmManagerLogoutMode logout_mode; GSList *query_clients; guint query_timeout_id; /* This is used for CSM_MANAGER_PHASE_END_SESSION only at the moment, * since it uses a sublist of all running client that replied in a * specific way */ GSList *next_query_clients; /* This is the action that will be done just before we exit */ CsmManagerLogoutType logout_type; GtkWidget *inhibit_dialog; /* List of clients which were disconnected due to disabled condition * and shouldn't be automatically restarted */ GSList *condition_clients; GSettings *settings; GSettings *session_settings; GSettings *power_settings; GSettings *lockdown_settings; CsmSystem *system; DBusGProxy *bus_proxy; DBusGConnection *connection; gboolean dbus_disconnected : 1; ca_context *ca; gboolean logout_sound_is_playing; }; enum { PROP_0, PROP_CLIENT_STORE, PROP_INHIBITED_ACTIONS, PROP_SESSION_NAME, PROP_FALLBACK, PROP_FAILSAFE }; enum { PHASE_CHANGED, CLIENT_ADDED, CLIENT_REMOVED, INHIBITOR_ADDED, INHIBITOR_REMOVED, SESSION_RUNNING, SESSION_OVER, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0 }; static void csm_manager_finalize (GObject *object); static void maybe_save_session (CsmManager *manager); static void maybe_play_logout_sound (CsmManager *manager); static gboolean _log_out_is_locked_down (CsmManager *manager); static gboolean _switch_user_is_locked_down (CsmManager *manager); static void _handle_client_end_session_response (CsmManager *manager, CsmClient *client, gboolean is_ok, gboolean do_last, gboolean cancel, const char *reason); static gpointer manager_object = NULL; G_DEFINE_TYPE (CsmManager, csm_manager, G_TYPE_OBJECT) GQuark csm_manager_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("csm_manager_error"); } return ret; } #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } GType csm_manager_error_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { ENUM_ENTRY (CSM_MANAGER_ERROR_GENERAL, "GeneralError"), ENUM_ENTRY (CSM_MANAGER_ERROR_NOT_IN_INITIALIZATION, "NotInInitialization"), ENUM_ENTRY (CSM_MANAGER_ERROR_NOT_IN_RUNNING, "NotInRunning"), ENUM_ENTRY (CSM_MANAGER_ERROR_ALREADY_REGISTERED, "AlreadyRegistered"), ENUM_ENTRY (CSM_MANAGER_ERROR_NOT_REGISTERED, "NotRegistered"), ENUM_ENTRY (CSM_MANAGER_ERROR_INVALID_OPTION, "InvalidOption"), ENUM_ENTRY (CSM_MANAGER_ERROR_LOCKED_DOWN, "LockedDown"), { 0, 0, 0 } }; g_assert (CSM_MANAGER_NUM_ERRORS == G_N_ELEMENTS (values) - 1); etype = g_enum_register_static ("CsmManagerError", values); } return etype; } static gboolean start_app_or_warn (CsmManager *manager, CsmApp *app) { gboolean res; GError *error = NULL; g_debug ("CsmManager: starting app '%s'", csm_app_peek_id (app)); res = csm_app_start (app, &error); if (error != NULL) { g_warning ("Failed to start app: %s", error->message); g_clear_error (&error); } return res; } static gboolean is_app_required (CsmManager *manager, CsmApp *app) { return g_slist_find (manager->priv->required_apps, app) != NULL; } static void on_required_app_failure (CsmManager *manager, CsmApp *app) { gboolean allow_logout; if (csm_system_is_login_session (manager->priv->system)) { allow_logout = FALSE; } else { allow_logout = !_log_out_is_locked_down (manager); } csm_fail_whale_dialog_we_failed (FALSE, allow_logout); } static gboolean _debug_client (const char *id, CsmClient *client, CsmManager *manager) { g_debug ("CsmManager: Client %s", csm_client_peek_id (client)); return FALSE; } static void debug_clients (CsmManager *manager) { csm_store_foreach (manager->priv->clients, (CsmStoreFunc)_debug_client, manager); } static gboolean _debug_inhibitor (const char *id, CsmInhibitor *inhibitor, CsmManager *manager) { g_debug ("CsmManager: Inhibitor app:%s client:%s bus-name:%s reason:%s", csm_inhibitor_peek_app_id (inhibitor), csm_inhibitor_peek_client_id (inhibitor), csm_inhibitor_peek_bus_name (inhibitor), csm_inhibitor_peek_reason (inhibitor)); return FALSE; } static void debug_inhibitors (CsmManager *manager) { csm_store_foreach (manager->priv->inhibitors, (CsmStoreFunc)_debug_inhibitor, manager); } static gboolean _find_by_cookie (const char *id, CsmInhibitor *inhibitor, guint *cookie_ap) { guint cookie_b; cookie_b = csm_inhibitor_peek_cookie (inhibitor); return (*cookie_ap == cookie_b); } static gboolean _client_has_startup_id (const char *id, CsmClient *client, const char *startup_id_a) { const char *startup_id_b; startup_id_b = csm_client_peek_startup_id (client); if (IS_STRING_EMPTY (startup_id_b)) { return FALSE; } return (strcmp (startup_id_a, startup_id_b) == 0); } static void app_condition_changed (CsmApp *app, gboolean condition, CsmManager *manager) { CsmClient *client; g_debug ("CsmManager: app:%s condition changed condition:%d", csm_app_peek_id (app), condition); client = (CsmClient *)csm_store_find (manager->priv->clients, (CsmStoreFunc)_client_has_startup_id, (char *)csm_app_peek_startup_id (app)); if (condition) { if (!csm_app_is_running (app) && client == NULL) { start_app_or_warn (manager, app); } else { g_debug ("CsmManager: not starting - app still running '%s'", csm_app_peek_id (app)); } } else { GError *error; gboolean res; if (client != NULL) { /* Kill client in case condition if false and make sure it won't * be automatically restarted by adding the client to * condition_clients */ manager->priv->condition_clients = g_slist_prepend (manager->priv->condition_clients, client); g_debug ("CsmManager: stopping client %s for app", csm_client_peek_id (client)); error = NULL; res = csm_client_stop (client, &error); if (! res) { g_warning ("Not able to stop app client from its condition: %s", error->message); g_error_free (error); } } else { g_debug ("CsmManager: stopping app %s", csm_app_peek_id (app)); /* If we don't have a client then we should try to kill the app , * if it is running */ error = NULL; if (csm_app_is_running (app)) { res = csm_app_stop (app, &error); if (! res) { g_warning ("Not able to stop app from its condition: %s", error->message); g_error_free (error); } } } } } static const char * phase_num_to_name (guint phase) { const char *name; switch (phase) { case CSM_MANAGER_PHASE_STARTUP: name = "STARTUP"; break; case CSM_MANAGER_PHASE_EARLY_INITIALIZATION: name = "EARLY_INITIALIZATION"; break; case CSM_MANAGER_PHASE_PRE_DISPLAY_SERVER: name = "PRE_DISPLAY_SERVER"; break; case CSM_MANAGER_PHASE_INITIALIZATION: name = "INITIALIZATION"; break; case CSM_MANAGER_PHASE_WINDOW_MANAGER: name = "WINDOW_MANAGER"; break; case CSM_MANAGER_PHASE_PANEL: name = "PANEL"; break; case CSM_MANAGER_PHASE_DESKTOP: name = "DESKTOP"; break; case CSM_MANAGER_PHASE_APPLICATION: name = "APPLICATION"; break; case CSM_MANAGER_PHASE_RUNNING: name = "RUNNING"; break; case CSM_MANAGER_PHASE_QUERY_END_SESSION: name = "QUERY_END_SESSION"; break; case CSM_MANAGER_PHASE_END_SESSION: name = "END_SESSION"; break; case CSM_MANAGER_PHASE_EXIT: name = "EXIT"; break; default: g_assert_not_reached (); break; } return name; } static void start_phase (CsmManager *manager); static void quit_request_failed (CsmSystem *system, GError *error, gpointer user_data) { g_warning ("Using an MDM logout action to shutdown/reboot the system."); MdmLogoutAction fallback_action = GPOINTER_TO_INT (user_data); mdm_set_logout_action (fallback_action); gtk_main_quit (); } static void csm_manager_quit (CsmManager *manager) { /* See the comment in request_reboot() for some more details about how * this works. */ switch (manager->priv->logout_type) { case CSM_MANAGER_LOGOUT_LOGOUT: gtk_main_quit (); break; case CSM_MANAGER_LOGOUT_REBOOT: case CSM_MANAGER_LOGOUT_REBOOT_INTERACT: g_warning ("Requesting system restart..."); mdm_set_logout_action (MDM_LOGOUT_ACTION_NONE); g_signal_connect (manager->priv->system, "request-failed", G_CALLBACK (quit_request_failed), GINT_TO_POINTER (MDM_LOGOUT_ACTION_REBOOT)); csm_system_attempt_restart (manager->priv->system); break; case CSM_MANAGER_LOGOUT_REBOOT_MDM: mdm_set_logout_action (MDM_LOGOUT_ACTION_REBOOT); gtk_main_quit (); break; case CSM_MANAGER_LOGOUT_SHUTDOWN: case CSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT: g_warning ("Requesting system shutdown..."); mdm_set_logout_action (MDM_LOGOUT_ACTION_NONE); g_signal_connect (manager->priv->system, "request-failed", G_CALLBACK (quit_request_failed), GINT_TO_POINTER (MDM_LOGOUT_ACTION_SHUTDOWN)); csm_system_attempt_stop (manager->priv->system); break; case CSM_MANAGER_LOGOUT_SHUTDOWN_MDM: mdm_set_logout_action (MDM_LOGOUT_ACTION_SHUTDOWN); gtk_main_quit (); break; default: g_assert_not_reached (); break; } } static void end_phase (CsmManager *manager) { gboolean start_next_phase = TRUE; g_debug ("CsmManager: ending phase %s\n", phase_num_to_name (manager->priv->phase)); g_slist_free (manager->priv->pending_apps); manager->priv->pending_apps = NULL; g_slist_free (manager->priv->query_clients); manager->priv->query_clients = NULL; g_slist_free (manager->priv->next_query_clients); manager->priv->next_query_clients = NULL; if (manager->priv->query_timeout_id > 0) { g_source_remove (manager->priv->query_timeout_id); manager->priv->query_timeout_id = 0; } if (manager->priv->phase_timeout_id > 0) { g_source_remove (manager->priv->phase_timeout_id); manager->priv->phase_timeout_id = 0; } switch (manager->priv->phase) { case CSM_MANAGER_PHASE_STARTUP: case CSM_MANAGER_PHASE_EARLY_INITIALIZATION: case CSM_MANAGER_PHASE_PRE_DISPLAY_SERVER: case CSM_MANAGER_PHASE_INITIALIZATION: case CSM_MANAGER_PHASE_WINDOW_MANAGER: case CSM_MANAGER_PHASE_PANEL: case CSM_MANAGER_PHASE_DESKTOP: case CSM_MANAGER_PHASE_APPLICATION: break; case CSM_MANAGER_PHASE_RUNNING: if (_log_out_is_locked_down (manager)) { g_warning ("Unable to logout: Logout has been locked down"); start_next_phase = FALSE; } break; case CSM_MANAGER_PHASE_QUERY_END_SESSION: break; case CSM_MANAGER_PHASE_END_SESSION: maybe_play_logout_sound (manager); maybe_save_session (manager); break; case CSM_MANAGER_PHASE_EXIT: start_next_phase = FALSE; csm_manager_quit (manager); break; default: g_assert_not_reached (); break; } if (start_next_phase) { manager->priv->phase++; start_phase (manager); } } static void app_event_during_startup (CsmManager *manager, CsmApp *app) { if (!(manager->priv->phase < CSM_MANAGER_PHASE_APPLICATION)) return; manager->priv->pending_apps = g_slist_remove (manager->priv->pending_apps, app); if (manager->priv->pending_apps == NULL) { if (manager->priv->phase_timeout_id > 0) { g_source_remove (manager->priv->phase_timeout_id); manager->priv->phase_timeout_id = 0; } end_phase (manager); } } static void _restart_app (CsmManager *manager, CsmApp *app) { GError *error = NULL; if (!csm_app_restart (app, &error)) { if (is_app_required (manager, app)) { on_required_app_failure (manager, app); } else { g_warning ("Error on restarting session managed app: %s", error->message); } g_clear_error (&error); app_event_during_startup (manager, app); } } static void app_died (CsmApp *app, int signal, CsmManager *manager) { g_warning ("Application '%s' killed by signal %d", csm_app_peek_app_id (app), signal); if (csm_app_peek_autorestart (app)) { g_debug ("Component '%s' is autorestart, ignoring died signal", csm_app_peek_app_id (app)); return; } _restart_app (manager, app); /* For now, we don't do anything with crashes from * non-required apps after they hit the restart limit. * * Note that both required and not-required apps will be * caught by ABRT/apport type infrastructure, and it'd be * better to pick up the crash from there and do something * un-intrusive about it generically. */ } static void app_exited (CsmApp *app, guchar exit_code, CsmManager *manager) { g_debug ("App %s exited with %d", csm_app_peek_app_id (app), exit_code); /* Consider that non-success exit status means "crash" for required components */ if (exit_code != 0 && is_app_required (manager, app)) { if (csm_app_peek_autorestart (app)) { g_debug ("Component '%s' is autorestart, ignoring non-successful exit", csm_app_peek_app_id (app)); return; } _restart_app (manager, app); } else { app_event_during_startup (manager, app); } } static void app_registered (CsmApp *app, CsmManager *manager) { g_debug ("App %s registered", csm_app_peek_app_id (app)); app_event_during_startup (manager, app); } static gboolean on_phase_timeout (CsmManager *manager) { GSList *a; manager->priv->phase_timeout_id = 0; switch (manager->priv->phase) { case CSM_MANAGER_PHASE_STARTUP: case CSM_MANAGER_PHASE_EARLY_INITIALIZATION: case CSM_MANAGER_PHASE_PRE_DISPLAY_SERVER: case CSM_MANAGER_PHASE_INITIALIZATION: case CSM_MANAGER_PHASE_WINDOW_MANAGER: case CSM_MANAGER_PHASE_PANEL: case CSM_MANAGER_PHASE_DESKTOP: case CSM_MANAGER_PHASE_APPLICATION: for (a = manager->priv->pending_apps; a; a = a->next) { CsmApp *app = a->data; g_warning ("Application '%s' failed to register before timeout", csm_app_peek_app_id (app)); if (is_app_required (manager, app)) on_required_app_failure (manager, app); } break; case CSM_MANAGER_PHASE_RUNNING: break; case CSM_MANAGER_PHASE_QUERY_END_SESSION: case CSM_MANAGER_PHASE_END_SESSION: break; case CSM_MANAGER_PHASE_EXIT: break; default: g_assert_not_reached (); break; } end_phase (manager); return FALSE; } static gboolean _autostart_delay_timeout (CsmApp *app) { GError *error = NULL; gboolean res; if (!csm_app_peek_is_disabled (app) && !csm_app_peek_is_conditionally_disabled (app)) { res = csm_app_start (app, &error); if (!res) { if (error != NULL) { g_warning ("Could not launch application '%s': %s", csm_app_peek_app_id (app), error->message); g_error_free (error); } } } g_object_unref (app); return FALSE; } static gboolean _start_app (const char *id, CsmApp *app, CsmManager *manager) { int delay; if (csm_app_peek_phase (app) != manager->priv->phase) { goto out; } /* Keep track of app autostart condition in order to react * accordingly in the future. */ g_signal_connect (app, "condition-changed", G_CALLBACK (app_condition_changed), manager); if (csm_app_peek_is_disabled (app) || csm_app_peek_is_conditionally_disabled (app)) { g_debug ("CsmManager: Skipping disabled app: %s", id); goto out; } delay = csm_app_peek_autostart_delay (app); if (delay > 0) { g_timeout_add_seconds (delay, (GSourceFunc)_autostart_delay_timeout, g_object_ref (app)); g_debug ("CsmManager: %s is scheduled to start in %d seconds", id, delay); goto out; } if (!start_app_or_warn (manager, app)) goto out; if (manager->priv->phase < CSM_MANAGER_PHASE_APPLICATION) { /* Historical note - apparently, * e.g. gnome-settings-daemon used to "daemonize", and * so cinnamon-session assumes process exit means "ok * we're done". Of course this is broken, we don't * even distinguish between exit code 0 versus not-0, * nor do we have any metadata which tells us a * process is going to "daemonize" or not (and * basically nothing should be anyways). */ g_signal_connect (app, "exited", G_CALLBACK (app_exited), manager); g_signal_connect (app, "registered", G_CALLBACK (app_registered), manager); g_signal_connect (app, "died", G_CALLBACK (app_died), manager); manager->priv->pending_apps = g_slist_prepend (manager->priv->pending_apps, app); } out: return FALSE; } static void do_phase_startup (CsmManager *manager) { csm_store_foreach (manager->priv->apps, (CsmStoreFunc)_start_app, manager); if (manager->priv->pending_apps != NULL) { if (manager->priv->phase < CSM_MANAGER_PHASE_APPLICATION) { manager->priv->phase_timeout_id = g_timeout_add_seconds (CSM_MANAGER_PHASE_TIMEOUT, (GSourceFunc)on_phase_timeout, manager); } } else { end_phase (manager); } } typedef struct { CsmManager *manager; guint flags; } ClientEndSessionData; static gboolean _client_end_session (CsmClient *client, ClientEndSessionData *data) { gboolean ret; GError *error; error = NULL; ret = csm_client_end_session (client, data->flags, &error); if (! ret) { g_warning ("Unable to query client: %s", error->message); g_error_free (error); /* FIXME: what should we do if we can't communicate with client? */ } else { g_debug ("CsmManager: adding client to end-session clients: %s", csm_client_peek_id (client)); data->manager->priv->query_clients = g_slist_prepend (data->manager->priv->query_clients, client); } return FALSE; } static gboolean _client_end_session_helper (const char *id, CsmClient *client, ClientEndSessionData *data) { return _client_end_session (client, data); } static void do_phase_end_session (CsmManager *manager) { ClientEndSessionData data; data.manager = manager; data.flags = 0; if (manager->priv->logout_mode == CSM_MANAGER_LOGOUT_MODE_FORCE) { data.flags |= CSM_CLIENT_END_SESSION_FLAG_FORCEFUL; } if (csm_manager_get_autosave_enabled (manager)) { data.flags |= CSM_CLIENT_END_SESSION_FLAG_SAVE; } if (manager->priv->phase_timeout_id > 0) { g_source_remove (manager->priv->phase_timeout_id); manager->priv->phase_timeout_id = 0; } if (csm_store_size (manager->priv->clients) > 0) { manager->priv->phase_timeout_id = g_timeout_add_seconds (CSM_MANAGER_PHASE_TIMEOUT, (GSourceFunc)on_phase_timeout, manager); csm_store_foreach (manager->priv->clients, (CsmStoreFunc)_client_end_session_helper, &data); } else { end_phase (manager); } } static void do_phase_end_session_part_2 (CsmManager *manager) { ClientEndSessionData data; data.manager = manager; data.flags = 0; if (manager->priv->logout_mode == CSM_MANAGER_LOGOUT_MODE_FORCE) { data.flags |= CSM_CLIENT_END_SESSION_FLAG_FORCEFUL; } if (csm_manager_get_autosave_enabled (manager)) { data.flags |= CSM_CLIENT_END_SESSION_FLAG_SAVE; } data.flags |= CSM_CLIENT_END_SESSION_FLAG_LAST; /* keep the timeout that was started at the beginning of the * CSM_MANAGER_PHASE_END_SESSION phase */ if (g_slist_length (manager->priv->next_query_clients) > 0) { g_slist_foreach (manager->priv->next_query_clients, (GFunc)_client_end_session, &data); g_slist_free (manager->priv->next_query_clients); manager->priv->next_query_clients = NULL; } else { end_phase (manager); } } static gboolean _client_stop (const char *id, CsmClient *client, gpointer user_data) { gboolean ret; GError *error; error = NULL; ret = csm_client_stop (client, &error); if (! ret) { g_warning ("Unable to stop client: %s", error->message); g_error_free (error); /* FIXME: what should we do if we can't communicate with client? */ } else { g_debug ("CsmManager: stopped client: %s", csm_client_peek_id (client)); } return FALSE; } static void maybe_restart_user_bus (CsmManager *manager) { CsmSystem *system; g_autoptr(GVariant) reply = NULL; g_autoptr(GError) error = NULL; if (manager->priv->dbus_disconnected) return; system = csm_get_system (); if (!csm_system_is_last_session_for_user (system)) return; reply = g_dbus_connection_call_sync (manager->priv->connection, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "TryRestartUnit", g_variant_new ("(ss)", "dbus.service", "replace"), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (error != NULL) { g_debug ("CsmManager: reloading user bus failed: %s", error->message); } } static void do_phase_exit (CsmManager *manager) { if (csm_store_size (manager->priv->clients) > 0) { csm_store_foreach (manager->priv->clients, (CsmStoreFunc)_client_stop, NULL); } if (WITH_DBUS_USER_SESSION) { maybe_restart_user_bus (manager); } end_phase (manager); } static gboolean _client_query_end_session (const char *id, CsmClient *client, ClientEndSessionData *data) { gboolean ret; GError *error; error = NULL; ret = csm_client_query_end_session (client, data->flags, &error); if (! ret) { g_warning ("Unable to query client: %s", error->message); g_error_free (error); /* FIXME: what should we do if we can't communicate with client? */ } else { g_debug ("CsmManager: adding client to query clients: %s", csm_client_peek_id (client)); data->manager->priv->query_clients = g_slist_prepend (data->manager->priv->query_clients, client); } return FALSE; } static gboolean inhibitor_has_flag (gpointer key, CsmInhibitor *inhibitor, gpointer data) { guint flag; guint flags; flag = GPOINTER_TO_UINT (data); flags = csm_inhibitor_peek_flags (inhibitor); return (flags & flag); } static gboolean csm_manager_is_logout_inhibited (CsmManager *manager) { CsmInhibitor *inhibitor; if (manager->priv->inhibitors == NULL) { return FALSE; } inhibitor = (CsmInhibitor *)csm_store_find (manager->priv->inhibitors, (CsmStoreFunc)inhibitor_has_flag, GUINT_TO_POINTER (CSM_INHIBITOR_FLAG_LOGOUT)); if (inhibitor == NULL) { return FALSE; } return TRUE; } static gboolean csm_manager_is_idle_inhibited (CsmManager *manager) { CsmInhibitor *inhibitor; if (manager->priv->inhibitors == NULL) { return FALSE; } inhibitor = (CsmInhibitor *)csm_store_find (manager->priv->inhibitors, (CsmStoreFunc)inhibitor_has_flag, GUINT_TO_POINTER (CSM_INHIBITOR_FLAG_IDLE)); if (inhibitor == NULL) { return FALSE; } return TRUE; } static gboolean _client_cancel_end_session (const char *id, CsmClient *client, CsmManager *manager) { gboolean res; GError *error; error = NULL; res = csm_client_cancel_end_session (client, &error); if (! res) { g_warning ("Unable to cancel end session: %s", error->message); g_error_free (error); } return FALSE; } static gboolean inhibitor_is_jit (gpointer key, CsmInhibitor *inhibitor, CsmManager *manager) { gboolean matches; const char *id; id = csm_inhibitor_peek_client_id (inhibitor); matches = (id != NULL && id[0] != '\0'); return matches; } static void cancel_end_session (CsmManager *manager) { /* just ignore if received outside of shutdown */ if (manager->priv->phase < CSM_MANAGER_PHASE_QUERY_END_SESSION) { return; } /* switch back to running phase */ g_debug ("CsmManager: Cancelling the end of session"); /* remove the dialog before we remove the inhibitors, else the dialog * will activate itself automatically when the last inhibitor will be * removed */ if (manager->priv->inhibit_dialog) gtk_widget_destroy (GTK_WIDGET (manager->priv->inhibit_dialog)); manager->priv->inhibit_dialog = NULL; /* clear all JIT inhibitors */ csm_store_foreach_remove (manager->priv->inhibitors, (CsmStoreFunc)inhibitor_is_jit, (gpointer)manager); csm_store_foreach (manager->priv->clients, (CsmStoreFunc)_client_cancel_end_session, NULL); csm_manager_set_phase (manager, CSM_MANAGER_PHASE_RUNNING); manager->priv->logout_mode = CSM_MANAGER_LOGOUT_MODE_NORMAL; manager->priv->logout_type = CSM_MANAGER_LOGOUT_NONE; mdm_set_logout_action (MDM_LOGOUT_ACTION_NONE); start_phase (manager); } static gboolean process_is_running (const char * name) { int num_processes; gchar *command = g_strdup_printf ("pidof %s | wc -l", name); FILE *fp = popen(command, "r"); fscanf(fp, "%d", &num_processes); pclose(fp); g_free (command); if (num_processes > 0) { return TRUE; } else { return FALSE; } } static gboolean sleep_lock_is_enabled (CsmManager *manager) { return g_settings_get_boolean (manager->priv->power_settings, KEY_LOCK_ON_SUSPEND); } static void manager_perhaps_lock (CsmManager *manager) { GError *error; gboolean ret; /* only lock if the user has selected 'lock-on-suspend' in power prefs */ if (!sleep_lock_is_enabled (manager)) { return; } /* do this sync to ensure it's on the screen when we start suspending */ error = NULL; ret = g_spawn_command_line_sync ("cinnamon-screensaver-command --lock", NULL, NULL, NULL, &error); if (!ret) { g_warning ("Couldn't lock screen: %s", error->message); g_error_free (error); } } static void manager_switch_user (GdkDisplay *display, CsmManager *manager) { GError *error; char *command; GAppLaunchContext *context; GAppInfo *app; /* We have to do this here and in request_switch_user() because this * function can be called at a later time, not just directly after * request_switch_user(). */ if (_switch_user_is_locked_down (manager)) { g_warning ("Unable to switch user: User switching has been locked down"); return; } if (process_is_running("mdm")) { command = g_strdup_printf ("%s %s", MDM_FLEXISERVER_COMMAND, MDM_FLEXISERVER_ARGS); error = NULL; context = (GAppLaunchContext*) gdk_display_get_app_launch_context (display); app = g_app_info_create_from_commandline (command, MDM_FLEXISERVER_COMMAND, 0, &error); if (app) { g_app_info_launch (app, NULL, context, &error); g_object_unref (app); } g_free (command); g_object_unref (context); if (error) { g_debug ("CsmManager: Unable to start MDM greeter: %s", error->message); g_error_free (error); } } else if (process_is_running("gdm") || process_is_running("gdm3")) { command = g_strdup_printf ("%s %s", GDM_FLEXISERVER_COMMAND, GDM_FLEXISERVER_ARGS); error = NULL; context = (GAppLaunchContext*) gdk_display_get_app_launch_context (display); app = g_app_info_create_from_commandline (command, GDM_FLEXISERVER_COMMAND, 0, &error); if (app) { manager_perhaps_lock (manager); g_app_info_launch (app, NULL, context, &error); g_object_unref (app); } g_free (command); g_object_unref (context); if (error) { g_debug ("CsmManager: Unable to start GDM greeter: %s", error->message); g_error_free (error); } } else if (g_getenv ("XDG_SEAT_PATH")) { GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START; GDBusProxy *proxy = NULL; error = NULL; proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, flags, NULL, "org.freedesktop.DisplayManager", g_getenv ("XDG_SEAT_PATH"), "org.freedesktop.DisplayManager.Seat", NULL, &error); if (proxy != NULL) { manager_perhaps_lock (manager); g_dbus_proxy_call (proxy, "SwitchToGreeter", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); g_object_unref (proxy); } else { g_debug ("CsmManager: Unable to start LightDM greeter: %s", error->message); g_error_free (error); } } } static void manager_attempt_hibernate (CsmManager *manager) { /* lock the screen before we try anything. If it all fails, at least the screen is locked * (if preferences dictate it) */ manager_perhaps_lock (manager); if (csm_system_can_hibernate (manager->priv->system)) { csm_system_hibernate (manager->priv->system); } } static void manager_attempt_suspend (CsmManager *manager) { /* lock the screen before we try anything. If it all fails, at least the screen is locked * (if preferences dictate it) */ manager_perhaps_lock (manager); if (g_settings_get_boolean (manager->priv->settings, KEY_PREFER_HYBRID_SLEEP) && csm_system_can_hybrid_sleep (manager->priv->system)) { csm_system_hybrid_sleep (manager->priv->system); } else if (csm_system_can_suspend (manager->priv->system)) { csm_system_suspend (manager->priv->system); } } static void do_inhibit_dialog_action (GdkDisplay *display, CsmManager *manager, int action) { switch (action) { case CSM_LOGOUT_ACTION_SWITCH_USER: manager_switch_user (display, manager); break; case CSM_LOGOUT_ACTION_HIBERNATE: manager_attempt_hibernate (manager); break; case CSM_LOGOUT_ACTION_SLEEP: manager_attempt_suspend (manager); break; case CSM_LOGOUT_ACTION_SHUTDOWN: case CSM_LOGOUT_ACTION_REBOOT: case CSM_LOGOUT_ACTION_LOGOUT: manager->priv->logout_mode = CSM_MANAGER_LOGOUT_MODE_FORCE; end_phase (manager); break; default: g_assert_not_reached (); break; } } static void inhibit_dialog_response (CsmInhibitDialog *dialog, guint response_id, CsmManager *manager) { GdkDisplay *display; int action; g_debug ("CsmManager: Inhibit dialog response: %d", response_id); display = gtk_widget_get_display (GTK_WIDGET (dialog)); /* must destroy dialog before cancelling since we'll remove JIT inhibitors and we don't want to trigger action. */ g_object_get (dialog, "action", &action, NULL); gtk_widget_destroy (GTK_WIDGET (dialog)); manager->priv->inhibit_dialog = NULL; /* In case of dialog cancel, switch user, hibernate and * suspend, we just perform the respective action and return, * without shutting down the session. */ switch (response_id) { case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_NONE: case GTK_RESPONSE_DELETE_EVENT: if (action == CSM_LOGOUT_ACTION_LOGOUT || action == CSM_LOGOUT_ACTION_SHUTDOWN || action == CSM_LOGOUT_ACTION_REBOOT) { cancel_end_session (manager); } break; case GTK_RESPONSE_ACCEPT: g_debug ("CsmManager: doing action %d", action); do_inhibit_dialog_action (display, manager, action); break; default: g_assert_not_reached (); break; } } static void end_session_or_show_fallback_dialog (CsmManager *manager) { CsmLogoutAction action; if (! csm_manager_is_logout_inhibited (manager)) { end_phase (manager); return; } if (manager->priv->inhibit_dialog != NULL) { g_debug ("CsmManager: inhibit dialog already up"); gtk_window_present (GTK_WINDOW (manager->priv->inhibit_dialog)); return; } switch (manager->priv->logout_type) { case CSM_MANAGER_LOGOUT_LOGOUT: action = CSM_LOGOUT_ACTION_LOGOUT; break; case CSM_MANAGER_LOGOUT_REBOOT: case CSM_MANAGER_LOGOUT_REBOOT_INTERACT: case CSM_MANAGER_LOGOUT_REBOOT_MDM: action = CSM_LOGOUT_ACTION_REBOOT; break; case CSM_MANAGER_LOGOUT_SHUTDOWN: case CSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT: case CSM_MANAGER_LOGOUT_SHUTDOWN_MDM: action = CSM_LOGOUT_ACTION_SHUTDOWN; break; default: g_warning ("Unexpected logout type %d when creating inhibit dialog", manager->priv->logout_type); action = CSM_LOGOUT_ACTION_LOGOUT; break; } /* Note: CSM_LOGOUT_ACTION_SHUTDOWN and CSM_LOGOUT_ACTION_REBOOT are * actually handled the same way as CSM_LOGOUT_ACTION_LOGOUT in the * inhibit dialog; the action, if the button is clicked, will be to * simply go to the next phase. */ manager->priv->inhibit_dialog = csm_inhibit_dialog_new (manager->priv->inhibitors, manager->priv->clients, action); g_signal_connect (manager->priv->inhibit_dialog, "response", G_CALLBACK (inhibit_dialog_response), manager); gtk_widget_show (manager->priv->inhibit_dialog); } static void query_end_session_complete (CsmManager *manager) { g_debug ("CsmManager: query end session complete"); /* Remove the timeout since this can be called from outside the timer * and we don't want to have it called twice */ if (manager->priv->query_timeout_id > 0) { g_source_remove (manager->priv->query_timeout_id); manager->priv->query_timeout_id = 0; } end_session_or_show_fallback_dialog (manager); } static guint32 generate_cookie (void) { guint32 cookie; cookie = (guint32)g_random_int_range (1, G_MAXINT32); return cookie; } static guint32 _generate_unique_cookie (CsmManager *manager) { guint32 cookie; do { cookie = generate_cookie (); } while (csm_store_find (manager->priv->inhibitors, (CsmStoreFunc)_find_by_cookie, &cookie) != NULL); return cookie; } static gboolean _on_query_end_session_timeout (CsmManager *manager) { GSList *l; manager->priv->query_timeout_id = 0; g_debug ("CsmManager: query end session timed out"); for (l = manager->priv->query_clients; l != NULL; l = l->next) { guint cookie; CsmInhibitor *inhibitor; const char *bus_name; char *app_id; g_warning ("Client '%s' failed to reply before timeout", csm_client_peek_id (l->data)); /* Don't add "not responding" inhibitors if logout is forced */ if (manager->priv->logout_mode == CSM_MANAGER_LOGOUT_MODE_FORCE) { continue; } /* Add JIT inhibit for unresponsive client */ if (CSM_IS_DBUS_CLIENT (l->data)) { bus_name = csm_dbus_client_get_bus_name (l->data); } else { bus_name = NULL; } app_id = g_strdup (csm_client_peek_app_id (l->data)); if (IS_STRING_EMPTY (app_id)) { /* XSMP clients don't give us an app id unless we start them */ g_free (app_id); app_id = csm_client_get_app_name (l->data); } cookie = _generate_unique_cookie (manager); inhibitor = csm_inhibitor_new_for_client (csm_client_peek_id (l->data), app_id, CSM_INHIBITOR_FLAG_LOGOUT, _("Not responding"), bus_name, cookie); g_free (app_id); csm_store_add (manager->priv->inhibitors, csm_inhibitor_peek_id (inhibitor), G_OBJECT (inhibitor)); g_object_unref (inhibitor); } g_slist_free (manager->priv->query_clients); manager->priv->query_clients = NULL; query_end_session_complete (manager); return FALSE; } static void do_phase_query_end_session (CsmManager *manager) { ClientEndSessionData data; data.manager = manager; data.flags = 0; if (manager->priv->logout_mode == CSM_MANAGER_LOGOUT_MODE_FORCE) { data.flags |= CSM_CLIENT_END_SESSION_FLAG_FORCEFUL; } /* We only query if an app is ready to log out, so we don't use * CSM_CLIENT_END_SESSION_FLAG_SAVE here. */ debug_clients (manager); g_debug ("CsmManager: sending query-end-session to clients (logout mode: %s)", manager->priv->logout_mode == CSM_MANAGER_LOGOUT_MODE_NORMAL? "normal" : manager->priv->logout_mode == CSM_MANAGER_LOGOUT_MODE_FORCE? "forceful": "no confirmation"); csm_store_foreach (manager->priv->clients, (CsmStoreFunc)_client_query_end_session, &data); /* This phase doesn't time out unless logout is forced. Typically, this * separate timer is only used to show UI. */ manager->priv->query_timeout_id = g_timeout_add_seconds (1, (GSourceFunc)_on_query_end_session_timeout, manager); } static void update_idle (CsmManager *manager) { if (csm_manager_is_idle_inhibited (manager)) { csm_presence_set_idle_enabled (manager->priv->presence, FALSE); } else { csm_presence_set_idle_enabled (manager->priv->presence, TRUE); } } static void start_phase (CsmManager *manager) { g_debug ("CsmManager: starting phase %s\n", phase_num_to_name (manager->priv->phase)); /* reset state */ g_slist_free (manager->priv->pending_apps); manager->priv->pending_apps = NULL; g_slist_free (manager->priv->query_clients); manager->priv->query_clients = NULL; g_slist_free (manager->priv->next_query_clients); manager->priv->next_query_clients = NULL; if (manager->priv->query_timeout_id > 0) { g_source_remove (manager->priv->query_timeout_id); manager->priv->query_timeout_id = 0; } if (manager->priv->phase_timeout_id > 0) { g_source_remove (manager->priv->phase_timeout_id); manager->priv->phase_timeout_id = 0; } switch (manager->priv->phase) { case CSM_MANAGER_PHASE_STARTUP: case CSM_MANAGER_PHASE_EARLY_INITIALIZATION: case CSM_MANAGER_PHASE_PRE_DISPLAY_SERVER: case CSM_MANAGER_PHASE_INITIALIZATION: case CSM_MANAGER_PHASE_WINDOW_MANAGER: case CSM_MANAGER_PHASE_PANEL: case CSM_MANAGER_PHASE_DESKTOP: case CSM_MANAGER_PHASE_APPLICATION: do_phase_startup (manager); break; case CSM_MANAGER_PHASE_RUNNING: csm_xsmp_server_start_accepting_new_clients (manager->priv->xsmp_server); g_signal_emit (manager, signals[SESSION_RUNNING], 0); update_idle (manager); break; case CSM_MANAGER_PHASE_QUERY_END_SESSION: csm_xsmp_server_stop_accepting_new_clients (manager->priv->xsmp_server); do_phase_query_end_session (manager); break; case CSM_MANAGER_PHASE_END_SESSION: do_phase_end_session (manager); break; case CSM_MANAGER_PHASE_EXIT: do_phase_exit (manager); break; default: g_assert_not_reached (); break; } } static gboolean _debug_app_for_phase (const char *id, CsmApp *app, gpointer data) { guint phase; phase = GPOINTER_TO_UINT (data); if (csm_app_peek_phase (app) != phase) { return FALSE; } g_debug ("CsmManager:\tID: %s\tapp-id:%s\tis-disabled:%d\tis-conditionally-disabled:%d\tis-delayed:%d", csm_app_peek_id (app), csm_app_peek_app_id (app), csm_app_peek_is_disabled (app), csm_app_peek_is_conditionally_disabled (app), (csm_app_peek_autostart_delay (app) > 0)); return FALSE; } static void debug_app_summary (CsmManager *manager) { guint phase; g_debug ("CsmManager: App startup summary"); for (phase = CSM_MANAGER_PHASE_EARLY_INITIALIZATION; phase < CSM_MANAGER_PHASE_RUNNING; phase++) { g_debug ("CsmManager: Phase %s", phase_num_to_name (phase)); csm_store_foreach (manager->priv->apps, (CsmStoreFunc)_debug_app_for_phase, GUINT_TO_POINTER (phase)); } } void csm_manager_start (CsmManager *manager) { g_debug ("CsmManager: CSM starting to manage"); g_return_if_fail (CSM_IS_MANAGER (manager)); csm_xsmp_server_start (manager->priv->xsmp_server); csm_manager_set_phase (manager, CSM_MANAGER_PHASE_EARLY_INITIALIZATION); debug_app_summary (manager); start_phase (manager); } const char * _csm_manager_get_default_session (CsmManager *manager) { return g_settings_get_string (manager->priv->session_settings, KEY_SESSION_NAME); } void _csm_manager_set_active_session (CsmManager *manager, const char *session_name, gboolean is_fallback) { g_free (manager->priv->session_name); manager->priv->session_name = g_strdup (session_name); manager->priv->is_fallback_session = is_fallback; } static gboolean _app_has_app_id (const char *id, CsmApp *app, const char *app_id_a) { const char *app_id_b; app_id_b = csm_app_peek_app_id (app); return (app_id_b != NULL && strcmp (app_id_a, app_id_b) == 0); } static CsmApp * find_app_for_app_id (CsmManager *manager, const char *app_id) { CsmApp *app; app = (CsmApp *)csm_store_find (manager->priv->apps, (CsmStoreFunc)_app_has_app_id, (char *)app_id); return app; } static gboolean inhibitor_has_client_id (gpointer key, CsmInhibitor *inhibitor, const char *client_id_a) { gboolean matches; const char *client_id_b; client_id_b = csm_inhibitor_peek_client_id (inhibitor); matches = FALSE; if (! IS_STRING_EMPTY (client_id_a) && ! IS_STRING_EMPTY (client_id_b)) { matches = (strcmp (client_id_a, client_id_b) == 0); if (matches) { g_debug ("CsmManager: removing JIT inhibitor for %s for reason '%s'", csm_inhibitor_peek_client_id (inhibitor), csm_inhibitor_peek_reason (inhibitor)); } } return matches; } static gboolean _app_has_startup_id (const char *id, CsmApp *app, const char *startup_id_a) { const char *startup_id_b; startup_id_b = csm_app_peek_startup_id (app); if (IS_STRING_EMPTY (startup_id_b)) { return FALSE; } return (strcmp (startup_id_a, startup_id_b) == 0); } static CsmApp * find_app_for_startup_id (CsmManager *manager, const char *startup_id) { CsmApp *found_app; GSList *a; found_app = NULL; /* If we're starting up the session, try to match the new client * with one pending apps for the current phase. If not, try to match * with any of the autostarted apps. */ if (manager->priv->phase < CSM_MANAGER_PHASE_APPLICATION) { for (a = manager->priv->pending_apps; a != NULL; a = a->next) { CsmApp *app = CSM_APP (a->data); if (strcmp (startup_id, csm_app_peek_startup_id (app)) == 0) { found_app = app; goto out; } } } else { CsmApp *app; app = (CsmApp *)csm_store_find (manager->priv->apps, (CsmStoreFunc)_app_has_startup_id, (char *)startup_id); if (app != NULL) { found_app = app; goto out; } } out: return found_app; } static void _disconnect_client (CsmManager *manager, CsmClient *client) { gboolean is_condition_client; CsmApp *app; const char *app_id; const char *startup_id; gboolean app_restart; CsmClientRestartStyle client_restart_hint; g_debug ("CsmManager: disconnect client: %s", csm_client_peek_id (client)); /* take a ref so it doesn't get finalized */ g_object_ref (client); csm_client_set_status (client, CSM_CLIENT_FINISHED); is_condition_client = FALSE; if (g_slist_find (manager->priv->condition_clients, client)) { manager->priv->condition_clients = g_slist_remove (manager->priv->condition_clients, client); is_condition_client = TRUE; } /* remove any inhibitors for this client */ csm_store_foreach_remove (manager->priv->inhibitors, (CsmStoreFunc)inhibitor_has_client_id, (gpointer)csm_client_peek_id (client)); app = NULL; /* first try to match on startup ID */ startup_id = csm_client_peek_startup_id (client); if (! IS_STRING_EMPTY (startup_id)) { app = find_app_for_startup_id (manager, startup_id); } /* then try to find matching app-id */ if (app == NULL) { app_id = csm_client_peek_app_id (client); if (! IS_STRING_EMPTY (app_id)) { g_debug ("CsmManager: disconnect for app '%s'", app_id); app = find_app_for_app_id (manager, app_id); } } if (manager->priv->phase == CSM_MANAGER_PHASE_QUERY_END_SESSION) { /* Instead of answering our end session query, the client just exited. * Treat that as an "okay, end the session" answer. * * This call implicitly removes any inhibitors for the client, along * with removing the client from the pending query list. */ _handle_client_end_session_response (manager, client, TRUE, FALSE, FALSE, "Client exited in " "query end session phase " "instead of end session " "phase"); } if (manager->priv->dbus_disconnected && CSM_IS_DBUS_CLIENT (client)) { g_debug ("CsmManager: dbus disconnected, not restarting application"); goto out; } if (app == NULL) { g_debug ("CsmManager: unable to find application for client - not restarting"); goto out; } if (manager->priv->phase >= CSM_MANAGER_PHASE_QUERY_END_SESSION) { g_debug ("CsmManager: in shutdown, not restarting application"); goto out; } app_restart = csm_app_peek_autorestart (app); client_restart_hint = csm_client_peek_restart_style_hint (client); /* allow legacy clients to override the app info */ if (! app_restart && client_restart_hint != CSM_CLIENT_RESTART_IMMEDIATELY) { g_debug ("CsmManager: autorestart not set, not restarting application"); goto out; } if (is_condition_client) { g_debug ("CsmManager: app conditionally disabled, not restarting application"); goto out; } g_debug ("CsmManager: restarting app"); _restart_app (manager, app); out: g_object_unref (client); } typedef struct { const char *service_name; CsmManager *manager; } RemoveClientData; static gboolean _disconnect_dbus_client (const char *id, CsmClient *client, RemoveClientData *data) { const char *name; if (! CSM_IS_DBUS_CLIENT (client)) { return FALSE; } /* If no service name, then we simply disconnect all clients */ if (!data->service_name) { _disconnect_client (data->manager, client); return TRUE; } name = csm_dbus_client_get_bus_name (CSM_DBUS_CLIENT (client)); if (IS_STRING_EMPTY (name)) { return FALSE; } if (strcmp (data->service_name, name) == 0) { _disconnect_client (data->manager, client); return TRUE; } return FALSE; } /** * remove_clients_for_connection: * @manager: a #CsmManager * @service_name: a service name * * Disconnects clients that own @service_name. * * If @service_name is NULL, then disconnects all clients for the connection. */ static void remove_clients_for_connection (CsmManager *manager, const char *service_name) { RemoveClientData data; data.service_name = service_name; data.manager = manager; /* disconnect dbus clients for name */ csm_store_foreach_remove (manager->priv->clients, (CsmStoreFunc)_disconnect_dbus_client, &data); if (manager->priv->phase >= CSM_MANAGER_PHASE_QUERY_END_SESSION && csm_store_size (manager->priv->clients) == 0) { g_debug ("CsmManager: last client disconnected - exiting"); end_phase (manager); } } static gboolean inhibitor_has_bus_name (gpointer key, CsmInhibitor *inhibitor, RemoveClientData *data) { gboolean matches; const char *bus_name_b; bus_name_b = csm_inhibitor_peek_bus_name (inhibitor); matches = FALSE; if (! IS_STRING_EMPTY (data->service_name) && ! IS_STRING_EMPTY (bus_name_b)) { matches = (strcmp (data->service_name, bus_name_b) == 0); if (matches) { g_debug ("CsmManager: removing inhibitor from %s for reason '%s' on connection %s", csm_inhibitor_peek_app_id (inhibitor), csm_inhibitor_peek_reason (inhibitor), csm_inhibitor_peek_bus_name (inhibitor)); } } return matches; } static void remove_inhibitors_for_connection (CsmManager *manager, const char *service_name) { RemoveClientData data; data.service_name = service_name; data.manager = manager; debug_inhibitors (manager); csm_store_foreach_remove (manager->priv->inhibitors, (CsmStoreFunc)inhibitor_has_bus_name, &data); } static void bus_name_owner_changed (DBusGProxy *bus_proxy, const char *service_name, const char *old_service_name, const char *new_service_name, CsmManager *manager) { if (strlen (new_service_name) == 0 && strlen (old_service_name) > 0) { /* service removed */ remove_inhibitors_for_connection (manager, old_service_name); remove_clients_for_connection (manager, old_service_name); } else if (strlen (old_service_name) == 0 && strlen (new_service_name) > 0) { /* service added */ /* use this if we support automatically registering * well known bus names */ } } static DBusHandlerResult csm_manager_bus_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { CsmManager *manager; manager = CSM_MANAGER (user_data); if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") && strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) { g_debug ("CsmManager: dbus disconnected; disconnecting dbus clients..."); manager->priv->dbus_disconnected = TRUE; remove_clients_for_connection (manager, NULL); /* let other filters get this disconnected signal, so that they * can handle it too */ } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static gboolean register_manager (CsmManager *manager) { GError *error = NULL; DBusConnection *connection; error = NULL; manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (manager->priv->connection == NULL) { if (error != NULL) { g_critical ("error getting session bus: %s", error->message); g_error_free (error); } exit (1); } connection = dbus_g_connection_get_connection (manager->priv->connection); dbus_connection_add_filter (connection, csm_manager_bus_filter, manager, NULL); manager->priv->dbus_disconnected = FALSE; manager->priv->bus_proxy = dbus_g_proxy_new_for_name (manager->priv->connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); dbus_g_proxy_add_signal (manager->priv->bus_proxy, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal (manager->priv->bus_proxy, "NameOwnerChanged", G_CALLBACK (bus_name_owner_changed), manager, NULL); dbus_g_connection_register_g_object (manager->priv->connection, CSM_MANAGER_DBUS_PATH, G_OBJECT (manager)); return TRUE; } static void csm_manager_set_failsafe (CsmManager *manager, gboolean enabled) { g_return_if_fail (CSM_IS_MANAGER (manager)); manager->priv->failsafe = enabled; } gboolean csm_manager_get_failsafe (CsmManager *manager) { g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); return manager->priv->failsafe; } static void on_client_disconnected (CsmClient *client, CsmManager *manager) { g_debug ("CsmManager: disconnect client"); _disconnect_client (manager, client); csm_store_remove (manager->priv->clients, csm_client_peek_id (client)); if (manager->priv->phase >= CSM_MANAGER_PHASE_QUERY_END_SESSION && csm_store_size (manager->priv->clients) == 0) { g_debug ("CsmManager: last client disconnected - exiting"); end_phase (manager); } } static gboolean on_xsmp_client_register_request (CsmXSMPClient *client, char **id, CsmManager *manager) { gboolean handled; char *new_id; CsmApp *app; handled = TRUE; new_id = NULL; if (manager->priv->phase >= CSM_MANAGER_PHASE_QUERY_END_SESSION) { goto out; } if (IS_STRING_EMPTY (*id)) { new_id = csm_util_generate_startup_id (); } else { CsmClient *client; client = (CsmClient *)csm_store_find (manager->priv->clients, (CsmStoreFunc)_client_has_startup_id, *id); /* We can't have two clients with the same id. */ if (client != NULL) { goto out; } new_id = g_strdup (*id); } g_debug ("CsmManager: Adding new client %s to session", new_id); g_signal_connect (client, "disconnected", G_CALLBACK (on_client_disconnected), manager); /* If it's a brand new client id, we just accept the client*/ if (IS_STRING_EMPTY (*id)) { goto out; } app = find_app_for_startup_id (manager, new_id); if (app != NULL) { csm_client_set_app_id (CSM_CLIENT (client), csm_app_peek_app_id (app)); csm_app_registered (app); goto out; } /* app not found */ g_free (new_id); new_id = NULL; out: g_free (*id); *id = new_id; return handled; } static void _finished_playing_logout_sound (ca_context *c, uint32_t id, int error, void *userdata) { g_warning ("Finished playing logout sound"); CsmManager *manager = (CsmManager *) userdata; manager->priv->logout_sound_is_playing = FALSE; g_warning ("Resuming logout sequence..."); } static void maybe_play_logout_sound (CsmManager *manager) { GSettings *settings = g_settings_new ("org.cinnamon.sounds"); gboolean enabled = g_settings_get_boolean(settings, "logout-enabled"); gchar *sound = g_settings_get_string (settings, "logout-file"); if (enabled) { if (sound) { if (g_file_test (sound, G_FILE_TEST_EXISTS)) { g_warning ("Playing logout sound '%s'", sound); manager->priv->logout_sound_is_playing = TRUE; ca_context_create (&manager->priv->ca); ca_context_set_driver (manager->priv->ca, "pulse"); ca_context_change_props (manager->priv->ca, 0, CA_PROP_APPLICATION_ID, "org.gnome.VolumeControl", NULL); ca_proplist *proplist = NULL; ca_proplist_create(&proplist); ca_proplist_sets(proplist, CA_PROP_MEDIA_FILENAME, sound); int result = ca_context_play_full(manager->priv->ca, 0, proplist, _finished_playing_logout_sound, manager); if (result != CA_SUCCESS) { g_warning ("Logout sound failed to play, skipping."); manager->priv->logout_sound_is_playing = FALSE; } } } } g_free(sound); g_object_unref (settings); while (manager->priv->logout_sound_is_playing) { sleep(1); } } static void maybe_save_session (CsmManager *manager) { GError *error; if (csm_system_is_login_session (manager->priv->system)) return; /* We only allow session saving when session is running or when * logging out */ if (manager->priv->phase != CSM_MANAGER_PHASE_RUNNING && manager->priv->phase != CSM_MANAGER_PHASE_END_SESSION) { return; } if (!csm_manager_get_autosave_enabled (manager)) { csm_session_save_clear (); return; } error = NULL; csm_session_save (manager->priv->clients, &error); if (error) { g_warning ("Error saving session: %s", error->message); g_error_free (error); } } static void _handle_client_end_session_response (CsmManager *manager, CsmClient *client, gboolean is_ok, gboolean do_last, gboolean cancel, const char *reason) { /* just ignore if received outside of shutdown */ if (manager->priv->phase < CSM_MANAGER_PHASE_QUERY_END_SESSION) { return; } g_debug ("CsmManager: Response from end session request: is-ok=%d do-last=%d cancel=%d reason=%s", is_ok, do_last, cancel, reason ? reason :""); if (cancel) { cancel_end_session (manager); return; } manager->priv->query_clients = g_slist_remove (manager->priv->query_clients, client); if (! is_ok && manager->priv->logout_mode != CSM_MANAGER_LOGOUT_MODE_FORCE) { guint cookie; CsmInhibitor *inhibitor; char *app_id; const char *bus_name; /* FIXME: do we support updating the reason? */ /* Create JIT inhibit */ if (CSM_IS_DBUS_CLIENT (client)) { bus_name = csm_dbus_client_get_bus_name (CSM_DBUS_CLIENT (client)); } else { bus_name = NULL; } app_id = g_strdup (csm_client_peek_app_id (client)); if (IS_STRING_EMPTY (app_id)) { /* XSMP clients don't give us an app id unless we start them */ g_free (app_id); app_id = csm_client_get_app_name (client); } cookie = _generate_unique_cookie (manager); inhibitor = csm_inhibitor_new_for_client (csm_client_peek_id (client), app_id, CSM_INHIBITOR_FLAG_LOGOUT, reason != NULL ? reason : _("Not responding"), bus_name, cookie); g_free (app_id); csm_store_add (manager->priv->inhibitors, csm_inhibitor_peek_id (inhibitor), G_OBJECT (inhibitor)); g_object_unref (inhibitor); } else { csm_store_foreach_remove (manager->priv->inhibitors, (CsmStoreFunc)inhibitor_has_client_id, (gpointer)csm_client_peek_id (client)); } if (manager->priv->phase == CSM_MANAGER_PHASE_QUERY_END_SESSION) { if (manager->priv->query_clients == NULL) { query_end_session_complete (manager); } } else if (manager->priv->phase == CSM_MANAGER_PHASE_END_SESSION) { if (do_last) { /* This only makes sense if we're in part 1 of * CSM_MANAGER_PHASE_END_SESSION. Doing this in part 2 * can only happen because of a buggy client that loops * wanting to be last again and again. The phase * timeout will take care of this issue. */ manager->priv->next_query_clients = g_slist_prepend (manager->priv->next_query_clients, client); } /* we can continue to the next step if all clients have replied * and if there's no inhibitor */ if (manager->priv->query_clients != NULL || csm_manager_is_logout_inhibited (manager)) { return; } if (manager->priv->next_query_clients != NULL) { do_phase_end_session_part_2 (manager); } else { end_phase (manager); } } } static void on_client_end_session_response (CsmClient *client, gboolean is_ok, gboolean do_last, gboolean cancel, const char *reason, CsmManager *manager) { _handle_client_end_session_response (manager, client, is_ok, do_last, cancel, reason); } static void on_xsmp_client_logout_request (CsmXSMPClient *client, gboolean show_dialog, CsmManager *manager) { GError *error; int logout_mode; if (show_dialog) { logout_mode = CSM_MANAGER_LOGOUT_MODE_NORMAL; } else { logout_mode = CSM_MANAGER_LOGOUT_MODE_NO_CONFIRMATION; } error = NULL; csm_manager_logout (manager, logout_mode, &error); if (error != NULL) { g_warning ("Unable to logout: %s", error->message); g_error_free (error); } } static void on_store_client_added (CsmStore *store, const char *id, CsmManager *manager) { CsmClient *client; g_debug ("CsmManager: Client added: %s", id); client = (CsmClient *)csm_store_lookup (store, id); /* a bit hacky */ if (CSM_IS_XSMP_CLIENT (client)) { g_signal_connect (client, "register-request", G_CALLBACK (on_xsmp_client_register_request), manager); g_signal_connect (client, "logout-request", G_CALLBACK (on_xsmp_client_logout_request), manager); } g_signal_connect (client, "end-session-response", G_CALLBACK (on_client_end_session_response), manager); g_signal_connect (client, "disconnected", G_CALLBACK (on_client_disconnected), manager); g_signal_emit (manager, signals [CLIENT_ADDED], 0, id); } static void on_store_client_removed (CsmStore *store, const char *id, CsmManager *manager) { g_debug ("CsmManager: Client removed: %s", id); g_signal_emit (manager, signals [CLIENT_REMOVED], 0, id); } static void csm_manager_set_client_store (CsmManager *manager, CsmStore *store) { g_return_if_fail (CSM_IS_MANAGER (manager)); if (store != NULL) { g_object_ref (store); } if (manager->priv->clients != NULL) { g_signal_handlers_disconnect_by_func (manager->priv->clients, on_store_client_added, manager); g_signal_handlers_disconnect_by_func (manager->priv->clients, on_store_client_removed, manager); g_object_unref (manager->priv->clients); } g_debug ("CsmManager: setting client store %p", store); manager->priv->clients = store; if (manager->priv->clients != NULL) { if (manager->priv->xsmp_server) g_object_unref (manager->priv->xsmp_server); manager->priv->xsmp_server = csm_xsmp_server_new (store); g_signal_connect (manager->priv->clients, "added", G_CALLBACK (on_store_client_added), manager); g_signal_connect (manager->priv->clients, "removed", G_CALLBACK (on_store_client_removed), manager); } } static void csm_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsmManager *self; self = CSM_MANAGER (object); switch (prop_id) { case PROP_FAILSAFE: csm_manager_set_failsafe (self, g_value_get_boolean (value)); break; case PROP_FALLBACK: self->priv->is_fallback_session = g_value_get_boolean (value); break; case PROP_CLIENT_STORE: csm_manager_set_client_store (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsmManager *self; self = CSM_MANAGER (object); switch (prop_id) { case PROP_FAILSAFE: g_value_set_boolean (value, self->priv->failsafe); break; case PROP_SESSION_NAME: g_value_set_string (value, self->priv->session_name); break; case PROP_FALLBACK: g_value_set_boolean (value, self->priv->is_fallback_session); break; case PROP_CLIENT_STORE: g_value_set_object (value, self->priv->clients); break; case PROP_INHIBITED_ACTIONS: g_value_set_uint (value, self->priv->inhibited_actions); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean _find_app_provides (const char *id, CsmApp *app, const char *service) { return csm_app_provides (app, service); } static GObject * csm_manager_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsmManager *manager; manager = CSM_MANAGER (G_OBJECT_CLASS (csm_manager_parent_class)->constructor (type, n_construct_properties, construct_properties)); return G_OBJECT (manager); } static void update_inhibited_actions (CsmManager *manager, CsmInhibitorFlag new_inhibited_actions) { DBusGConnection *gconnection; DBusConnection *connection; DBusMessage *message; DBusMessageIter iter; DBusMessageIter subiter; DBusMessageIter dict_iter; DBusMessageIter v_iter; const char *iface_name = CSM_MANAGER_DBUS_NAME; const char *prop_name = "InhibitedActions"; if (manager->priv->inhibited_actions == new_inhibited_actions) return; manager->priv->inhibited_actions = new_inhibited_actions; g_object_notify (G_OBJECT (manager), "inhibited-actions"); /* Now, the following bits emit the PropertiesChanged signal * that GDBus expects. This code should just die in a port to * GDBus. */ gconnection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL); g_assert (gconnection); connection = dbus_g_connection_get_connection (gconnection); message = dbus_message_new_signal (CSM_MANAGER_DBUS_PATH, "org.freedesktop.DBus.Properties", "PropertiesChanged"); g_assert (message != NULL); dbus_message_iter_init_append (message, &iter); dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &iface_name); /* changed */ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &subiter); dbus_message_iter_open_container (&subiter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_iter); dbus_message_iter_append_basic (&dict_iter, DBUS_TYPE_STRING, &prop_name); dbus_message_iter_open_container (&dict_iter, DBUS_TYPE_VARIANT, "u", &v_iter); dbus_message_iter_append_basic (&v_iter, DBUS_TYPE_UINT32, &new_inhibited_actions); dbus_message_iter_close_container (&dict_iter, &v_iter); dbus_message_iter_close_container (&subiter, &dict_iter); dbus_message_iter_close_container (&iter, &subiter); /* invalidated */ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &subiter); dbus_message_iter_close_container (&iter, &subiter); dbus_connection_send (connection, message, NULL); dbus_message_unref (message); } static void on_store_inhibitor_added (CsmStore *store, const char *id, CsmManager *manager) { CsmInhibitor *i; CsmInhibitorFlag new_inhibited_actions; g_debug ("CsmManager: Inhibitor added: %s", id); i = CSM_INHIBITOR (csm_store_lookup (store, id)); csm_system_add_inhibitor (manager->priv->system, id, csm_inhibitor_peek_flags (i)); new_inhibited_actions = manager->priv->inhibited_actions | csm_inhibitor_peek_flags (i); update_inhibited_actions (manager, new_inhibited_actions); g_signal_emit (manager, signals [INHIBITOR_ADDED], 0, id); update_idle (manager); } static gboolean collect_inhibition_flags (const char *id, GObject *object, gpointer user_data) { CsmInhibitorFlag *new_inhibited_actions = user_data; *new_inhibited_actions |= csm_inhibitor_peek_flags (CSM_INHIBITOR (object)); return FALSE; } static void on_store_inhibitor_removed (CsmStore *store, const char *id, CsmManager *manager) { CsmInhibitorFlag new_inhibited_actions; g_debug ("CsmManager: Inhibitor removed: %s", id); csm_system_remove_inhibitor (manager->priv->system, id); new_inhibited_actions = 0; csm_store_foreach (manager->priv->inhibitors, collect_inhibition_flags, &new_inhibited_actions); update_inhibited_actions (manager, new_inhibited_actions); g_signal_emit (manager, signals [INHIBITOR_REMOVED], 0, id); update_idle (manager); } static void csm_manager_dispose (GObject *object) { CsmManager *manager = CSM_MANAGER (object); g_debug ("CsmManager: disposing manager"); g_clear_object (&manager->priv->xsmp_server); if (manager->priv->clients != NULL) { g_signal_handlers_disconnect_by_func (manager->priv->clients, on_store_client_added, manager); g_signal_handlers_disconnect_by_func (manager->priv->clients, on_store_client_removed, manager); g_object_unref (manager->priv->clients); manager->priv->clients = NULL; } if (manager->priv->apps != NULL) { g_object_unref (manager->priv->apps); manager->priv->apps = NULL; } g_slist_free (manager->priv->required_apps); manager->priv->required_apps = NULL; if (manager->priv->inhibitors != NULL) { g_signal_handlers_disconnect_by_func (manager->priv->inhibitors, on_store_inhibitor_added, manager); g_signal_handlers_disconnect_by_func (manager->priv->inhibitors, on_store_inhibitor_removed, manager); g_object_unref (manager->priv->inhibitors); manager->priv->inhibitors = NULL; } if (manager->priv->presence != NULL) { g_object_unref (manager->priv->presence); manager->priv->presence = NULL; } if (manager->priv->settings) { g_object_unref (manager->priv->settings); manager->priv->settings = NULL; } if (manager->priv->session_settings) { g_object_unref (manager->priv->session_settings); manager->priv->session_settings = NULL; } if (manager->priv->power_settings) { g_object_unref (manager->priv->power_settings); manager->priv->power_settings = NULL; } if (manager->priv->lockdown_settings) { g_object_unref (manager->priv->lockdown_settings); manager->priv->lockdown_settings = NULL; } if (manager->priv->system != NULL) { g_object_unref (manager->priv->system); manager->priv->system = NULL; } G_OBJECT_CLASS (csm_manager_parent_class)->dispose (object); } static void csm_manager_class_init (CsmManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = csm_manager_get_property; object_class->set_property = csm_manager_set_property; object_class->constructor = csm_manager_constructor; object_class->finalize = csm_manager_finalize; object_class->dispose = csm_manager_dispose; signals [PHASE_CHANGED] = g_signal_new ("phase-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmManagerClass, phase_changed), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); signals [SESSION_RUNNING] = g_signal_new ("session-running", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmManagerClass, session_running), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals [SESSION_OVER] = g_signal_new ("session-over", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmManagerClass, session_over), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals [CLIENT_ADDED] = g_signal_new ("client-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmManagerClass, client_added), NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, DBUS_TYPE_G_OBJECT_PATH); signals [CLIENT_REMOVED] = g_signal_new ("client-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmManagerClass, client_removed), NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, DBUS_TYPE_G_OBJECT_PATH); signals [INHIBITOR_ADDED] = g_signal_new ("inhibitor-added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmManagerClass, inhibitor_added), NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, DBUS_TYPE_G_OBJECT_PATH); signals [INHIBITOR_REMOVED] = g_signal_new ("inhibitor-removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmManagerClass, inhibitor_removed), NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, DBUS_TYPE_G_OBJECT_PATH); g_object_class_install_property (object_class, PROP_FAILSAFE, g_param_spec_boolean ("failsafe", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); /** * CsmManager::inhibited-actions * * A bitmask of flags to indicate which actions are inhibited. See the Inhibit() * function's description for a list of possible values. */ g_object_class_install_property (object_class, PROP_INHIBITED_ACTIONS, g_param_spec_uint ("inhibited-actions", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READABLE)); /** * CsmManager::session-name * * Then name of the currently active session, typically "gnome" or "gnome-fallback". * This may be the name of the configured default session, or the name of a fallback * session in case we fell back. */ g_object_class_install_property (object_class, PROP_SESSION_NAME, g_param_spec_string ("session-name", NULL, NULL, NULL, G_PARAM_READABLE)); /** * CsmManager::fallback * * If %TRUE, the current session is running in the "fallback" mode; * this is distinct from whether or not it was configured as default. */ g_object_class_install_property (object_class, PROP_FALLBACK, g_param_spec_boolean ("fallback", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_CLIENT_STORE, g_param_spec_object ("client-store", NULL, NULL, CSM_TYPE_STORE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (CsmManagerPrivate)); dbus_g_object_type_install_info (CSM_TYPE_MANAGER, &dbus_glib_csm_manager_object_info); dbus_g_error_domain_register (CSM_MANAGER_ERROR, NULL, CSM_MANAGER_TYPE_ERROR); } static void on_presence_status_changed (CsmPresence *presence, guint status, CsmManager *manager) { CsmSystem *system; system = csm_get_system (); csm_system_set_session_idle (system, (status == CSM_PRESENCE_STATUS_IDLE)); g_object_unref (system); } static gboolean idle_timeout_get_mapping (GValue *value, GVariant *variant, gpointer user_data) { guint32 idle_timeout; idle_timeout = g_variant_get_uint32 (variant); g_value_set_uint (value, idle_timeout * 1000); return TRUE; } static void csm_manager_init (CsmManager *manager) { manager->priv = CSM_MANAGER_GET_PRIVATE (manager); manager->priv->settings = g_settings_new (CSM_MANAGER_SCHEMA); manager->priv->session_settings = g_settings_new (SESSION_SCHEMA); manager->priv->power_settings = g_settings_new (POWER_SETTINGS_SCHEMA); manager->priv->lockdown_settings = g_settings_new (LOCKDOWN_SCHEMA); manager->priv->inhibitors = csm_store_new (); g_signal_connect (manager->priv->inhibitors, "added", G_CALLBACK (on_store_inhibitor_added), manager); g_signal_connect (manager->priv->inhibitors, "removed", G_CALLBACK (on_store_inhibitor_removed), manager); manager->priv->apps = csm_store_new (); manager->priv->presence = csm_presence_new (); g_signal_connect (manager->priv->presence, "status-changed", G_CALLBACK (on_presence_status_changed), manager); g_settings_bind_with_mapping (manager->priv->session_settings, KEY_IDLE_DELAY, manager->priv->presence, "idle-timeout", G_SETTINGS_BIND_GET, idle_timeout_get_mapping, NULL, NULL, NULL); manager->priv->system = csm_get_system (); } static void csm_manager_finalize (GObject *object) { CsmManager *manager; g_return_if_fail (object != NULL); g_return_if_fail (CSM_IS_MANAGER (object)); manager = CSM_MANAGER (object); g_return_if_fail (manager->priv != NULL); G_OBJECT_CLASS (csm_manager_parent_class)->finalize (object); } CsmManager * csm_manager_get (void) { return manager_object; } CsmManager * csm_manager_new (CsmStore *client_store, gboolean failsafe) { if (manager_object != NULL) { g_object_ref (manager_object); } else { gboolean res; manager_object = g_object_new (CSM_TYPE_MANAGER, "client-store", client_store, "failsafe", failsafe, NULL); g_object_add_weak_pointer (manager_object, (gpointer *) &manager_object); res = register_manager (manager_object); if (! res) { g_object_unref (manager_object); return NULL; } } return CSM_MANAGER (manager_object); } gboolean csm_manager_setenv (CsmManager *manager, const char *variable, const char *value, GError **error) { g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); if (manager->priv->phase > CSM_MANAGER_PHASE_INITIALIZATION) { g_set_error (error, CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_NOT_IN_INITIALIZATION, "Setenv interface is only available during the Initialization phase"); return FALSE; } csm_util_setenv (variable, value); return TRUE; } gboolean csm_manager_initialization_error (CsmManager *manager, const char *message, gboolean fatal, GError **error) { g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); if (manager->priv->phase > CSM_MANAGER_PHASE_INITIALIZATION) { g_set_error (error, CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_NOT_IN_INITIALIZATION, "InitializationError interface is only available during the Initialization phase"); return FALSE; } csm_util_init_error (fatal, "%s", message); return TRUE; } static gboolean csm_manager_is_switch_user_inhibited (CsmManager *manager) { CsmInhibitor *inhibitor; if (manager->priv->inhibitors == NULL) { return FALSE; } inhibitor = (CsmInhibitor *)csm_store_find (manager->priv->inhibitors, (CsmStoreFunc)inhibitor_has_flag, GUINT_TO_POINTER (CSM_INHIBITOR_FLAG_SWITCH_USER)); if (inhibitor == NULL) { return FALSE; } return TRUE; } static gboolean csm_manager_is_suspend_inhibited (CsmManager *manager) { CsmInhibitor *inhibitor; if (manager->priv->inhibitors == NULL) { return FALSE; } inhibitor = (CsmInhibitor *)csm_store_find (manager->priv->inhibitors, (CsmStoreFunc)inhibitor_has_flag, GUINT_TO_POINTER (CSM_INHIBITOR_FLAG_SUSPEND)); if (inhibitor == NULL) { return FALSE; } return TRUE; } static void request_reboot (CsmManager *manager) { g_debug ("CsmManager: requesting reboot"); /* FIXME: We need to support a more structured shutdown here, * but that's blocking on an improved ConsoleKit api. * * See https://bugzilla.gnome.org/show_bug.cgi?id=585614 */ manager->priv->logout_type = CSM_MANAGER_LOGOUT_REBOOT_INTERACT; end_phase (manager); } static void request_shutdown (CsmManager *manager) { g_debug ("CsmManager: requesting shutdown"); /* See the comment in request_reboot() for some more details about * what work needs to be done here. */ manager->priv->logout_type = CSM_MANAGER_LOGOUT_SHUTDOWN_INTERACT; end_phase (manager); } static void request_suspend (CsmManager *manager) { g_debug ("CsmManager: requesting suspend"); if (! csm_manager_is_suspend_inhibited (manager)) { manager_attempt_suspend (manager); return; } if (manager->priv->inhibit_dialog != NULL) { g_debug ("CsmManager: inhibit dialog already up"); gtk_window_present (GTK_WINDOW (manager->priv->inhibit_dialog)); return; } manager->priv->inhibit_dialog = csm_inhibit_dialog_new (manager->priv->inhibitors, manager->priv->clients, CSM_LOGOUT_ACTION_SLEEP); g_signal_connect (manager->priv->inhibit_dialog, "response", G_CALLBACK (inhibit_dialog_response), manager); gtk_widget_show (manager->priv->inhibit_dialog); } static void request_hibernate (CsmManager *manager) { g_debug ("CsmManager: requesting hibernate"); /* hibernate uses suspend inhibit */ if (! csm_manager_is_suspend_inhibited (manager)) { manager_attempt_hibernate (manager); return; } if (manager->priv->inhibit_dialog != NULL) { g_debug ("CsmManager: inhibit dialog already up"); gtk_window_present (GTK_WINDOW (manager->priv->inhibit_dialog)); return; } manager->priv->inhibit_dialog = csm_inhibit_dialog_new (manager->priv->inhibitors, manager->priv->clients, CSM_LOGOUT_ACTION_HIBERNATE); g_signal_connect (manager->priv->inhibit_dialog, "response", G_CALLBACK (inhibit_dialog_response), manager); gtk_widget_show (manager->priv->inhibit_dialog); } static void request_logout (CsmManager *manager, CsmManagerLogoutMode mode) { g_debug ("CsmManager: requesting logout"); manager->priv->logout_mode = mode; manager->priv->logout_type = CSM_MANAGER_LOGOUT_LOGOUT; end_phase (manager); } static void request_switch_user (GdkDisplay *display, CsmManager *manager) { g_debug ("CsmManager: requesting user switch"); /* See comment in manager_switch_user() to understand why we do this in * both functions. */ if (_switch_user_is_locked_down (manager)) { g_warning ("Unable to switch user: User switching has been locked down"); return; } if (! csm_manager_is_switch_user_inhibited (manager)) { manager_switch_user (display, manager); return; } if (manager->priv->inhibit_dialog != NULL) { g_debug ("CsmManager: inhibit dialog already up"); gtk_window_present (GTK_WINDOW (manager->priv->inhibit_dialog)); return; } manager->priv->inhibit_dialog = csm_inhibit_dialog_new (manager->priv->inhibitors, manager->priv->clients, CSM_LOGOUT_ACTION_SWITCH_USER); g_signal_connect (manager->priv->inhibit_dialog, "response", G_CALLBACK (inhibit_dialog_response), manager); gtk_widget_show (manager->priv->inhibit_dialog); } static void logout_dialog_response (CsmLogoutDialog *logout_dialog, guint response_id, CsmManager *manager) { GdkDisplay *display; /* We should only be here if mode has already have been set from * show_fallback_shutdown/logout_dialog */ g_assert (manager->priv->logout_mode == CSM_MANAGER_LOGOUT_MODE_NORMAL); g_debug ("CsmManager: Logout dialog response: %d", response_id); display = gtk_widget_get_display (GTK_WIDGET (logout_dialog)); gtk_widget_destroy (GTK_WIDGET (logout_dialog)); /* In case of dialog cancel, switch user, hibernate and * suspend, we just perform the respective action and return, * without shutting down the session. */ switch (response_id) { case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_NONE: case GTK_RESPONSE_DELETE_EVENT: break; case CSM_LOGOUT_RESPONSE_SWITCH_USER: request_switch_user (display, manager); break; case CSM_LOGOUT_RESPONSE_HIBERNATE: request_hibernate (manager); break; case CSM_LOGOUT_RESPONSE_SLEEP: request_suspend (manager); break; case CSM_LOGOUT_RESPONSE_SHUTDOWN: request_shutdown (manager); break; case CSM_LOGOUT_RESPONSE_REBOOT: request_reboot (manager); break; case CSM_LOGOUT_RESPONSE_LOGOUT: /* We've already gotten confirmation from the user so * initiate the logout in NO_CONFIRMATION mode. */ request_logout (manager, CSM_MANAGER_LOGOUT_MODE_NO_CONFIRMATION); break; default: g_assert_not_reached (); break; } } static void show_fallback_shutdown_dialog (CsmManager *manager, gboolean is_reboot) { GtkWidget *dialog; if (manager->priv->phase >= CSM_MANAGER_PHASE_QUERY_END_SESSION) { /* Already shutting down, nothing more to do */ return; } manager->priv->logout_mode = CSM_MANAGER_LOGOUT_MODE_NORMAL; dialog = csm_get_shutdown_dialog (gdk_screen_get_default (), gtk_get_current_event_time (), is_reboot ? CSM_DIALOG_LOGOUT_TYPE_REBOOT : CSM_DIALOG_LOGOUT_TYPE_SHUTDOWN); g_signal_connect (dialog, "response", G_CALLBACK (logout_dialog_response), manager); gtk_window_present (GTK_WINDOW (dialog)); } static void show_fallback_logout_dialog (CsmManager *manager) { GtkWidget *dialog; if (manager->priv->phase >= CSM_MANAGER_PHASE_QUERY_END_SESSION) { /* Already shutting down, nothing more to do */ return; } manager->priv->logout_mode = CSM_MANAGER_LOGOUT_MODE_NORMAL; dialog = csm_get_logout_dialog (gdk_screen_get_default (), gtk_get_current_event_time ()); g_signal_connect (dialog, "response", G_CALLBACK (logout_dialog_response), manager); gtk_window_present (GTK_WINDOW (dialog)); } static void user_logout (CsmManager *manager, CsmManagerLogoutMode mode) { gboolean logout_prompt; if (manager->priv->phase >= CSM_MANAGER_PHASE_QUERY_END_SESSION) { /* Already shutting down, nothing more to do */ return; } logout_prompt = g_settings_get_boolean (manager->priv->settings, KEY_LOGOUT_PROMPT); /* If the shell isn't running, and this isn't a non-interative logout request, * and the user has their settings configured to show a confirmation dialog for * logout, then go ahead and show the fallback confirmation dialog now. * * If the shell is running, then the confirmation dialog and inhibitor dialog are * combined, so we'll show it at a later stage in the logout process. */ if (mode == CSM_MANAGER_LOGOUT_MODE_NORMAL && logout_prompt) { show_fallback_logout_dialog (manager); } else { request_logout (manager, mode); } } /* dbus-send --session --type=method_call --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager org.freedesktop.DBus.Introspectable.Introspect */ gboolean csm_manager_set_phase (CsmManager *manager, CsmManagerPhase phase) { g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); manager->priv->phase = phase; return (TRUE); } static gboolean _log_out_is_locked_down (CsmManager *manager) { return g_settings_get_boolean (manager->priv->lockdown_settings, KEY_DISABLE_LOG_OUT); } static gboolean _switch_user_is_locked_down (CsmManager *manager) { return g_settings_get_boolean (manager->priv->lockdown_settings, KEY_DISABLE_USER_SWITCHING); } gboolean csm_manager_request_shutdown (CsmManager *manager, GError **error) { g_debug ("CsmManager: RequestShutdown called"); g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); if (manager->priv->phase != CSM_MANAGER_PHASE_RUNNING) { g_set_error (error, CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_NOT_IN_RUNNING, "RequestShutdown interface is only available during the Running phase"); return FALSE; } request_shutdown (manager); return TRUE; } gboolean csm_manager_request_reboot (CsmManager *manager, GError **error) { g_debug ("CsmManager: RequestReboot called"); g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); if (manager->priv->phase != CSM_MANAGER_PHASE_RUNNING) { g_set_error (error, CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_NOT_IN_RUNNING, "RequestReboot interface is only available during the Running phase"); return FALSE; } request_reboot (manager); return TRUE; } gboolean csm_manager_shutdown (CsmManager *manager, GError **error) { g_debug ("CsmManager: Shutdown called"); g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); if (manager->priv->phase != CSM_MANAGER_PHASE_RUNNING) { g_set_error (error, CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_NOT_IN_RUNNING, "Shutdown interface is only available during the Running phase"); return FALSE; } if (_log_out_is_locked_down (manager)) { g_set_error (error, CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_LOCKED_DOWN, "Logout has been locked down"); return FALSE; } show_fallback_shutdown_dialog (manager, FALSE); return TRUE; } gboolean csm_manager_reboot (CsmManager *manager, GError **error) { g_debug ("CsmManager: Reboot called"); g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); if (manager->priv->phase != CSM_MANAGER_PHASE_RUNNING) { g_set_error (error, CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_NOT_IN_RUNNING, "Reboot interface is only available during the Running phase"); return FALSE; } if (_log_out_is_locked_down (manager)) { g_set_error (error, CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_LOCKED_DOWN, "Logout has been locked down"); return FALSE; } show_fallback_shutdown_dialog (manager, TRUE); return TRUE; } gboolean csm_manager_can_shutdown (CsmManager *manager, gboolean *shutdown_available, GError **error) { g_debug ("CsmManager: CanShutdown called"); g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); *shutdown_available = !_log_out_is_locked_down (manager) && (csm_system_can_stop (manager->priv->system) || csm_system_can_restart (manager->priv->system) || csm_system_can_suspend (manager->priv->system) || csm_system_can_hibernate (manager->priv->system)); return TRUE; } gboolean csm_manager_logout (CsmManager *manager, guint logout_mode, GError **error) { g_debug ("CsmManager: Logout called"); g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); if (manager->priv->phase != CSM_MANAGER_PHASE_RUNNING) { g_set_error (error, CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_NOT_IN_RUNNING, "Logout interface is only available during the Running phase"); return FALSE; } if (_log_out_is_locked_down (manager)) { g_set_error (error, CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_LOCKED_DOWN, "Logout has been locked down"); return FALSE; } switch (logout_mode) { case CSM_MANAGER_LOGOUT_MODE_NORMAL: case CSM_MANAGER_LOGOUT_MODE_NO_CONFIRMATION: case CSM_MANAGER_LOGOUT_MODE_FORCE: user_logout (manager, logout_mode); break; default: g_debug ("Unknown logout mode option"); g_set_error (error, CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_INVALID_OPTION, "Unknown logout mode flag"); return FALSE; } return TRUE; } gboolean csm_manager_register_client (CsmManager *manager, const char *app_id, const char *startup_id, DBusGMethodInvocation *context) { char *new_startup_id; char *sender; CsmClient *client; CsmApp *app; g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); app = NULL; client = NULL; g_debug ("CsmManager: RegisterClient %s", startup_id); if (manager->priv->phase >= CSM_MANAGER_PHASE_QUERY_END_SESSION) { GError *new_error; g_debug ("Unable to register client: shutting down"); new_error = g_error_new (CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_NOT_IN_RUNNING, "Unable to register client"); dbus_g_method_return_error (context, new_error); g_error_free (new_error); return FALSE; } if (IS_STRING_EMPTY (startup_id)) { new_startup_id = csm_util_generate_startup_id (); } else { client = (CsmClient *)csm_store_find (manager->priv->clients, (CsmStoreFunc)_client_has_startup_id, (char *)startup_id); /* We can't have two clients with the same startup id. */ if (client != NULL) { GError *new_error; g_debug ("Unable to register client: already registered"); new_error = g_error_new (CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_ALREADY_REGISTERED, "Unable to register client"); dbus_g_method_return_error (context, new_error); g_error_free (new_error); return FALSE; } new_startup_id = g_strdup (startup_id); } g_debug ("CsmManager: Adding new client %s to session", new_startup_id); if (app == NULL && !IS_STRING_EMPTY (startup_id)) { app = find_app_for_startup_id (manager, startup_id); } if (app == NULL && !IS_STRING_EMPTY (app_id)) { /* try to associate this app id with a known app */ app = find_app_for_app_id (manager, app_id); } sender = dbus_g_method_get_sender (context); client = csm_dbus_client_new (new_startup_id, sender); g_free (sender); if (client == NULL) { GError *new_error; g_debug ("Unable to create client"); new_error = g_error_new (CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_GENERAL, "Unable to register client"); dbus_g_method_return_error (context, new_error); g_error_free (new_error); return FALSE; } csm_store_add (manager->priv->clients, csm_client_peek_id (client), G_OBJECT (client)); /* the store will own the ref */ g_object_unref (client); if (app != NULL) { csm_client_set_app_id (client, csm_app_peek_app_id (app)); csm_app_registered (app); } else { /* if an app id is specified store it in the client so we can save it later */ csm_client_set_app_id (client, app_id); } csm_client_set_status (client, CSM_CLIENT_REGISTERED); g_assert (new_startup_id != NULL); g_free (new_startup_id); dbus_g_method_return (context, csm_client_peek_id (client)); return TRUE; } gboolean csm_manager_unregister_client (CsmManager *manager, const char *client_id, DBusGMethodInvocation *context) { CsmClient *client; g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); g_debug ("CsmManager: UnregisterClient %s", client_id); client = (CsmClient *)csm_store_lookup (manager->priv->clients, client_id); if (client == NULL) { GError *new_error; g_debug ("Unable to unregister client: not registered"); new_error = g_error_new (CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_NOT_REGISTERED, "Unable to unregister client"); dbus_g_method_return_error (context, new_error); g_error_free (new_error); return FALSE; } /* don't disconnect client here, only change the status. Wait until it leaves the bus before disconnecting it */ csm_client_set_status (client, CSM_CLIENT_UNREGISTERED); dbus_g_method_return (context); return TRUE; } gboolean csm_manager_inhibit (CsmManager *manager, const char *app_id, guint toplevel_xid, const char *reason, guint flags, DBusGMethodInvocation *context) { CsmInhibitor *inhibitor; guint cookie; g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); g_debug ("CsmManager: Inhibit xid=%u app_id=%s reason=%s flags=%u", toplevel_xid, app_id, reason, flags); if (manager->priv->logout_mode == CSM_MANAGER_LOGOUT_MODE_FORCE) { GError *new_error; new_error = g_error_new (CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_GENERAL, "Forced logout cannot be inhibited"); g_debug ("CsmManager: Unable to inhibit: %s", new_error->message); dbus_g_method_return_error (context, new_error); g_error_free (new_error); return FALSE; } if (IS_STRING_EMPTY (app_id)) { GError *new_error; new_error = g_error_new (CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_GENERAL, "Application ID not specified"); g_debug ("CsmManager: Unable to inhibit: %s", new_error->message); dbus_g_method_return_error (context, new_error); g_error_free (new_error); return FALSE; } if (IS_STRING_EMPTY (reason)) { GError *new_error; new_error = g_error_new (CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_GENERAL, "Reason not specified"); g_debug ("CsmManager: Unable to inhibit: %s", new_error->message); dbus_g_method_return_error (context, new_error); g_error_free (new_error); return FALSE; } if (flags == 0) { GError *new_error; new_error = g_error_new (CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_GENERAL, "Invalid inhibit flags"); g_debug ("CsmManager: Unable to inhibit: %s", new_error->message); dbus_g_method_return_error (context, new_error); g_error_free (new_error); return FALSE; } cookie = _generate_unique_cookie (manager); inhibitor = csm_inhibitor_new (app_id, toplevel_xid, flags, reason, dbus_g_method_get_sender (context), cookie); csm_store_add (manager->priv->inhibitors, csm_inhibitor_peek_id (inhibitor), G_OBJECT (inhibitor)); g_object_unref (inhibitor); dbus_g_method_return (context, cookie); return TRUE; } gboolean csm_manager_uninhibit (CsmManager *manager, guint cookie, DBusGMethodInvocation *context) { CsmInhibitor *inhibitor; g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); g_debug ("CsmManager: Uninhibit %u", cookie); inhibitor = (CsmInhibitor *)csm_store_find (manager->priv->inhibitors, (CsmStoreFunc)_find_by_cookie, &cookie); if (inhibitor == NULL) { GError *new_error; new_error = g_error_new (CSM_MANAGER_ERROR, CSM_MANAGER_ERROR_GENERAL, "Unable to uninhibit: Invalid cookie"); dbus_g_method_return_error (context, new_error); g_debug ("Unable to uninhibit: %s", new_error->message); g_error_free (new_error); return FALSE; } g_debug ("CsmManager: removing inhibitor %s %u reason '%s' %u connection %s", csm_inhibitor_peek_app_id (inhibitor), csm_inhibitor_peek_toplevel_xid (inhibitor), csm_inhibitor_peek_reason (inhibitor), csm_inhibitor_peek_flags (inhibitor), csm_inhibitor_peek_bus_name (inhibitor)); csm_store_remove (manager->priv->inhibitors, csm_inhibitor_peek_id (inhibitor)); dbus_g_method_return (context); return TRUE; } gboolean csm_manager_is_inhibited (CsmManager *manager, guint flags, gboolean *is_inhibited, GError *error) { CsmInhibitor *inhibitor; g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); if (manager->priv->inhibitors == NULL || csm_store_size (manager->priv->inhibitors) == 0) { *is_inhibited = FALSE; return TRUE; } inhibitor = (CsmInhibitor *) csm_store_find (manager->priv->inhibitors, (CsmStoreFunc)inhibitor_has_flag, GUINT_TO_POINTER (flags)); if (inhibitor == NULL) { *is_inhibited = FALSE; } else { *is_inhibited = TRUE; } return TRUE; } static gboolean listify_store_ids (char *id, GObject *object, GPtrArray **array) { g_ptr_array_add (*array, g_strdup (id)); return FALSE; } gboolean csm_manager_get_clients (CsmManager *manager, GPtrArray **clients, GError **error) { g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); if (clients == NULL) { return FALSE; } *clients = g_ptr_array_new (); csm_store_foreach (manager->priv->clients, (CsmStoreFunc)listify_store_ids, clients); return TRUE; } gboolean csm_manager_get_inhibitors (CsmManager *manager, GPtrArray **inhibitors, GError **error) { g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); if (inhibitors == NULL) { return FALSE; } *inhibitors = g_ptr_array_new (); csm_store_foreach (manager->priv->inhibitors, (CsmStoreFunc) listify_store_ids, inhibitors); return TRUE; } static gboolean _app_has_autostart_condition (const char *id, CsmApp *app, const char *condition) { gboolean has; gboolean disabled; has = csm_app_has_autostart_condition (app, condition); disabled = csm_app_peek_is_disabled (app); return has && !disabled; } gboolean csm_manager_is_autostart_condition_handled (CsmManager *manager, const char *condition, gboolean *handled, GError **error) { CsmApp *app; g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); app = (CsmApp *) csm_store_find (manager->priv->apps,( CsmStoreFunc) _app_has_autostart_condition, (char *)condition); if (app != NULL) { *handled = TRUE; } else { *handled = FALSE; } return TRUE; } static void append_app (CsmManager *manager, CsmApp *app, const char *provides, gboolean is_required) { const char *id; const char *app_id; CsmApp *dup; id = csm_app_peek_id (app); if (IS_STRING_EMPTY (id)) { g_debug ("CsmManager: not adding app: no id"); return; } dup = (CsmApp *)csm_store_lookup (manager->priv->apps, id); if (dup != NULL) { g_debug ("CsmManager: not adding app: already added"); return; } app_id = csm_app_peek_app_id (app); if (IS_STRING_EMPTY (app_id)) { g_debug ("CsmManager: not adding app: no app-id"); return; } dup = find_app_for_app_id (manager, app_id); if (dup != NULL) { g_debug ("CsmManager: not adding app: app-id '%s' already exists", app_id); if (provides && CSM_IS_AUTOSTART_APP (dup)) csm_autostart_app_add_provides (CSM_AUTOSTART_APP (dup), provides); if (is_required && !g_slist_find (manager->priv->required_apps, dup)) { g_debug ("CsmManager: making app '%s' required", csm_app_peek_app_id (dup)); manager->priv->required_apps = g_slist_prepend (manager->priv->required_apps, dup); } return; } csm_store_add (manager->priv->apps, id, G_OBJECT (app)); if (is_required) { g_debug ("CsmManager: adding required app %s", csm_app_peek_app_id (app)); manager->priv->required_apps = g_slist_prepend (manager->priv->required_apps, app); } } static gboolean add_autostart_app_internal (CsmManager *manager, const char *path, const char *provides, gboolean is_required) { CsmApp *app; char **internal_provides; g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); g_return_val_if_fail (path != NULL, FALSE); /* Note: if we cannot add the app because its service is already * provided, because its app-id is taken, or because of any other * reason meaning there is already an app playing its role, then we * should make sure that relevant properties (like * provides/is_required) are set in the pre-existing app if needed. */ /* first check to see if service is already provided */ if (provides != NULL) { CsmApp *dup; dup = (CsmApp *)csm_store_find (manager->priv->apps, (CsmStoreFunc)_find_app_provides, (char *)provides); if (dup != NULL) { g_debug ("CsmManager: service '%s' is already provided", provides); if (is_required && !g_slist_find (manager->priv->required_apps, dup)) { g_debug ("CsmManager: making app '%s' required", csm_app_peek_app_id (dup)); manager->priv->required_apps = g_slist_prepend (manager->priv->required_apps, dup); } return FALSE; } } app = csm_autostart_app_new (path); if (app == NULL) { g_warning ("could not read %s", path); return FALSE; } internal_provides = csm_app_get_provides (app); if (internal_provides) { int i; gboolean provided = FALSE; for (i = 0; internal_provides[i] != NULL; i++) { CsmApp *dup; dup = (CsmApp *)csm_store_find (manager->priv->apps, (CsmStoreFunc)_find_app_provides, (char *)internal_provides[i]); if (dup != NULL) { g_debug ("CsmManager: service '%s' is already provided", internal_provides[i]); if (is_required && !g_slist_find (manager->priv->required_apps, dup)) { g_debug ("CsmManager: making app '%s' required", csm_app_peek_app_id (dup)); manager->priv->required_apps = g_slist_prepend (manager->priv->required_apps, dup); } provided = TRUE; break; } } g_strfreev (internal_provides); if (provided) { g_object_unref (app); return FALSE; } } if (provides) csm_autostart_app_add_provides (CSM_AUTOSTART_APP (app), provides); g_debug ("CsmManager: read %s", path); append_app (manager, app, provides, is_required); g_object_unref (app); return TRUE; } gboolean csm_manager_add_autostart_app (CsmManager *manager, const char *path, const char *provides) { return add_autostart_app_internal (manager, path, provides, FALSE); } /** * csm_manager_add_required_app: * @manager: a #CsmManager * @path: Path to desktop file * @provides: What the component provides, as a space separated list * * Similar to csm_manager_add_autostart_app(), except marks the * component as being required; we then try harder to ensure * it's running and inform the user if we can't. * */ gboolean csm_manager_add_required_app (CsmManager *manager, const char *path, const char *provides) { return add_autostart_app_internal (manager, path, provides, TRUE); } gboolean csm_manager_add_autostart_apps_from_dir (CsmManager *manager, const char *path) { GDir *dir; const char *name; g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); g_return_val_if_fail (path != NULL, FALSE); g_debug ("CsmManager: *** Adding autostart apps for %s", path); dir = g_dir_open (path, 0, NULL); if (dir == NULL) { return FALSE; } while ((name = g_dir_read_name (dir))) { char *desktop_file; if (!g_str_has_suffix (name, ".desktop") || csm_manager_get_app_is_blacklisted (manager, name)) { continue; } desktop_file = g_build_filename (path, name, NULL); csm_manager_add_autostart_app (manager, desktop_file, NULL); g_free (desktop_file); } g_dir_close (dir); return TRUE; } gboolean csm_manager_is_session_running (CsmManager *manager, gboolean *running, GError **error) { g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); *running = (manager->priv->phase == CSM_MANAGER_PHASE_RUNNING); return TRUE; } gboolean csm_manager_get_app_is_blacklisted (CsmManager *manager, const char *name) { g_return_val_if_fail (CSM_IS_MANAGER (manager), FALSE); gchar **gs_blacklist = g_settings_get_strv(manager->priv->settings, KEY_BLACKLIST); GList *list = NULL; gboolean ret = FALSE; int i; for (i = 0; i < g_strv_length (gs_blacklist); i++) list = g_list_append (list, g_strdup (gs_blacklist[i])); GList *l; for (l = list; l != NULL; l = l->next) { gchar *ptr = g_strstr_len (name, -1, l->data); if (ptr != NULL) { ret = TRUE; break; } } g_list_free_full (list, g_free); g_strfreev (gs_blacklist); return ret; } gboolean csm_manager_get_autosave_enabled (CsmManager *manager) { return g_settings_get_boolean (manager->priv->settings, KEY_AUTOSAVE); } cinnamon-session-3.6.1/cinnamon-session/csm-manager.h0000644000175000017500000002704313205266677021374 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CSM_MANAGER_H #define __CSM_MANAGER_H #include #include #include "csm-store.h" G_BEGIN_DECLS #define CSM_TYPE_MANAGER (csm_manager_get_type ()) #define CSM_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSM_TYPE_MANAGER, CsmManager)) #define CSM_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSM_TYPE_MANAGER, CsmManagerClass)) #define CSM_IS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSM_TYPE_MANAGER)) #define CSM_IS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSM_TYPE_MANAGER)) #define CSM_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSM_TYPE_MANAGER, CsmManagerClass)) typedef struct CsmManagerPrivate CsmManagerPrivate; typedef struct { GObject parent; CsmManagerPrivate *priv; } CsmManager; typedef struct { GObjectClass parent_class; void (* session_running) (CsmManager *manager); void (* session_over) (CsmManager *manager); void (* session_over_notice) (CsmManager *manager); void (* phase_changed) (CsmManager *manager, const char *phase); void (* client_added) (CsmManager *manager, const char *id); void (* client_removed) (CsmManager *manager, const char *id); void (* inhibitor_added) (CsmManager *manager, const char *id); void (* inhibitor_removed) (CsmManager *manager, const char *id); } CsmManagerClass; typedef enum { /* csm's own startup/initialization phase */ CSM_MANAGER_PHASE_STARTUP = 0, /* gnome-initial-setup */ CSM_MANAGER_PHASE_EARLY_INITIALIZATION, /* gnome-keyring-daemon */ CSM_MANAGER_PHASE_PRE_DISPLAY_SERVER, /* xrandr setup, gnome-settings-daemon, etc */ CSM_MANAGER_PHASE_INITIALIZATION, /* window/compositing managers */ CSM_MANAGER_PHASE_WINDOW_MANAGER, /* apps that will create _NET_WM_WINDOW_TYPE_PANEL windows */ CSM_MANAGER_PHASE_PANEL, /* apps that will create _NET_WM_WINDOW_TYPE_DESKTOP windows */ CSM_MANAGER_PHASE_DESKTOP, /* everything else */ CSM_MANAGER_PHASE_APPLICATION, /* done launching */ CSM_MANAGER_PHASE_RUNNING, /* shutting down */ CSM_MANAGER_PHASE_QUERY_END_SESSION, CSM_MANAGER_PHASE_END_SESSION, CSM_MANAGER_PHASE_EXIT } CsmManagerPhase; typedef enum { CSM_MANAGER_ERROR_GENERAL = 0, CSM_MANAGER_ERROR_NOT_IN_INITIALIZATION, CSM_MANAGER_ERROR_NOT_IN_RUNNING, CSM_MANAGER_ERROR_ALREADY_REGISTERED, CSM_MANAGER_ERROR_NOT_REGISTERED, CSM_MANAGER_ERROR_INVALID_OPTION, CSM_MANAGER_ERROR_LOCKED_DOWN, CSM_MANAGER_NUM_ERRORS } CsmManagerError; #define CSM_MANAGER_ERROR csm_manager_error_quark () typedef enum { CSM_MANAGER_LOGOUT_MODE_NORMAL = 0, CSM_MANAGER_LOGOUT_MODE_NO_CONFIRMATION, CSM_MANAGER_LOGOUT_MODE_FORCE } CsmManagerLogoutMode; GType csm_manager_error_get_type (void); #define CSM_MANAGER_TYPE_ERROR (csm_manager_error_get_type ()) GQuark csm_manager_error_quark (void); GType csm_manager_get_type (void); CsmManager * csm_manager_new (CsmStore *client_store, gboolean failsafe); CsmManager * csm_manager_get (void); gboolean csm_manager_get_failsafe (CsmManager *manager); gboolean csm_manager_add_autostart_app (CsmManager *manager, const char *path, const char *provides); gboolean csm_manager_add_required_app (CsmManager *manager, const char *path, const char *provides); gboolean csm_manager_add_autostart_apps_from_dir (CsmManager *manager, const char *path); gboolean csm_manager_add_legacy_session_apps (CsmManager *manager, const char *path); void csm_manager_start (CsmManager *manager); const char * _csm_manager_get_default_session (CsmManager *manager); void _csm_manager_set_active_session (CsmManager *manager, const char *session_name, gboolean is_fallback); /* exported methods */ gboolean csm_manager_register_client (CsmManager *manager, const char *app_id, const char *client_startup_id, DBusGMethodInvocation *context); gboolean csm_manager_unregister_client (CsmManager *manager, const char *session_client_id, DBusGMethodInvocation *context); gboolean csm_manager_inhibit (CsmManager *manager, const char *app_id, guint toplevel_xid, const char *reason, guint flags, DBusGMethodInvocation *context); gboolean csm_manager_uninhibit (CsmManager *manager, guint inhibit_cookie, DBusGMethodInvocation *context); gboolean csm_manager_is_inhibited (CsmManager *manager, guint flags, gboolean *is_inhibited, GError *error); gboolean csm_manager_request_shutdown (CsmManager *manager, GError **error); gboolean csm_manager_request_reboot (CsmManager *manager, GError **error); gboolean csm_manager_shutdown (CsmManager *manager, GError **error); gboolean csm_manager_reboot (CsmManager *manager, GError **error); gboolean csm_manager_can_shutdown (CsmManager *manager, gboolean *shutdown_available, GError **error); gboolean csm_manager_logout (CsmManager *manager, guint logout_mode, GError **error); gboolean csm_manager_setenv (CsmManager *manager, const char *variable, const char *value, GError **error); gboolean csm_manager_initialization_error (CsmManager *manager, const char *message, gboolean fatal, GError **error); gboolean csm_manager_get_clients (CsmManager *manager, GPtrArray **clients, GError **error); gboolean csm_manager_get_inhibitors (CsmManager *manager, GPtrArray **inhibitors, GError **error); gboolean csm_manager_is_autostart_condition_handled (CsmManager *manager, const char *condition, gboolean *handled, GError **error); gboolean csm_manager_set_phase (CsmManager *manager, CsmManagerPhase phase); gboolean csm_manager_is_session_running (CsmManager *manager, gboolean *running, GError **error); gboolean csm_manager_get_app_is_blacklisted (CsmManager *manager, const gchar *name); gboolean csm_manager_get_autosave_enabled (CsmManager *manager); G_END_DECLS #endif /* __CSM_MANAGER_H */ cinnamon-session-3.6.1/cinnamon-session/csm-marshal.list0000644000175000017500000000012113205266677022121 0ustar maxymaxyBOOLEAN:POINTER VOID:BOOLEAN,BOOLEAN,BOOLEAN,STRING VOID:BOOLEAN,BOOLEAN,POINTER cinnamon-session-3.6.1/cinnamon-session/csm-presence.c0000644000175000017500000005104113205266677021554 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2009 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include "config.h" #include #include #include #include #include #include #include "cs-idle-monitor.h" #include "csm-presence.h" #include "csm-presence-glue.h" #define CSM_PRESENCE_DBUS_PATH "/org/gnome/SessionManager/Presence" #define CS_NAME "org.cinnamon.ScreenSaver" #define CS_PATH "/org/cinnamon/ScreenSaver" #define CS_INTERFACE "org.cinnamon.ScreenSaver" #define MAX_STATUS_TEXT 140 #define CSM_PRESENCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_PRESENCE, CsmPresencePrivate)) struct CsmPresencePrivate { guint status; guint saved_status; char *status_text; gboolean idle_enabled; CSIdleMonitor *idle_monitor; guint idle_watch_id; guint idle_timeout; gboolean screensaver_active; DBusGConnection *bus_connection; DBusGProxy *bus_proxy; DBusGProxy *screensaver_proxy; }; enum { PROP_0, PROP_STATUS, PROP_STATUS_TEXT, PROP_IDLE_ENABLED, PROP_IDLE_TIMEOUT, }; enum { STATUS_CHANGED, STATUS_TEXT_CHANGED, LAST_SIGNAL }; static guint signals [LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (CsmPresence, csm_presence, G_TYPE_OBJECT) GQuark csm_presence_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("csm_presence_error"); } return ret; } #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } GType csm_presence_error_get_type (void) { static GType etype = 0; if (etype == 0) { static const GEnumValue values[] = { ENUM_ENTRY (CSM_PRESENCE_ERROR_GENERAL, "GeneralError"), { 0, 0, 0 } }; g_assert (CSM_PRESENCE_NUM_ERRORS == G_N_ELEMENTS (values) - 1); etype = g_enum_register_static ("CsmPresenceError", values); } return etype; } static void set_session_idle (CsmPresence *presence, gboolean is_idle) { g_debug ("CsmPresence: setting idle: %d", is_idle); if (is_idle) { if (presence->priv->status == CSM_PRESENCE_STATUS_IDLE) { g_debug ("CsmPresence: already idle, ignoring"); return; } /* save current status */ presence->priv->saved_status = presence->priv->status; csm_presence_set_status (presence, CSM_PRESENCE_STATUS_IDLE, NULL); } else { if (presence->priv->status != CSM_PRESENCE_STATUS_IDLE) { g_debug ("CsmPresence: already not idle, ignoring"); return; } /* restore saved status */ csm_presence_set_status (presence, presence->priv->saved_status, NULL); g_debug ("CsmPresence: setting non-idle status %d", presence->priv->saved_status); presence->priv->saved_status = CSM_PRESENCE_STATUS_AVAILABLE; } } static gboolean on_idle_timeout (CSIdleMonitor *monitor, guint id, gboolean condition, CsmPresence *presence) { gboolean handled; handled = TRUE; set_session_idle (presence, condition); return handled; } static void reset_idle_watch (CsmPresence *presence) { if (presence->priv->idle_monitor == NULL) { return; } if (presence->priv->idle_watch_id > 0) { g_debug ("CsmPresence: removing idle watch (%i)", presence->priv->idle_watch_id); cs_idle_monitor_remove_watch (presence->priv->idle_monitor, presence->priv->idle_watch_id); presence->priv->idle_watch_id = 0; } if (! presence->priv->screensaver_active && presence->priv->idle_enabled && presence->priv->idle_timeout > 0) { presence->priv->idle_watch_id = cs_idle_monitor_add_watch (presence->priv->idle_monitor, presence->priv->idle_timeout, (CSIdleMonitorWatchFunc)on_idle_timeout, presence); g_debug ("CsmPresence: adding idle watch (%i) for %d secs", presence->priv->idle_watch_id, presence->priv->idle_timeout / 1000); } } static void on_screensaver_active_changed (DBusGProxy *proxy, gboolean is_active, CsmPresence *presence) { g_debug ("screensaver status changed: %d", is_active); if (presence->priv->screensaver_active != is_active) { presence->priv->screensaver_active = is_active; reset_idle_watch (presence); set_session_idle (presence, is_active); } } static void on_screensaver_proxy_destroy (GObject *proxy, CsmPresence *presence) { g_warning ("Detected that screensaver has left the bus"); presence->priv->screensaver_proxy = NULL; presence->priv->screensaver_active = FALSE; set_session_idle (presence, FALSE); reset_idle_watch (presence); } static void on_bus_name_owner_changed (DBusGProxy *bus_proxy, const char *service_name, const char *old_service_name, const char *new_service_name, CsmPresence *presence) { GError *error; if (service_name == NULL || strcmp (service_name, CS_NAME) != 0) { /* ignore */ return; } if (strlen (new_service_name) == 0 && strlen (old_service_name) > 0) { /* service removed */ /* let destroy signal handle this? */ } else if (strlen (old_service_name) == 0 && strlen (new_service_name) > 0) { /* service added */ g_debug ("Detected that screensaver has appeared on the bus"); error = NULL; presence->priv->screensaver_proxy = dbus_g_proxy_new_for_name_owner (presence->priv->bus_connection, CS_NAME, CS_PATH, CS_INTERFACE, &error); if (presence->priv->screensaver_proxy != NULL) { g_signal_connect (presence->priv->screensaver_proxy, "destroy", G_CALLBACK (on_screensaver_proxy_destroy), presence); dbus_g_proxy_add_signal (presence->priv->screensaver_proxy, "ActiveChanged", G_TYPE_BOOLEAN, G_TYPE_INVALID); dbus_g_proxy_connect_signal (presence->priv->screensaver_proxy, "ActiveChanged", G_CALLBACK (on_screensaver_active_changed), presence, NULL); } else { g_warning ("Unable to get screensaver proxy: %s", error->message); g_error_free (error); } } } static gboolean register_presence (CsmPresence *presence) { GError *error; error = NULL; presence->priv->bus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (presence->priv->bus_connection == NULL) { if (error != NULL) { g_critical ("error getting session bus: %s", error->message); g_error_free (error); } return FALSE; } dbus_g_connection_register_g_object (presence->priv->bus_connection, CSM_PRESENCE_DBUS_PATH, G_OBJECT (presence)); return TRUE; } static GObject * csm_presence_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsmPresence *presence; gboolean res; presence = CSM_PRESENCE (G_OBJECT_CLASS (csm_presence_parent_class)->constructor (type, n_construct_properties, construct_properties)); res = register_presence (presence); if (! res) { g_warning ("Unable to register presence with session bus"); } presence->priv->bus_proxy = dbus_g_proxy_new_for_name (presence->priv->bus_connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); if (presence->priv->bus_proxy != NULL) { dbus_g_proxy_add_signal (presence->priv->bus_proxy, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal (presence->priv->bus_proxy, "NameOwnerChanged", G_CALLBACK (on_bus_name_owner_changed), presence, NULL); } return G_OBJECT (presence); } static void csm_presence_init (CsmPresence *presence) { presence->priv = CSM_PRESENCE_GET_PRIVATE (presence); presence->priv->idle_monitor = cs_idle_monitor_new (); } void csm_presence_set_idle_enabled (CsmPresence *presence, gboolean enabled) { g_return_if_fail (CSM_IS_PRESENCE (presence)); if (presence->priv->idle_enabled != enabled) { presence->priv->idle_enabled = enabled; reset_idle_watch (presence); g_object_notify (G_OBJECT (presence), "idle-enabled"); } } gboolean csm_presence_set_status_text (CsmPresence *presence, const char *status_text, GError **error) { g_return_val_if_fail (CSM_IS_PRESENCE (presence), FALSE); g_free (presence->priv->status_text); presence->priv->status_text = NULL; /* check length */ if (status_text != NULL && strlen (status_text) > MAX_STATUS_TEXT) { g_set_error (error, CSM_PRESENCE_ERROR, CSM_PRESENCE_ERROR_GENERAL, "Status text too long"); return FALSE; } if (status_text != NULL) { presence->priv->status_text = g_strdup (status_text); } g_object_notify (G_OBJECT (presence), "status-text"); g_signal_emit (presence, signals[STATUS_TEXT_CHANGED], 0, presence->priv->status_text ? presence->priv->status_text : ""); return TRUE; } gboolean csm_presence_set_status (CsmPresence *presence, guint status, GError **error) { g_return_val_if_fail (CSM_IS_PRESENCE (presence), FALSE); if (status != presence->priv->status) { presence->priv->status = status; g_object_notify (G_OBJECT (presence), "status"); g_signal_emit (presence, signals[STATUS_CHANGED], 0, presence->priv->status); } return TRUE; } void csm_presence_set_idle_timeout (CsmPresence *presence, guint timeout) { g_return_if_fail (CSM_IS_PRESENCE (presence)); if (timeout != presence->priv->idle_timeout) { presence->priv->idle_timeout = timeout; reset_idle_watch (presence); g_object_notify (G_OBJECT (presence), "idle-timeout"); } } static void csm_presence_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsmPresence *self; self = CSM_PRESENCE (object); switch (prop_id) { case PROP_STATUS: csm_presence_set_status (self, g_value_get_uint (value), NULL); break; case PROP_STATUS_TEXT: csm_presence_set_status_text (self, g_value_get_string (value), NULL); break; case PROP_IDLE_ENABLED: csm_presence_set_idle_enabled (self, g_value_get_boolean (value)); break; case PROP_IDLE_TIMEOUT: csm_presence_set_idle_timeout (self, g_value_get_uint (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_presence_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsmPresence *self; self = CSM_PRESENCE (object); switch (prop_id) { case PROP_STATUS: g_value_set_uint (value, self->priv->status); break; case PROP_STATUS_TEXT: g_value_set_string (value, self->priv->status_text ? self->priv->status_text : ""); break; case PROP_IDLE_ENABLED: g_value_set_boolean (value, self->priv->idle_enabled); break; case PROP_IDLE_TIMEOUT: g_value_set_uint (value, self->priv->idle_timeout); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_presence_finalize (GObject *object) { CsmPresence *presence = (CsmPresence *) object; if (presence->priv->idle_watch_id > 0) { cs_idle_monitor_remove_watch (presence->priv->idle_monitor, presence->priv->idle_watch_id); presence->priv->idle_watch_id = 0; } if (presence->priv->status_text != NULL) { g_free (presence->priv->status_text); presence->priv->status_text = NULL; } if (presence->priv->idle_monitor != NULL) { g_object_unref (presence->priv->idle_monitor); presence->priv->idle_monitor = NULL; } G_OBJECT_CLASS (csm_presence_parent_class)->finalize (object); } static void csm_presence_class_init (CsmPresenceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = csm_presence_finalize; object_class->constructor = csm_presence_constructor; object_class->get_property = csm_presence_get_property; object_class->set_property = csm_presence_set_property; signals [STATUS_CHANGED] = g_signal_new ("status-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmPresenceClass, status_changed), NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT); signals [STATUS_TEXT_CHANGED] = g_signal_new ("status-text-changed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmPresenceClass, status_text_changed), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); g_object_class_install_property (object_class, PROP_STATUS, g_param_spec_uint ("status", "status", "status", 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_STATUS_TEXT, g_param_spec_string ("status-text", "status text", "status text", "", G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_IDLE_ENABLED, g_param_spec_boolean ("idle-enabled", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_IDLE_TIMEOUT, g_param_spec_uint ("idle-timeout", "idle timeout", "idle timeout", 0, G_MAXINT, 300000, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); dbus_g_object_type_install_info (CSM_TYPE_PRESENCE, &dbus_glib_csm_presence_object_info); dbus_g_error_domain_register (CSM_PRESENCE_ERROR, NULL, CSM_PRESENCE_TYPE_ERROR); g_type_class_add_private (klass, sizeof (CsmPresencePrivate)); } CsmPresence * csm_presence_new (void) { CsmPresence *presence; presence = g_object_new (CSM_TYPE_PRESENCE, NULL); return presence; } cinnamon-session-3.6.1/cinnamon-session/csm-presence.h0000644000175000017500000000706713205266677021572 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2009 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_PRESENCE_H__ #define __CSM_PRESENCE_H__ #include #include G_BEGIN_DECLS #define CSM_TYPE_PRESENCE (csm_presence_get_type ()) #define CSM_PRESENCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSM_TYPE_PRESENCE, CsmPresence)) #define CSM_PRESENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSM_TYPE_PRESENCE, CsmPresenceClass)) #define CSM_IS_PRESENCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSM_TYPE_PRESENCE)) #define CSM_IS_PRESENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSM_TYPE_PRESENCE)) #define CSM_PRESENCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CSM_TYPE_PRESENCE, CsmPresenceClass)) typedef struct _CsmPresence CsmPresence; typedef struct _CsmPresenceClass CsmPresenceClass; typedef struct CsmPresencePrivate CsmPresencePrivate; struct _CsmPresence { GObject parent; CsmPresencePrivate *priv; }; struct _CsmPresenceClass { GObjectClass parent_class; void (* status_changed) (CsmPresence *presence, guint status); void (* status_text_changed) (CsmPresence *presence, const char *status_text); }; typedef enum { CSM_PRESENCE_STATUS_AVAILABLE = 0, CSM_PRESENCE_STATUS_INVISIBLE, CSM_PRESENCE_STATUS_BUSY, CSM_PRESENCE_STATUS_IDLE, } CsmPresenceStatus; typedef enum { CSM_PRESENCE_ERROR_GENERAL = 0, CSM_PRESENCE_NUM_ERRORS } CsmPresenceError; #define CSM_PRESENCE_ERROR csm_presence_error_quark () GType csm_presence_error_get_type (void); #define CSM_PRESENCE_TYPE_ERROR (csm_presence_error_get_type ()) GQuark csm_presence_error_quark (void); GType csm_presence_get_type (void) G_GNUC_CONST; CsmPresence * csm_presence_new (void); void csm_presence_set_idle_enabled (CsmPresence *presence, gboolean enabled); void csm_presence_set_idle_timeout (CsmPresence *presence, guint n_seconds); /* exported to bus */ gboolean csm_presence_set_status (CsmPresence *presence, guint status, GError **error); gboolean csm_presence_set_status_text (CsmPresence *presence, const char *status_text, GError **error); G_END_DECLS #endif /* __CSM_PRESENCE_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-process-helper.c0000644000175000017500000001124213205266677022702 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Novell, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include #include #include #include #include #include #include "csm-process-helper.h" typedef struct { const char *command_line; GPid pid; gboolean timed_out; int status; GMainLoop *loop; guint child_id; guint timeout_id; } CsmProcessHelper; static void on_child_exited (GPid pid, gint status, gpointer data) { CsmProcessHelper *helper = data; helper->timed_out = FALSE; helper->status = status; g_spawn_close_pid (pid); g_main_loop_quit (helper->loop); } static gboolean on_child_timeout (gpointer data) { CsmProcessHelper *helper = data; kill (helper->pid, SIGTERM); helper->timed_out = TRUE; g_main_loop_quit (helper->loop); return FALSE; } gboolean csm_process_helper (const char *command_line, unsigned int timeout, GError **error) { CsmProcessHelper *helper; gchar **argv = NULL; GPid pid; gboolean ret; if (!g_shell_parse_argv (command_line, NULL, &argv, error)) return FALSE; ret = g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, error); g_strfreev (argv); if (!ret) return FALSE; ret = FALSE; helper = g_slice_new0 (CsmProcessHelper); helper->command_line = command_line; helper->pid = pid; helper->timed_out = FALSE; helper->status = -1; helper->loop = g_main_loop_new (NULL, FALSE); helper->child_id = g_child_watch_add (helper->pid, on_child_exited, helper); helper->timeout_id = g_timeout_add (timeout, on_child_timeout, helper); g_main_loop_run (helper->loop); if (helper->timed_out) { g_set_error_literal (error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, "Timed out"); } else { if (WIFEXITED (helper->status)) { if (WEXITSTATUS (helper->status) == 0) ret = TRUE; else g_set_error (error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, _("Exited with code %d"), WEXITSTATUS (helper->status)); } else if (WIFSIGNALED (helper->status)) { g_set_error (error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, _("Killed by signal %d"), WTERMSIG (helper->status)); } else if (WIFSTOPPED (helper->status)) { g_set_error (error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, _("Stopped by signal %d"), WSTOPSIG (helper->status)); } } if (helper->loop) { g_main_loop_unref (helper->loop); helper->loop = NULL; } if (helper->child_id) { g_source_remove (helper->child_id); helper->child_id = 0; } if (helper->timeout_id) { g_source_remove (helper->timeout_id); helper->timeout_id = 0; } g_slice_free (CsmProcessHelper, helper); return ret; } cinnamon-session-3.6.1/cinnamon-session/csm-process-helper.h0000644000175000017500000000217113205266677022710 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Novell, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_PROCESS_HELPER_H #define __CSM_PROCESS_HELPER_H #include G_BEGIN_DECLS int csm_process_helper (const char *command_line, unsigned int timeout, GError **error); G_END_DECLS #endif /* __CSM_PROCESS_HELPER_H */ cinnamon-session-3.6.1/cinnamon-session/csm-session-fill.c0000644000175000017500000004234413205266677022365 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006, 2010 Novell, Inc. * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include #include "csm-session-fill.h" #include "csm-system.h" #include "csm-manager.h" #include "csm-process-helper.h" #include "csm-util.h" #define CSM_KEYFILE_SESSION_GROUP "Cinnamon Session" #define CSM_KEYFILE_RUNNABLE_KEY "IsRunnableHelper" #define CSM_KEYFILE_FALLBACK_KEY "FallbackSession" #define CSM_KEYFILE_DESKTOP_NAME_KEY "DesktopName" #define CSM_KEYFILE_REQUIRED_COMPONENTS_KEY "RequiredComponents" #define CSM_KEYFILE_REQUIRED_PROVIDERS_KEY "RequiredProviders" #define CSM_KEYFILE_DEFAULT_PROVIDER_PREFIX "DefaultProvider" /* See https://bugzilla.gnome.org/show_bug.cgi?id=641992 for discussion */ #define CSM_RUNNABLE_HELPER_TIMEOUT 3000 /* ms */ typedef void (*CsmFillHandleProvider) (const char *provides, const char *default_provider, const char *app_path, gpointer user_data); typedef void (*CsmFillHandleComponent) (const char *component, const char *app_path, gpointer user_data); static void handle_default_providers (GKeyFile *keyfile, gboolean look_in_saved_session, CsmFillHandleProvider callback, gpointer user_data) { char **default_providers; int i; g_assert (keyfile != NULL); g_assert (callback != NULL); default_providers = g_key_file_get_string_list (keyfile, CSM_KEYFILE_SESSION_GROUP, CSM_KEYFILE_REQUIRED_PROVIDERS_KEY, NULL, NULL); if (!default_providers) return; for (i = 0; default_providers[i] != NULL; i++) { char *key; char *value; char *app_path; if (IS_STRING_EMPTY (default_providers[i])) continue; key = g_strdup_printf ("%s-%s", CSM_KEYFILE_DEFAULT_PROVIDER_PREFIX, default_providers[i]); value = g_key_file_get_string (keyfile, CSM_KEYFILE_SESSION_GROUP, key, NULL); g_free (key); if (IS_STRING_EMPTY (value)) { g_free (value); continue; } g_debug ("fill: provider '%s' looking for component: '%s'", default_providers[i], value); app_path = csm_util_find_desktop_file_for_app_name (value, look_in_saved_session, TRUE); callback (default_providers[i], value, app_path, user_data); g_free (app_path); g_free (value); } g_strfreev (default_providers); } static void handle_required_components (GKeyFile *keyfile, gboolean look_in_saved_session, CsmFillHandleComponent callback, gpointer user_data) { char **required_components; int i; g_assert (keyfile != NULL); g_assert (callback != NULL); required_components = g_key_file_get_string_list (keyfile, CSM_KEYFILE_SESSION_GROUP, CSM_KEYFILE_REQUIRED_COMPONENTS_KEY, NULL, NULL); if (!required_components) return; for (i = 0; required_components[i] != NULL; i++) { char *app_path; app_path = csm_util_find_desktop_file_for_app_name (required_components[i], look_in_saved_session, TRUE); callback (required_components[i], app_path, user_data); g_free (app_path); } g_strfreev (required_components); } static void check_required_providers_helper (const char *provides, const char *default_provider, const char *app_path, gpointer user_data) { gboolean *error = user_data; if (app_path == NULL) { g_warning ("Unable to find default provider '%s' of required provider '%s'", default_provider, provides); *error = TRUE; } } static void check_required_components_helper (const char *component, const char *app_path, gpointer user_data) { gboolean *error = user_data; if (app_path == NULL) { g_warning ("Unable to find required component '%s'", component); *error = TRUE; } } static gboolean check_required (GKeyFile *keyfile) { gboolean error = FALSE; g_debug ("fill: *** Checking required components and providers"); handle_default_providers (keyfile, FALSE, check_required_providers_helper, &error); handle_required_components (keyfile, FALSE, check_required_components_helper, &error); g_debug ("fill: *** Done checking required components and providers"); return !error; } static void maybe_load_saved_session_apps (CsmManager *manager) { CsmSystem *system; gboolean is_login; system = csm_get_system (); is_login = csm_system_is_login_session (system); g_object_unref (system); // if (is_login) // return; csm_manager_add_autostart_apps_from_dir (manager, csm_util_get_saved_session_dir ()); } static void append_required_providers_helper (const char *provides, const char *default_provider, const char *app_path, gpointer user_data) { CsmManager *manager = user_data; if (app_path == NULL) g_warning ("Unable to find default provider '%s' of required provider '%s'", default_provider, provides); else csm_manager_add_required_app (manager, app_path, provides); } static void append_required_components_helper (const char *component, const char *app_path, gpointer user_data) { CsmManager *manager = user_data; if (app_path == NULL) g_warning ("Unable to find required component '%s'", component); else csm_manager_add_required_app (manager, app_path, NULL); } static void load_standard_apps (CsmManager *manager, GKeyFile *keyfile) { if (g_file_test ("/usr/bin/session-migration", G_FILE_TEST_EXISTS)) { GError *error; g_debug ("fill: *** Executing user migration"); error = NULL; if(!g_spawn_command_line_sync ("session-migration", NULL, NULL, NULL, &error)) { g_warning ("Error while executing session-migration: %s", error->message); g_error_free (error); } } g_debug ("fill: *** Adding required components"); handle_required_components (keyfile, !csm_manager_get_failsafe (manager), append_required_components_helper, manager); g_debug ("fill: *** Done adding required components"); if (!csm_manager_get_failsafe (manager)) { char **autostart_dirs; int i; autostart_dirs = csm_util_get_autostart_dirs (); if (csm_manager_get_autosave_enabled (manager)) maybe_load_saved_session_apps (manager); for (i = 0; autostart_dirs[i]; i++) { csm_manager_add_autostart_apps_from_dir (manager, autostart_dirs[i]); } g_strfreev (autostart_dirs); } g_debug ("fill: *** Adding default providers"); handle_default_providers (keyfile, !csm_manager_get_failsafe (manager), append_required_providers_helper, manager); g_debug ("fill: *** Done adding default providers"); } static GKeyFile * get_session_keyfile_if_valid (const char *path) { GKeyFile *keyfile; gsize len; char **list; g_debug ("fill: *** Looking if %s is a valid session file", path); keyfile = g_key_file_new (); if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, NULL)) { g_debug ("Cannot use session '%s': non-existing or invalid file.", path); goto error; } if (!g_key_file_has_group (keyfile, CSM_KEYFILE_SESSION_GROUP)) { g_warning ("Cannot use session '%s': no '%s' group.", path, CSM_KEYFILE_SESSION_GROUP); goto error; } /* check that we have default providers defined for required providers */ list = g_key_file_get_string_list (keyfile, CSM_KEYFILE_SESSION_GROUP, CSM_KEYFILE_REQUIRED_PROVIDERS_KEY, &len, NULL); if (list != NULL) { int i; char *key; char *value; for (i = 0; list[i] != NULL; i++) { key = g_strdup_printf ("%s-%s", CSM_KEYFILE_DEFAULT_PROVIDER_PREFIX, list[i]); value = g_key_file_get_string (keyfile, CSM_KEYFILE_SESSION_GROUP, key, NULL); g_free (key); if (IS_STRING_EMPTY (value)) { g_free (value); break; } g_free (value); } if (list[i] != NULL) { g_warning ("Cannot use session '%s': required provider '%s' is not defined.", path, list[i]); g_strfreev (list); goto error; } g_strfreev (list); } /* we don't want an empty session, so if there's no required provider, check * that we do have some required components */ if (len == 0) { list = g_key_file_get_string_list (keyfile, CSM_KEYFILE_SESSION_GROUP, CSM_KEYFILE_REQUIRED_COMPONENTS_KEY, &len, NULL); if (list) g_strfreev (list); if (len == 0) { g_warning ("Cannot use session '%s': no component in the session.", path); goto error; } } return keyfile; error: g_key_file_free (keyfile); return NULL; } /** * find_valid_session_keyfile: * @session: name of session * * We look for the session file in XDG_CONFIG_HOME, XDG_CONFIG_DIRS and * XDG_DATA_DIRS. This enables users and sysadmins to override a specific * session that is shipped in XDG_DATA_DIRS. */ static GKeyFile * find_valid_session_keyfile (const char *session) { GPtrArray *dirs; const char * const *system_config_dirs; const char * const *system_data_dirs; int i; GKeyFile *keyfile; char *basename; char *path; dirs = g_ptr_array_new (); g_ptr_array_add (dirs, (gpointer) g_get_user_config_dir ()); system_config_dirs = g_get_system_config_dirs (); for (i = 0; system_config_dirs[i]; i++) g_ptr_array_add (dirs, (gpointer) system_config_dirs[i]); system_data_dirs = g_get_system_data_dirs (); for (i = 0; system_data_dirs[i]; i++) g_ptr_array_add (dirs, (gpointer) system_data_dirs[i]); keyfile = NULL; basename = g_strdup_printf ("%s.session", session); path = NULL; for (i = 0; i < dirs->len; i++) { path = g_build_filename (dirs->pdata[i], "cinnamon-session", "sessions", basename, NULL); keyfile = get_session_keyfile_if_valid (path); if (keyfile != NULL) break; } if (dirs) g_ptr_array_free (dirs, TRUE); if (basename) g_free (basename); if (path) g_free (path); return keyfile; } static GKeyFile * get_session_keyfile (const char *session, char **actual_session, gboolean *is_fallback) { GKeyFile *keyfile; gboolean session_runnable; char *value; GError *error = NULL; *actual_session = NULL; g_debug ("fill: *** Getting session '%s'", session); keyfile = find_valid_session_keyfile (session); if (!keyfile) return NULL; session_runnable = TRUE; value = g_key_file_get_string (keyfile, CSM_KEYFILE_SESSION_GROUP, CSM_KEYFILE_RUNNABLE_KEY, NULL); if (!IS_STRING_EMPTY (value)) { g_debug ("fill: *** Launching helper '%s' to know if session is runnable", value); session_runnable = csm_process_helper (value, CSM_RUNNABLE_HELPER_TIMEOUT, &error); if (!session_runnable) { g_warning ("Session '%s' runnable check failed: %s", session, error->message); g_clear_error (&error); } } g_free (value); if (session_runnable) { session_runnable = check_required (keyfile); } if (session_runnable) { *actual_session = g_strdup (session); if (is_fallback) *is_fallback = FALSE; return keyfile; } g_debug ("fill: *** Session is not runnable"); /* We can't run this session, so try to use the fallback */ value = g_key_file_get_string (keyfile, CSM_KEYFILE_SESSION_GROUP, CSM_KEYFILE_FALLBACK_KEY, NULL); g_key_file_free (keyfile); keyfile = NULL; if (!IS_STRING_EMPTY (value)) { if (is_fallback) *is_fallback = TRUE; keyfile = get_session_keyfile (value, actual_session, NULL); } g_free (value); return keyfile; } static void set_xdg_current_desktop (GKeyFile *keyfile) { char *value; value = g_key_file_get_string (keyfile, CSM_KEYFILE_SESSION_GROUP, CSM_KEYFILE_DESKTOP_NAME_KEY, NULL); if (!IS_STRING_EMPTY (value)) { csm_util_setenv ("XDG_CURRENT_DESKTOP", value); } else { csm_util_setenv ("XDG_CURRENT_DESKTOP", "GNOME"); } g_free (value); } gboolean csm_session_fill (CsmManager *manager, const char *session) { GKeyFile *keyfile; gboolean is_fallback; char *actual_session; keyfile = get_session_keyfile (session, &actual_session, &is_fallback); if (!keyfile) { g_free (actual_session); return FALSE; } _csm_manager_set_active_session (manager, actual_session, is_fallback); g_free (actual_session); set_xdg_current_desktop (keyfile); load_standard_apps (manager, keyfile); g_key_file_free (keyfile); return TRUE; } cinnamon-session-3.6.1/cinnamon-session/csm-session-fill.h0000644000175000017500000000216013205266677022362 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006, 2010 Novell, Inc. * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_SESSION_FILL_H #define __CSM_SESSION_FILL_H #include "csm-manager.h" G_BEGIN_DECLS gboolean csm_session_fill (CsmManager *manager, const char *session); G_END_DECLS #endif /* __CSM_SESSION_FILL_H */ cinnamon-session-3.6.1/cinnamon-session/csm-session-save.c0000644000175000017500000002145413205266677022374 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * csm-session-save.c * Copyright (C) 2008 Lucas Rocha. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include #include #include #include "csm-util.h" #include "csm-autostart-app.h" #include "csm-client.h" #include "csm-session-save.h" static gboolean csm_session_clear_saved_session (const char *directory, GHashTable *discard_hash); typedef struct { char *dir; GHashTable *discard_hash; GError **error; } SessionSaveData; static gboolean save_one_client (char *id, GObject *object, SessionSaveData *data) { CsmClient *client; GKeyFile *keyfile; const char *app_id; char *path = NULL; char *filename = NULL; char *contents = NULL; gsize length = 0; char *discard_exec; GError *local_error; client = CSM_CLIENT (object); local_error = NULL; keyfile = csm_client_save (client, &local_error); if (keyfile == NULL || local_error) { goto out; } contents = g_key_file_to_data (keyfile, &length, &local_error); if (local_error) { goto out; } app_id = csm_client_peek_app_id (client); if (!IS_STRING_EMPTY (app_id)) { if (g_str_has_suffix (app_id, ".desktop")) filename = g_strdup (app_id); else filename = g_strdup_printf ("%s.desktop", app_id); path = g_build_filename (data->dir, filename, NULL); } if (!path || g_file_test (path, G_FILE_TEST_EXISTS)) { if (filename) g_free (filename); if (path) g_free (path); filename = g_strdup_printf ("%s.desktop", csm_client_peek_startup_id (client)); path = g_build_filename (data->dir, filename, NULL); } g_file_set_contents (path, contents, length, &local_error); if (local_error) { goto out; } discard_exec = g_key_file_get_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, CSM_AUTOSTART_APP_DISCARD_KEY, NULL); if (discard_exec) { g_hash_table_insert (data->discard_hash, discard_exec, discard_exec); } g_debug ("CsmSessionSave: saved client %s to %s", id, filename); out: if (keyfile != NULL) { g_key_file_free (keyfile); } g_free (contents); g_free (filename); g_free (path); /* in case of any error, stop saving session */ if (local_error) { g_propagate_error (data->error, local_error); g_error_free (local_error); return TRUE; } return FALSE; } void csm_session_save (CsmStore *client_store, GError **error) { const char *save_dir; char *tmp_dir; SessionSaveData data; g_debug ("CsmSessionSave: Saving session"); save_dir = csm_util_get_saved_session_dir (); if (save_dir == NULL) { g_warning ("CsmSessionSave: cannot create saved session directory"); return; } tmp_dir = csm_util_get_empty_tmp_session_dir (); if (tmp_dir == NULL) { g_warning ("CsmSessionSave: cannot create new saved session directory"); return; } /* save the session in a temp directory, and remember the discard * commands */ data.dir = tmp_dir; data.discard_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); data.error = error; csm_store_foreach (client_store, (CsmStoreFunc) save_one_client, &data); if (!*error) { /* remove the old saved session */ csm_session_clear_saved_session (save_dir, data.discard_hash); /* rename the temp session dir */ if (g_file_test (save_dir, G_FILE_TEST_IS_DIR)) g_rmdir (save_dir); g_rename (tmp_dir, save_dir); } else { g_warning ("CsmSessionSave: error saving session: %s", (*error)->message); /* FIXME: we should create a hash table filled with the discard * commands that are in desktop files from save_dir. */ csm_session_clear_saved_session (tmp_dir, NULL); g_rmdir (tmp_dir); } g_hash_table_destroy (data.discard_hash); g_free (tmp_dir); } static gboolean csm_session_clear_one_client (const char *filename, GHashTable *discard_hash) { gboolean result = TRUE; GKeyFile *key_file = NULL; char *discard_exec = NULL; g_debug ("CsmSessionSave: removing '%s' from saved session", filename); key_file = g_key_file_new (); if (g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL)) { char **argv; int argc; discard_exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, CSM_AUTOSTART_APP_DISCARD_KEY, NULL); if (!discard_exec) goto out; if (discard_hash && g_hash_table_lookup (discard_hash, discard_exec)) goto out; if (!g_shell_parse_argv (discard_exec, &argc, &argv, NULL)) goto out; result = g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL) && result; g_strfreev (argv); } else { result = FALSE; } out: if (key_file) g_key_file_free (key_file); if (discard_exec) g_free (discard_exec); result = (g_unlink (filename) == 0) && result; return result; } static gboolean csm_session_clear_saved_session (const char *directory, GHashTable *discard_hash) { GDir *dir; const char *filename; gboolean result = TRUE; GError *error; g_debug ("CsmSessionSave: clearing currently saved session at %s", directory); if (directory == NULL) { return FALSE; } error = NULL; dir = g_dir_open (directory, 0, &error); if (error) { g_warning ("CsmSessionSave: error loading saved session directory: %s", error->message); g_error_free (error); return FALSE; } while ((filename = g_dir_read_name (dir))) { char *path = g_build_filename (directory, filename, NULL); result = csm_session_clear_one_client (path, discard_hash) && result; g_free (path); } g_dir_close (dir); return result; } void csm_session_save_clear (void) { const char *save_dir; g_debug ("CsmSessionSave: Clearing saved session"); save_dir = csm_util_get_saved_session_dir (); if (save_dir == NULL) { g_warning ("CsmSessionSave: cannot create saved session directory"); return; } csm_session_clear_saved_session (save_dir, NULL); } cinnamon-session-3.6.1/cinnamon-session/csm-session-save.h0000644000175000017500000000217113205266677022374 0ustar maxymaxy/* csm-session-save.h * Copyright (C) 2008 Lucas Rocha. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_SESSION_SAVE_H__ #define __CSM_SESSION_SAVE_H__ #include #include "csm-store.h" G_BEGIN_DECLS void csm_session_save (CsmStore *client_store, GError **error); void csm_session_save_clear (void); G_END_DECLS #endif /* __CSM_SESSION_SAVE_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-store.c0000644000175000017500000002531213205266677021106 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include "csm-store.h" #define CSM_STORE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_STORE, CsmStorePrivate)) struct CsmStorePrivate { GHashTable *objects; gboolean locked; }; enum { ADDED, REMOVED, LAST_SIGNAL }; enum { PROP_0, PROP_LOCKED }; static guint signals [LAST_SIGNAL] = { 0 }; static void csm_store_finalize (GObject *object); G_DEFINE_TYPE (CsmStore, csm_store, G_TYPE_OBJECT) GQuark csm_store_error_quark (void) { static GQuark ret = 0; if (ret == 0) { ret = g_quark_from_static_string ("csm_store_error"); } return ret; } guint csm_store_size (CsmStore *store) { return g_hash_table_size (store->priv->objects); } gboolean csm_store_remove (CsmStore *store, const char *id) { GObject *found; gboolean removed; char *id_copy; g_return_val_if_fail (store != NULL, FALSE); found = g_hash_table_lookup (store->priv->objects, id); if (found == NULL) { return FALSE; } id_copy = g_strdup (id); g_object_ref (found); removed = g_hash_table_remove (store->priv->objects, id_copy); g_assert (removed); g_signal_emit (store, signals [REMOVED], 0, id_copy); g_object_unref (found); g_free (id_copy); return TRUE; } void csm_store_foreach (CsmStore *store, CsmStoreFunc func, gpointer user_data) { g_return_if_fail (store != NULL); g_return_if_fail (func != NULL); g_hash_table_find (store->priv->objects, (GHRFunc)func, user_data); } GObject * csm_store_find (CsmStore *store, CsmStoreFunc predicate, gpointer user_data) { GObject *object; g_return_val_if_fail (store != NULL, NULL); g_return_val_if_fail (predicate != NULL, NULL); object = g_hash_table_find (store->priv->objects, (GHRFunc)predicate, user_data); return object; } GObject * csm_store_lookup (CsmStore *store, const char *id) { GObject *object; g_return_val_if_fail (store != NULL, NULL); g_return_val_if_fail (id != NULL, NULL); object = g_hash_table_lookup (store->priv->objects, id); return object; } typedef struct { CsmStoreFunc func; gpointer user_data; CsmStore *store; GList *removed; } WrapperData; static gboolean foreach_remove_wrapper (const char *id, GObject *object, WrapperData *data) { gboolean res; res = (data->func) (id, object, data->user_data); if (res) { data->removed = g_list_prepend (data->removed, g_strdup (id)); } return res; } guint csm_store_foreach_remove (CsmStore *store, CsmStoreFunc func, gpointer user_data) { guint ret; WrapperData data; g_return_val_if_fail (store != NULL, 0); g_return_val_if_fail (func != NULL, 0); data.store = store; data.user_data = user_data; data.func = func; data.removed = NULL; ret = g_hash_table_foreach_remove (store->priv->objects, (GHRFunc)foreach_remove_wrapper, &data); while (data.removed != NULL) { char *id; id = data.removed->data; g_debug ("CsmStore: emitting removed for %s", id); g_signal_emit (store, signals [REMOVED], 0, id); g_free (data.removed->data); data.removed->data = NULL; data.removed = g_list_delete_link (data.removed, data.removed); } return ret; } static gboolean _remove_all (const char *id, GObject *object, gpointer data) { return TRUE; } void csm_store_clear (CsmStore *store) { g_return_if_fail (store != NULL); g_debug ("CsmStore: Clearing object store"); csm_store_foreach_remove (store, _remove_all, NULL); } gboolean csm_store_add (CsmStore *store, const char *id, GObject *object) { g_return_val_if_fail (store != NULL, FALSE); g_return_val_if_fail (id != NULL, FALSE); g_return_val_if_fail (object != NULL, FALSE); /* If we're locked, we don't accept any new session objects. */ if (store->priv->locked) { return FALSE; } g_debug ("CsmStore: Adding object id %s to store", id); g_hash_table_insert (store->priv->objects, g_strdup (id), g_object_ref (object)); g_signal_emit (store, signals [ADDED], 0, id); return TRUE; } void csm_store_set_locked (CsmStore *store, gboolean locked) { g_return_if_fail (CSM_IS_STORE (store)); store->priv->locked = locked; } gboolean csm_store_get_locked (CsmStore *store) { g_return_val_if_fail (CSM_IS_STORE (store), FALSE); return store->priv->locked; } static void csm_store_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsmStore *self; self = CSM_STORE (object); switch (prop_id) { case PROP_LOCKED: csm_store_set_locked (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_store_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsmStore *self; self = CSM_STORE (object); switch (prop_id) { case PROP_LOCKED: g_value_set_boolean (value, self->priv->locked); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_store_dispose (GObject *object) { CsmStore *store; g_return_if_fail (object != NULL); g_return_if_fail (CSM_IS_STORE (object)); store = CSM_STORE (object); csm_store_clear (store); G_OBJECT_CLASS (csm_store_parent_class)->dispose (object); } static void csm_store_class_init (CsmStoreClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = csm_store_get_property; object_class->set_property = csm_store_set_property; object_class->finalize = csm_store_finalize; object_class->dispose = csm_store_dispose; signals [ADDED] = g_signal_new ("added", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmStoreClass, added), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); signals [REMOVED] = g_signal_new ("removed", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmStoreClass, removed), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); g_object_class_install_property (object_class, PROP_LOCKED, g_param_spec_boolean ("locked", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (CsmStorePrivate)); } static void _destroy_object (GObject *object) { g_debug ("CsmStore: Unreffing object: %p", object); g_object_unref (object); } static void csm_store_init (CsmStore *store) { store->priv = CSM_STORE_GET_PRIVATE (store); store->priv->objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) _destroy_object); } static void csm_store_finalize (GObject *object) { CsmStore *store; g_return_if_fail (object != NULL); g_return_if_fail (CSM_IS_STORE (object)); store = CSM_STORE (object); g_return_if_fail (store->priv != NULL); g_hash_table_destroy (store->priv->objects); G_OBJECT_CLASS (csm_store_parent_class)->finalize (object); } CsmStore * csm_store_new (void) { GObject *object; object = g_object_new (CSM_TYPE_STORE, NULL); return CSM_STORE (object); } cinnamon-session-3.6.1/cinnamon-session/csm-store.h0000644000175000017500000000765513205266677021125 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007-2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CSM_STORE_H #define __CSM_STORE_H #include G_BEGIN_DECLS #define CSM_TYPE_STORE (csm_store_get_type ()) #define CSM_STORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSM_TYPE_STORE, CsmStore)) #define CSM_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSM_TYPE_STORE, CsmStoreClass)) #define CSM_IS_STORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSM_TYPE_STORE)) #define CSM_IS_STORE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSM_TYPE_STORE)) #define CSM_STORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSM_TYPE_STORE, CsmStoreClass)) typedef struct CsmStorePrivate CsmStorePrivate; typedef struct { GObject parent; CsmStorePrivate *priv; } CsmStore; typedef struct { GObjectClass parent_class; void (* added) (CsmStore *store, const char *id); void (* removed) (CsmStore *store, const char *id); } CsmStoreClass; typedef enum { CSM_STORE_ERROR_GENERAL } CsmStoreError; #define CSM_STORE_ERROR csm_store_error_quark () typedef gboolean (*CsmStoreFunc) (const char *id, GObject *object, gpointer user_data); GQuark csm_store_error_quark (void); GType csm_store_get_type (void); CsmStore * csm_store_new (void); gboolean csm_store_get_locked (CsmStore *store); void csm_store_set_locked (CsmStore *store, gboolean locked); guint csm_store_size (CsmStore *store); gboolean csm_store_add (CsmStore *store, const char *id, GObject *object); void csm_store_clear (CsmStore *store); gboolean csm_store_remove (CsmStore *store, const char *id); void csm_store_foreach (CsmStore *store, CsmStoreFunc func, gpointer user_data); guint csm_store_foreach_remove (CsmStore *store, CsmStoreFunc func, gpointer user_data); GObject * csm_store_find (CsmStore *store, CsmStoreFunc predicate, gpointer user_data); GObject * csm_store_lookup (CsmStore *store, const char *id); G_END_DECLS #endif /* __CSM_STORE_H */ cinnamon-session-3.6.1/cinnamon-session/csm-system.c0000644000175000017500000001173613205266677021303 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * 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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include "config.h" #include #include #include #include "csm-system.h" #include "csm-consolekit.h" #include "csm-systemd.h" enum { REQUEST_FAILED = 0, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_INTERFACE (CsmSystem, csm_system, G_TYPE_OBJECT) static void csm_system_default_init (CsmSystemInterface *iface) { signals [REQUEST_FAILED] = g_signal_new ("request-failed", CSM_TYPE_SYSTEM, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmSystemInterface, request_completed), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); } GQuark csm_system_error_quark (void) { static GQuark error_quark = 0; if (error_quark == 0) { error_quark = g_quark_from_static_string ("csm-system-error"); } return error_quark; } gboolean csm_system_can_switch_user (CsmSystem *system) { return CSM_SYSTEM_GET_IFACE (system)->can_switch_user (system); } gboolean csm_system_can_stop (CsmSystem *system) { return CSM_SYSTEM_GET_IFACE (system)->can_stop (system); } gboolean csm_system_can_restart (CsmSystem *system) { return CSM_SYSTEM_GET_IFACE (system)->can_restart (system); } gboolean csm_system_can_hybrid_sleep (CsmSystem *system) { return CSM_SYSTEM_GET_IFACE (system)->can_hybrid_sleep (system); } gboolean csm_system_can_suspend (CsmSystem *system) { return CSM_SYSTEM_GET_IFACE (system)->can_suspend (system); } gboolean csm_system_can_hibernate (CsmSystem *system) { return CSM_SYSTEM_GET_IFACE (system)->can_hibernate (system); } void csm_system_attempt_stop (CsmSystem *system) { CSM_SYSTEM_GET_IFACE (system)->attempt_stop (system); } void csm_system_attempt_restart (CsmSystem *system) { CSM_SYSTEM_GET_IFACE (system)->attempt_restart (system); } void csm_system_hybrid_sleep (CsmSystem *system) { CSM_SYSTEM_GET_IFACE (system)->hybrid_sleep (system); } void csm_system_suspend (CsmSystem *system) { CSM_SYSTEM_GET_IFACE (system)->suspend (system); } void csm_system_hibernate (CsmSystem *system) { CSM_SYSTEM_GET_IFACE (system)->hibernate (system); } void csm_system_set_session_idle (CsmSystem *system, gboolean is_idle) { CSM_SYSTEM_GET_IFACE (system)->set_session_idle (system, is_idle); } void csm_system_add_inhibitor (CsmSystem *system, const gchar *id, CsmInhibitorFlag flag) { CSM_SYSTEM_GET_IFACE (system)->add_inhibitor (system, id, flag); } void csm_system_remove_inhibitor (CsmSystem *system, const gchar *id) { CSM_SYSTEM_GET_IFACE (system)->remove_inhibitor (system, id); } gboolean csm_system_is_login_session (CsmSystem *system) { return CSM_SYSTEM_GET_IFACE (system)->is_login_session (system); } gboolean csm_system_is_last_session_for_user (CsmSystem *system) { return CSM_SYSTEM_GET_IFACE (system)->is_last_session_for_user (system); } CsmSystem * csm_get_system (void) { static CsmSystem *system = NULL; if (system == NULL) { GSettings *session_settings = g_settings_new ("org.cinnamon.desktop.session"); if (g_settings_get_boolean (session_settings, "session-manager-uses-logind")) { // Use logind system = CSM_SYSTEM (csm_systemd_new ()); if (system != NULL) { g_debug ("Using systemd for session tracking"); } } else { // Use consolekit system = CSM_SYSTEM (csm_consolekit_new ()); if (system != NULL) { g_debug ("Using ConsoleKit for session tracking"); } } g_object_unref (session_settings); } return g_object_ref (system); } cinnamon-session-3.6.1/cinnamon-session/csm-system.h0000644000175000017500000001110413205266677021275 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Jon McCann * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Authors: * Jon McCann */ #ifndef __CSM_SYSTEM_H__ #define __CSM_SYSTEM_H__ #include #include #include "csm-inhibitor.h" G_BEGIN_DECLS #define CSM_TYPE_SYSTEM (csm_system_get_type ()) #define CSM_SYSTEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSM_TYPE_SYSTEM, CsmSystem)) #define CSM_SYSTEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSM_TYPE_SYSTEM, CsmSystemInterface)) #define CSM_IS_SYSTEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSM_TYPE_SYSTEM)) #define CSM_SYSTEM_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE((obj), CSM_TYPE_SYSTEM, CsmSystemInterface)) #define CSM_SYSTEM_ERROR (csm_system_error_quark ()) typedef struct _CsmSystem CsmSystem; typedef struct _CsmSystemInterface CsmSystemInterface; typedef enum _CsmSystemError CsmSystemError; struct _CsmSystemInterface { GTypeInterface base_interface; void (* request_completed) (CsmSystem *system, GError *error); gboolean (* can_switch_user) (CsmSystem *system); gboolean (* can_stop) (CsmSystem *system); gboolean (* can_restart) (CsmSystem *system); gboolean (* can_hybrid_sleep) (CsmSystem *system); gboolean (* can_suspend) (CsmSystem *system); gboolean (* can_hibernate) (CsmSystem *system); void (* attempt_stop) (CsmSystem *system); void (* attempt_restart) (CsmSystem *system); void (* hybrid_sleep) (CsmSystem *system); void (* suspend) (CsmSystem *system); void (* hibernate) (CsmSystem *system); void (* set_session_idle) (CsmSystem *system, gboolean is_idle); gboolean (* is_login_session) (CsmSystem *system); void (* add_inhibitor) (CsmSystem *system, const gchar *id, CsmInhibitorFlag flags); void (* remove_inhibitor) (CsmSystem *system, const gchar *id); gboolean (* is_last_session_for_user) (CsmSystem *system); }; enum _CsmSystemError { CSM_SYSTEM_ERROR_RESTARTING = 0, CSM_SYSTEM_ERROR_STOPPING }; GType csm_system_get_type (void); GQuark csm_system_error_quark (void); CsmSystem *csm_get_system (void); gboolean csm_system_can_switch_user (CsmSystem *system); gboolean csm_system_can_stop (CsmSystem *system); gboolean csm_system_can_restart (CsmSystem *system); gboolean csm_system_can_hybrid_sleep (CsmSystem *system); gboolean csm_system_can_suspend (CsmSystem *system); gboolean csm_system_can_hibernate (CsmSystem *system); void csm_system_attempt_stop (CsmSystem *system); void csm_system_attempt_restart (CsmSystem *system); void csm_system_hybrid_sleep (CsmSystem *system); void csm_system_suspend (CsmSystem *system); void csm_system_hibernate (CsmSystem *system); void csm_system_set_session_idle (CsmSystem *system, gboolean is_idle); gboolean csm_system_is_login_session (CsmSystem *system); gboolean csm_system_is_last_session_for_user (CsmSystem *system); void csm_system_add_inhibitor (CsmSystem *system, const gchar *id, CsmInhibitorFlag flags); void csm_system_remove_inhibitor (CsmSystem *system, const gchar *id); G_END_DECLS #endif /* __CSM_SYSTEM_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-systemd.c0000644000175000017500000005600313205266677021443 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2011 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Author: Matthias Clasen */ #include "config.h" #include "csm-systemd.h" #ifdef HAVE_LOGIND #include #include #include #include #include #include #include #include #include #include #include #include #include "csm-marshal.h" #include "csm-system.h" #define SD_NAME "org.freedesktop.login1" #define SD_PATH "/org/freedesktop/login1" #define SD_INTERFACE "org.freedesktop.login1.Manager" #define SD_SEAT_INTERFACE "org.freedesktop.login1.Seat" #define SD_SESSION_INTERFACE "org.freedesktop.login1.Session" struct _CsmSystemdPrivate { GDBusProxy *sd_proxy; char *session_id; gchar *session_path; GSList *inhibitors; gint inhibit_fd; }; static void csm_systemd_system_init (CsmSystemInterface *iface); G_DEFINE_TYPE_WITH_CODE (CsmSystemd, csm_systemd, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (CSM_TYPE_SYSTEM, csm_systemd_system_init)) static void drop_system_inhibitor (CsmSystemd *manager) { if (manager->priv->inhibit_fd != -1) { g_debug ("Dropping system inhibitor"); close (manager->priv->inhibit_fd); manager->priv->inhibit_fd = -1; } } static void csm_systemd_finalize (GObject *object) { CsmSystemd *systemd = CSM_SYSTEMD (object); g_clear_object (&systemd->priv->sd_proxy); free (systemd->priv->session_id); g_free (systemd->priv->session_path); if (systemd->priv->inhibitors != NULL) { g_slist_free_full (systemd->priv->inhibitors, g_free); } drop_system_inhibitor (systemd); G_OBJECT_CLASS (csm_systemd_parent_class)->finalize (object); } static void csm_systemd_class_init (CsmSystemdClass *manager_class) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (manager_class); object_class->finalize = csm_systemd_finalize; g_type_class_add_private (manager_class, sizeof (CsmSystemdPrivate)); } static void csm_systemd_init (CsmSystemd *manager) { GError *error; GDBusConnection *bus; GVariant *res; manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, CSM_TYPE_SYSTEMD, CsmSystemdPrivate); manager->priv->inhibit_fd = -1; error = NULL; bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (bus == NULL) { g_warning ("Failed to connect to system bus: %s", error->message); g_error_free (error); } else { manager->priv->sd_proxy = g_dbus_proxy_new_sync (bus, 0, NULL, SD_NAME, SD_PATH, SD_INTERFACE, NULL, &error); if (manager->priv->sd_proxy == NULL) { g_warning ("Failed to connect to systemd: %s", error->message); g_error_free (error); } g_object_unref (bus); } sd_pid_get_session (getpid (), &manager->priv->session_id); if (manager->priv->session_id == NULL) { g_warning ("Could not get session id for session. Check that logind is " "properly installed and pam_systemd is getting used at login."); return; } res = g_dbus_proxy_call_sync (manager->priv->sd_proxy, "GetSession", g_variant_new ("(s)", manager->priv->session_id), 0, G_MAXINT, NULL, NULL); if (res == NULL) { g_warning ("Could not get session id for session. Check that logind is " "properly installed and pam_systemd is getting used at login."); return; } g_variant_get (res, "(o)", &manager->priv->session_path); g_variant_unref (res); } static void restart_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); CsmSystemd *manager = user_data; GError *error = NULL; GVariant *res; res = g_dbus_proxy_call_finish (proxy, result, &error); if (!res) { g_warning ("Unable to restart system via systemd: %s", error->message); g_signal_emit_by_name (G_OBJECT (manager), "request-failed", NULL); g_error_free (error); } else { g_variant_unref (res); } } static void csm_systemd_attempt_restart (CsmSystem *system) { g_warning ("Attempting to restart using systemd..."); CsmSystemd *manager = CSM_SYSTEMD (system); g_dbus_proxy_call (manager->priv->sd_proxy, "Reboot", g_variant_new ("(b)", TRUE), 0, G_MAXINT, NULL, restart_done, manager); } static void stop_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); CsmSystemd *manager = user_data; GError *error = NULL; GVariant *res; res = g_dbus_proxy_call_finish (proxy, result, &error); if (!res) { g_warning ("Unable to stop system via systemd: %s", error->message); g_signal_emit_by_name (G_OBJECT (manager), "request-failed", NULL); g_error_free (error); } else { g_variant_unref (res); } } static void csm_systemd_attempt_stop (CsmSystem *system) { g_warning ("Attempting to shutdown using systemd..."); CsmSystemd *manager = CSM_SYSTEMD (system); g_dbus_proxy_call (manager->priv->sd_proxy, "PowerOff", g_variant_new ("(b)", TRUE), 0, G_MAXINT, NULL, stop_done, manager); } static void csm_systemd_set_session_idle (CsmSystem *system, gboolean is_idle) { CsmSystemd *manager = CSM_SYSTEMD (system); GDBusConnection *bus; g_debug ("Updating systemd idle status: %d", is_idle); bus = g_dbus_proxy_get_connection (manager->priv->sd_proxy); g_dbus_connection_call (bus, SD_NAME, manager->priv->session_path, SD_SESSION_INTERFACE, "SetIdleHint", g_variant_new ("(b)", is_idle), G_VARIANT_TYPE_BOOLEAN, 0, G_MAXINT, NULL, NULL, NULL); } static gboolean csm_systemd_can_switch_user (CsmSystem *system) { CsmSystemd *manager = CSM_SYSTEMD (system); gchar *seat; gint ret; sd_session_get_seat (manager->priv->session_id, &seat); ret = sd_seat_can_multi_session (seat); free (seat); return ret > 0; } static gboolean csm_systemd_can_restart (CsmSystem *system) { CsmSystemd *manager = CSM_SYSTEMD (system); gchar *rv; GVariant *res; gboolean can_restart; res = g_dbus_proxy_call_sync (manager->priv->sd_proxy, "CanReboot", NULL, 0, G_MAXINT, NULL, NULL); if (!res) { g_warning ("Calling CanReboot failed. Check that logind is " "properly installed and pam_systemd is getting used at login."); return FALSE; } g_variant_get (res, "(s)", &rv); g_variant_unref (res); can_restart = g_strcmp0 (rv, "yes") == 0 || g_strcmp0 (rv, "challenge") == 0; g_free (rv); return can_restart; } static gboolean csm_systemd_can_stop (CsmSystem *system) { CsmSystemd *manager = CSM_SYSTEMD (system); gchar *rv; GVariant *res; gboolean can_stop; res = g_dbus_proxy_call_sync (manager->priv->sd_proxy, "CanPowerOff", NULL, 0, G_MAXINT, NULL, NULL); if (!res) { g_warning ("Calling CanPowerOff failed. Check that logind is " "properly installed and pam_systemd is getting used at login."); return FALSE; } g_variant_get (res, "(s)", &rv); g_variant_unref (res); can_stop = g_strcmp0 (rv, "yes") == 0 || g_strcmp0 (rv, "challenge") == 0; g_free (rv); return can_stop; } static gboolean csm_systemd_is_login_session (CsmSystem *system) { CsmSystemd *manager = CSM_SYSTEMD (system); int res; gboolean ret; gchar *session_class = NULL; ret = FALSE; if (manager->priv->session_id == NULL) { return ret; } res = sd_session_get_class (manager->priv->session_id, &session_class); if (res < 0) { g_warning ("could not get session class: %s", strerror (-res)); return FALSE; } ret = (g_strcmp0 (session_class, "greeter") == 0); free (session_class); return ret; } static gboolean csm_systemd_can_hybrid_sleep (CsmSystem *system) { CsmSystemd *manager = CSM_SYSTEMD (system); gchar *rv; GVariant *res; gboolean can_hybrid_sleep; res = g_dbus_proxy_call_sync (manager->priv->sd_proxy, "CanHybridSleep", NULL, 0, G_MAXINT, NULL, NULL); if (!res) { g_warning ("Calling CanHybridSleep failed. Check that logind is " "properly installed and pam_systemd is getting used at login."); return FALSE; } g_variant_get (res, "(s)", &rv); g_variant_unref (res); can_hybrid_sleep = g_strcmp0 (rv, "yes") == 0 || g_strcmp0 (rv, "challenge") == 0; g_free (rv); return can_hybrid_sleep; } static gboolean csm_systemd_can_suspend (CsmSystem *system) { CsmSystemd *manager = CSM_SYSTEMD (system); gchar *rv; GVariant *res; gboolean can_suspend; res = g_dbus_proxy_call_sync (manager->priv->sd_proxy, "CanSuspend", NULL, 0, G_MAXINT, NULL, NULL); if (!res) { g_warning ("Calling CanSuspend failed. Check that logind is " "properly installed and pam_systemd is getting used at login."); return FALSE; } g_variant_get (res, "(s)", &rv); g_variant_unref (res); can_suspend = g_strcmp0 (rv, "yes") == 0 || g_strcmp0 (rv, "challenge") == 0; g_free (rv); return can_suspend; } static gboolean csm_systemd_can_hibernate (CsmSystem *system) { CsmSystemd *manager = CSM_SYSTEMD (system); gchar *rv; GVariant *res; gboolean can_hibernate; res = g_dbus_proxy_call_sync (manager->priv->sd_proxy, "CanHibernate", NULL, 0, G_MAXINT, NULL, NULL); if (!res) { g_warning ("Calling CanHibernate failed. Check that logind is " "properly installed and pam_systemd is getting used at login."); return FALSE; } g_variant_get (res, "(s)", &rv); g_variant_unref (res); can_hibernate = g_strcmp0 (rv, "yes") == 0 || g_strcmp0 (rv, "challenge") == 0; g_free (rv); return can_hibernate; } static void hybrid_sleep_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); GError *error = NULL; GVariant *res; res = g_dbus_proxy_call_finish (proxy, result, &error); if (!res) { g_warning ("Unable to send system to hybrid sleep: %s", error->message); g_error_free (error); } else { g_variant_unref (res); } } static void suspend_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); GError *error = NULL; GVariant *res; res = g_dbus_proxy_call_finish (proxy, result, &error); if (!res) { g_warning ("Unable to suspend system: %s", error->message); g_error_free (error); } else { g_variant_unref (res); } } static void hibernate_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); GError *error = NULL; GVariant *res; res = g_dbus_proxy_call_finish (proxy, result, &error); if (!res) { g_warning ("Unable to hibernate system: %s", error->message); g_error_free (error); } else { g_variant_unref (res); } } static void csm_systemd_hybrid_sleep (CsmSystem *system) { CsmSystemd *manager = CSM_SYSTEMD (system); g_dbus_proxy_call (manager->priv->sd_proxy, "HybridSleep", g_variant_new ("(b)", TRUE), 0, G_MAXINT, NULL, hybrid_sleep_done, manager); } static void csm_systemd_suspend (CsmSystem *system) { CsmSystemd *manager = CSM_SYSTEMD (system); g_dbus_proxy_call (manager->priv->sd_proxy, "Suspend", g_variant_new ("(b)", TRUE), 0, G_MAXINT, NULL, hibernate_done, manager); } static void csm_systemd_hibernate (CsmSystem *system) { CsmSystemd *manager = CSM_SYSTEMD (system); g_dbus_proxy_call (manager->priv->sd_proxy, "Hibernate", g_variant_new ("(b)", TRUE), 0, G_MAXINT, NULL, suspend_done, manager); } static void inhibit_done (GObject *source, GAsyncResult *result, gpointer user_data) { GDBusProxy *proxy = G_DBUS_PROXY (source); CsmSystemd *manager = CSM_SYSTEMD (user_data); GError *error = NULL; GVariant *res; GUnixFDList *fd_list = NULL; gint idx; res = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, &fd_list, result, &error); if (!res) { g_warning ("Unable to inhibit system: %s", error->message); g_error_free (error); } else { g_variant_get (res, "(h)", &idx); manager->priv->inhibit_fd = g_unix_fd_list_get (fd_list, idx, &error); if (manager->priv->inhibit_fd == -1) { g_warning ("Failed to receive system inhibitor fd: %s", error->message); g_error_free (error); } g_debug ("System inhibitor fd is %d", manager->priv->inhibit_fd); g_object_unref (fd_list); g_variant_unref (res); } if (manager->priv->inhibitors == NULL) { drop_system_inhibitor (manager); } } static void csm_systemd_add_inhibitor (CsmSystem *system, const gchar *id, CsmInhibitorFlag flag) { CsmSystemd *manager = CSM_SYSTEMD (system); if ((flag & CSM_INHIBITOR_FLAG_SUSPEND) == 0) return; if (manager->priv->inhibitors == NULL) { g_debug ("Adding system inhibitor"); g_dbus_proxy_call_with_unix_fd_list (manager->priv->sd_proxy, "Inhibit", g_variant_new ("(ssss)", "sleep:shutdown", g_get_user_name (), "user session inhibited", "block"), 0, G_MAXINT, NULL, NULL, inhibit_done, manager); } manager->priv->inhibitors = g_slist_prepend (manager->priv->inhibitors, g_strdup (id)); } static void csm_systemd_remove_inhibitor (CsmSystem *system, const gchar *id) { CsmSystemd *manager = CSM_SYSTEMD (system); GSList *l; l = g_slist_find_custom (manager->priv->inhibitors, id, (GCompareFunc)g_strcmp0); if (l == NULL) return; g_free (l->data); manager->priv->inhibitors = g_slist_delete_link (manager->priv->inhibitors, l); if (manager->priv->inhibitors == NULL) { drop_system_inhibitor (manager); } } static gboolean csm_systemd_is_last_session_for_user (CsmSystem *system) { char **sessions = NULL; char *session = NULL; gboolean is_last_session; int ret, i; ret = sd_pid_get_session (getpid (), &session); if (ret != 0) { return FALSE; } ret = sd_uid_get_sessions (getuid (), FALSE, &sessions); if (ret <= 0) { return FALSE; } is_last_session = TRUE; for (i = 0; sessions[i]; i++) { char *state = NULL; char *type = NULL; if (g_strcmp0 (sessions[i], session) == 0) continue; ret = sd_session_get_state (sessions[i], &state); if (ret != 0) continue; if (g_strcmp0 (state, "closing") == 0) { free (state); continue; } free (state); ret = sd_session_get_type (sessions[i], &type); if (ret != 0) continue; if (g_strcmp0 (type, "x11") != 0 && g_strcmp0 (type, "wayland") != 0) { free (type); continue; } is_last_session = FALSE; } for (i = 0; sessions[i]; i++) free (sessions[i]); free (sessions); return is_last_session; } static void csm_systemd_system_init (CsmSystemInterface *iface) { iface->can_switch_user = csm_systemd_can_switch_user; iface->can_stop = csm_systemd_can_stop; iface->can_restart = csm_systemd_can_restart; iface->can_hybrid_sleep = csm_systemd_can_hybrid_sleep; iface->can_suspend = csm_systemd_can_suspend; iface->can_hibernate = csm_systemd_can_hibernate; iface->attempt_stop = csm_systemd_attempt_stop; iface->attempt_restart = csm_systemd_attempt_restart; iface->hybrid_sleep = csm_systemd_hybrid_sleep; iface->suspend = csm_systemd_suspend; iface->hibernate = csm_systemd_hibernate; iface->set_session_idle = csm_systemd_set_session_idle; iface->is_login_session = csm_systemd_is_login_session; iface->add_inhibitor = csm_systemd_add_inhibitor; iface->remove_inhibitor = csm_systemd_remove_inhibitor; iface->is_last_session_for_user = csm_systemd_is_last_session_for_user; } CsmSystemd * csm_systemd_new (void) { CsmSystemd *manager; /* logind is not running ? */ if (access("/run/systemd/seats/", F_OK) < 0) return NULL; manager = g_object_new (CSM_TYPE_SYSTEMD, NULL); return manager; } #else CsmSystemd * csm_systemd_new (void) { return NULL; } #endif cinnamon-session-3.6.1/cinnamon-session/csm-systemd.h0000644000175000017500000000375713205266677021460 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2012 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Authors: * Matthias Clasen */ #ifndef __CSM_SYSTEMD_H__ #define __CSM_SYSTEMD_H__ #include #include G_BEGIN_DECLS #define CSM_TYPE_SYSTEMD (csm_systemd_get_type ()) #define CSM_SYSTEMD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSM_TYPE_SYSTEMD, CsmSystemd)) #define CSM_SYSTEMD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSM_TYPE_SYSTEMD, CsmSystemdClass)) #define CSM_IS_SYSTEMD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSM_TYPE_SYSTEMD)) #define CSM_IS_SYSTEMD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSM_TYPE_SYSTEMD)) #define CSM_SYSTEMD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), CSM_TYPE_SYSTEMD, CsmSystemdClass)) typedef struct _CsmSystemd CsmSystemd; typedef struct _CsmSystemdClass CsmSystemdClass; typedef struct _CsmSystemdPrivate CsmSystemdPrivate; struct _CsmSystemd { GObject parent; CsmSystemdPrivate *priv; }; struct _CsmSystemdClass { GObjectClass parent_class; }; GType csm_systemd_get_type (void); CsmSystemd *csm_systemd_new (void) G_GNUC_MALLOC; G_END_DECLS #endif /* __CSM_SYSTEMD_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-util.c0000644000175000017500000006107113205266677020731 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * csm-util.c * Copyright (C) 2008 Lucas Rocha. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "csm-util.h" static gchar *_saved_session_dir = NULL; char * csm_util_find_desktop_file_for_app_name (const char *name, gboolean look_in_saved_session, gboolean autostart_first) { char *app_path; char **app_dirs; GKeyFile *key_file; char *desktop_file; int i; app_path = NULL; app_dirs = csm_util_get_desktop_dirs (look_in_saved_session, autostart_first); key_file = g_key_file_new (); desktop_file = g_strdup_printf ("%s.desktop", name); g_debug ("CsmUtil: Looking for file '%s'", desktop_file); for (i = 0; app_dirs[i] != NULL; i++) { g_debug ("CsmUtil: Looking in '%s'", app_dirs[i]); } g_key_file_load_from_dirs (key_file, desktop_file, (const char **) app_dirs, &app_path, G_KEY_FILE_NONE, NULL); if (app_path != NULL) { g_debug ("CsmUtil: found in XDG dirs: '%s'", app_path); } /* look for gnome vendor prefix */ if (app_path == NULL) { g_free (desktop_file); desktop_file = g_strdup_printf ("gnome-%s.desktop", name); g_key_file_load_from_dirs (key_file, desktop_file, (const char **) app_dirs, &app_path, G_KEY_FILE_NONE, NULL); if (app_path != NULL) { g_debug ("CsmUtil: found in XDG dirs: '%s'", app_path); } } g_free (desktop_file); g_key_file_free (key_file); g_strfreev (app_dirs); return app_path; } static gboolean ensure_dir_exists (const char *dir) { if (g_file_test (dir, G_FILE_TEST_IS_DIR)) return TRUE; if (g_mkdir_with_parents (dir, 0755) == 0) return TRUE; if (errno == EEXIST) return g_file_test (dir, G_FILE_TEST_IS_DIR); g_warning ("CsmSessionSave: Failed to create directory %s: %s", dir, strerror (errno)); return FALSE; } gchar * csm_util_get_empty_tmp_session_dir (void) { char *tmp; gboolean exists; tmp = g_build_filename (g_get_user_config_dir (), "cinnamon-session", "saved-session.new", NULL); exists = ensure_dir_exists (tmp); if (G_UNLIKELY (!exists)) { g_warning ("CsmSessionSave: could not create directory for saved session: %s", tmp); g_free (tmp); return NULL; } else { /* make sure it's empty */ GDir *dir; const char *filename; dir = g_dir_open (tmp, 0, NULL); if (dir) { while ((filename = g_dir_read_name (dir))) { gchar *path = g_build_filename (tmp, filename, NULL); g_unlink (path); g_free (path); } g_dir_close (dir); } } return tmp; } const gchar * csm_util_get_saved_session_dir (void) { if (_saved_session_dir == NULL) { gboolean exists; _saved_session_dir = g_build_filename (g_get_user_config_dir (), "cinnamon-session", "saved-session", NULL); exists = ensure_dir_exists (_saved_session_dir); if (G_UNLIKELY (!exists)) { static gboolean printed_warning = FALSE; if (!printed_warning) { g_warning ("CsmSessionSave: could not create directory for saved session: %s", _saved_session_dir); printed_warning = TRUE; } _saved_session_dir = NULL; return NULL; } } return _saved_session_dir; } static char ** autostart_dirs; void csm_util_set_autostart_dirs (char ** dirs) { autostart_dirs = g_strdupv (dirs); } static char ** csm_util_get_standard_autostart_dirs () { GPtrArray *dirs; const char * const *system_config_dirs; const char * const *system_data_dirs; int i; dirs = g_ptr_array_new (); g_ptr_array_add (dirs, g_build_filename (g_get_user_config_dir (), "autostart", NULL)); system_data_dirs = g_get_system_data_dirs (); for (i = 0; system_data_dirs[i]; i++) { g_ptr_array_add (dirs, g_build_filename (system_data_dirs[i], "gnome", "autostart", NULL)); } system_config_dirs = g_get_system_config_dirs (); for (i = 0; system_config_dirs[i]; i++) { g_ptr_array_add (dirs, g_build_filename (system_config_dirs[i], "autostart", NULL)); } g_ptr_array_add (dirs, NULL); return (char **) g_ptr_array_free (dirs, FALSE); } char ** csm_util_get_autostart_dirs () { if (autostart_dirs) { return g_strdupv ((char **)autostart_dirs); } return csm_util_get_standard_autostart_dirs (); } char ** csm_util_get_app_dirs () { GPtrArray *dirs; const char * const *system_data_dirs; int i; dirs = g_ptr_array_new (); g_ptr_array_add (dirs, g_build_filename (g_get_user_data_dir (), "applications", NULL)); system_data_dirs = g_get_system_data_dirs (); for (i = 0; system_data_dirs[i]; i++) { g_ptr_array_add (dirs, g_build_filename (system_data_dirs[i], "applications", NULL)); } g_ptr_array_add (dirs, NULL); return (char **) g_ptr_array_free (dirs, FALSE); } char ** csm_util_get_desktop_dirs (gboolean include_saved_session, gboolean autostart_first) { char **apps; char **autostart; char **standard_autostart; char **result; int size; int i; apps = csm_util_get_app_dirs (); autostart = csm_util_get_autostart_dirs (); /* Still, check the standard autostart dirs for things like fulfilling session reqs, * if using a non-standard autostart dir for autostarting */ if (autostart_dirs != NULL) standard_autostart = csm_util_get_standard_autostart_dirs (); else standard_autostart = NULL; size = 0; for (i = 0; apps[i] != NULL; i++) { size++; } for (i = 0; autostart[i] != NULL; i++) { size++; } if (autostart_dirs != NULL) for (i = 0; standard_autostart[i] != NULL; i++) { size++; } if (include_saved_session) size += 1; result = g_new (char *, size + 1); /* including last NULL */ size = 0; if (autostart_first) { if (include_saved_session) result[size++] = g_strdup (csm_util_get_saved_session_dir ()); for (i = 0; autostart[i] != NULL; i++, size++) { result[size] = autostart[i]; } if (standard_autostart != NULL) { for (i = 0; standard_autostart[i] != NULL; i++, size++) { result[size] = standard_autostart[i]; } } for (i = 0; apps[i] != NULL; i++, size++) { result[size] = apps[i]; } } else { for (i = 0; apps[i] != NULL; i++, size++) { result[size] = apps[i]; } if (standard_autostart != NULL) { for (i = 0; standard_autostart[i] != NULL; i++, size++) { result[size] = standard_autostart[i]; } } for (i = 0; autostart[i] != NULL; i++, size++) { result[size] = autostart[i]; } if (include_saved_session) result[size++] = g_strdup (csm_util_get_saved_session_dir ()); } g_free (apps); g_free (autostart); g_free (standard_autostart); result[size] = NULL; return result; } const char * csm_util_get_current_desktop () { static char *current_desktop = NULL; /* Support XDG_CURRENT_DESKTOP environment variable; this can be used * to abuse cinnamon-session in non-Cinnamon desktops. */ if (!current_desktop) { const char *desktop; desktop = g_getenv ("XDG_CURRENT_DESKTOP"); /* Note: if XDG_CURRENT_DESKTOP is set but empty, do as if it * was not set */ if (!desktop || desktop[0] == '\0') current_desktop = g_strdup ("GNOME"); else current_desktop = g_strdup (desktop); } /* Using "*" means skipping desktop-related checks */ if (g_strcmp0 (current_desktop, "*") == 0) return NULL; return current_desktop; } gboolean csm_util_text_is_blank (const char *str) { if (str == NULL) { return TRUE; } while (*str) { if (!isspace(*str)) { return FALSE; } str++; } return TRUE; } /** * csm_util_init_error: * @fatal: whether or not the error is fatal to the login session * @format: printf-style error message format * @...: error message args * * Displays the error message to the user. If @fatal is %TRUE, csm * will exit after displaying the message. * * This should be called for major errors that occur before the * session is up and running. (Notably, it positions the dialog box * itself, since no window manager will be running yet.) **/ void csm_util_init_error (gboolean fatal, const char *format, ...) { GtkButtonsType buttons; GtkWidget *dialog; char *msg; va_list args; va_start (args, format); msg = g_strdup_vprintf (format, args); va_end (args); /* If option parsing failed, Gtk won't have been initialized... */ if (!gdk_display_get_default ()) { if (!gtk_init_check (NULL, NULL)) { /* Oh well, no X for you! */ g_printerr (_("Unable to start login session (and unable to connect to the X server)")); g_printerr ("%s", msg); exit (1); } } if (fatal) buttons = GTK_BUTTONS_NONE; else buttons = GTK_BUTTONS_CLOSE; dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, buttons, "%s", msg); if (fatal) gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Log Out"), GTK_RESPONSE_CLOSE); g_free (msg); gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); if (fatal) { if (gtk_main_level () > 0) gtk_main_quit (); else exit (1); } } /** * csm_util_generate_startup_id: * * Generates a new SM client ID. * * Return value: an SM client ID. **/ char * csm_util_generate_startup_id (void) { static int sequence = -1; static guint rand1 = 0; static guint rand2 = 0; static pid_t pid = 0; struct timeval tv; /* The XSMP spec defines the ID as: * * Version: "1" * Address type and address: * "1" + an IPv4 address as 8 hex digits * "2" + a DECNET address as 12 hex digits * "6" + an IPv6 address as 32 hex digits * Time stamp: milliseconds since UNIX epoch as 13 decimal digits * Process-ID type and process-ID: * "1" + POSIX PID as 10 decimal digits * Sequence number as 4 decimal digits * * XSMP client IDs are supposed to be globally unique: if * SmsGenerateClientID() is unable to determine a network * address for the machine, it gives up and returns %NULL. * GNOME and KDE have traditionally used a fourth address * format in this case: * "0" + 16 random hex digits * * We don't even bother trying SmsGenerateClientID(), since the * user's IP address is probably "192.168.1.*" anyway, so a random * number is actually more likely to be globally unique. */ if (!rand1) { rand1 = g_random_int (); rand2 = g_random_int (); pid = getpid (); } sequence = (sequence + 1) % 10000; gettimeofday (&tv, NULL); return g_strdup_printf ("10%.04x%.04x%.10lu%.3u%.10lu%.4d", rand1, rand2, (unsigned long) tv.tv_sec, (unsigned) tv.tv_usec, (unsigned long) pid, sequence); } static gboolean csm_util_update_activation_environment (const char *variable, const char *value, GError **error) { GDBusConnection *connection; gboolean environment_updated; GVariantBuilder builder; GVariant *reply; GError *bus_error = NULL; environment_updated = FALSE; connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error); if (connection == NULL) { return FALSE; } g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}")); g_variant_builder_add (&builder, "{ss}", variable, value); reply = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "UpdateActivationEnvironment", g_variant_new ("(@a{ss})", g_variant_builder_end (&builder)), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &bus_error); if (bus_error != NULL) { g_propagate_error (error, bus_error); } else { environment_updated = TRUE; g_variant_unref (reply); } g_clear_object (&connection); return environment_updated; } gboolean csm_util_export_activation_environment (GError **error) { GDBusConnection *connection; gboolean environment_updated = FALSE; char **entry_names; int i = 0; GVariantBuilder builder; GRegex *name_regex, *value_regex; GVariant *reply; GError *bus_error = NULL; connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error); if (connection == NULL) { return FALSE; } name_regex = g_regex_new ("^[a-zA-Z_][a-zA-Z0-9_]*$", G_REGEX_OPTIMIZE, 0, error); if (name_regex == NULL) { return FALSE; } value_regex = g_regex_new ("^([[:blank:]]|[^[:cntrl:]])*$", G_REGEX_OPTIMIZE, 0, error); if (value_regex == NULL) { return FALSE; } g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}")); for (entry_names = g_listenv (); entry_names[i] != NULL; i++) { const char *entry_name = entry_names[i]; const char *entry_value = g_getenv (entry_name); if (!g_utf8_validate (entry_name, -1, NULL)) continue; if (!g_regex_match (name_regex, entry_name, 0, NULL)) continue; if (!g_utf8_validate (entry_value, -1, NULL)) continue; if (!g_regex_match (value_regex, entry_value, 0, NULL)) continue; g_variant_builder_add (&builder, "{ss}", entry_name, entry_value); } g_regex_unref (name_regex); g_regex_unref (value_regex); g_strfreev (entry_names); reply = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "UpdateActivationEnvironment", g_variant_new ("(@a{ss})", g_variant_builder_end (&builder)), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &bus_error); if (bus_error != NULL) { g_propagate_error (error, bus_error); } else { environment_updated = TRUE; g_variant_unref (reply); } g_clear_object (&connection); return environment_updated; } gboolean csm_util_export_user_environment (GError **error) { GDBusConnection *connection; gboolean environment_updated = FALSE; char **entries; int i = 0; GVariantBuilder builder; GRegex *regex; GVariant *reply; GError *bus_error = NULL; connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error); if (connection == NULL) { return FALSE; } regex = g_regex_new ("^[a-zA-Z_][a-zA-Z0-9_]*=([[:blank:]]|[^[:cntrl:]])*$", G_REGEX_OPTIMIZE, 0, error); if (regex == NULL) { return FALSE; } g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); for (entries = g_get_environ (); entries[i] != NULL; i++) { const char *entry = entries[i]; if (!g_utf8_validate (entry, -1, NULL)) continue; if (!g_regex_match (regex, entry, 0, NULL)) continue; g_variant_builder_add (&builder, "s", entry); } g_regex_unref (regex); g_strfreev (entries); reply = g_dbus_connection_call_sync (connection, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "SetEnvironment", g_variant_new ("(@as)", g_variant_builder_end (&builder)), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &bus_error); if (bus_error != NULL) { g_propagate_error (error, bus_error); } else { environment_updated = TRUE; g_variant_unref (reply); } g_clear_object (&connection); return environment_updated; } static gboolean csm_util_update_user_environment (const char *variable, const char *value, GError **error) { GDBusConnection *connection; gboolean environment_updated; char *entry; GVariantBuilder builder; GVariant *reply; GError *bus_error = NULL; environment_updated = FALSE; connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error); if (connection == NULL) { return FALSE; } g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); entry = g_strdup_printf ("%s=%s", variable, value); g_variant_builder_add (&builder, "s", entry); g_free (entry); reply = g_dbus_connection_call_sync (connection, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "SetEnvironment", g_variant_new ("(@as)", g_variant_builder_end (&builder)), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &bus_error); if (bus_error != NULL) { g_propagate_error (error, bus_error); } else { environment_updated = TRUE; g_variant_unref (reply); } g_clear_object (&connection); return environment_updated; } void csm_util_setenv (const char *variable, const char *value) { GError *error = NULL; g_setenv (variable, value, TRUE); /* If this fails it isn't fatal, it means some things like session * management and keyring won't work in activated clients. */ if (!csm_util_update_activation_environment (variable, value, &error)) { g_warning ("Could not make bus activated clients aware of %s=%s environment variable: %s", variable, value, error->message); g_clear_error (&error); } /* If this fails, the system user session won't get the updated environment */ if (!csm_util_update_user_environment (variable, value, &error)) { g_debug ("Could not make systemd aware of %s=%s environment variable: %s", variable, value, error->message); g_clear_error (&error); } } GtkIconSize csm_util_get_computer_fail_icon_size (void) { static GtkIconSize icon_size = 0; if (icon_size == 0) icon_size = gtk_icon_size_register ("cinnamon-session-computer-fail", 128, 128); return icon_size; } cinnamon-session-3.6.1/cinnamon-session/csm-util.h0000644000175000017500000000455213205266677020737 0ustar maxymaxy/* csm-util.h * Copyright (C) 2008 Lucas Rocha. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_UTIL_H__ #define __CSM_UTIL_H__ #include #include G_BEGIN_DECLS #define IS_STRING_EMPTY(x) ((x)==NULL||(x)[0]=='\0') char * csm_util_find_desktop_file_for_app_name (const char *app_name, gboolean look_in_saved_session, gboolean autostart_first); gchar *csm_util_get_empty_tmp_session_dir (void); const char *csm_util_get_saved_session_dir (void); gchar** csm_util_get_app_dirs (void); gchar** csm_util_get_autostart_dirs (void); void csm_util_set_autostart_dirs (char **dirs); gchar ** csm_util_get_desktop_dirs (gboolean include_saved_session, gboolean autostart_first); const char *csm_util_get_current_desktop (void); gboolean csm_util_text_is_blank (const char *str); void csm_util_init_error (gboolean fatal, const char *format, ...); char * csm_util_generate_startup_id (void); gboolean csm_util_export_activation_environment (GError **error); gboolean csm_util_export_user_environment (GError **error); void csm_util_setenv (const char *variable, const char *value); GtkIconSize csm_util_get_computer_fail_icon_size (void); G_END_DECLS #endif /* __CSM_UTIL_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-xsmp-client.c0000644000175000017500000013116413205266677022220 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Novell, Inc. * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include "config.h" #include #include #include #include #include #include #include #include #include "csm-xsmp-client.h" #include "csm-marshal.h" #include "csm-util.h" #include "csm-autostart-app.h" #include "csm-icon-names.h" #include "csm-manager.h" #define CsmDesktopFile "_CSM_DesktopFile" #define CSM_XSMP_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_XSMP_CLIENT, CsmXSMPClientPrivate)) struct CsmXSMPClientPrivate { SmsConn conn; IceConn ice_connection; guint watch_id; char *description; GPtrArray *props; /* SaveYourself state */ int current_save_yourself; int next_save_yourself; guint next_save_yourself_allow_interact : 1; }; enum { PROP_0, PROP_ICE_CONNECTION }; enum { REGISTER_REQUEST, LOGOUT_REQUEST, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (CsmXSMPClient, csm_xsmp_client, CSM_TYPE_CLIENT) static gboolean client_iochannel_watch (GIOChannel *channel, GIOCondition condition, CsmXSMPClient *client) { gboolean keep_going; g_object_ref (client); switch (IceProcessMessages (client->priv->ice_connection, NULL, NULL)) { case IceProcessMessagesSuccess: keep_going = TRUE; break; case IceProcessMessagesIOError: g_debug ("CsmXSMPClient: IceProcessMessagesIOError on '%s'", client->priv->description); csm_client_set_status (CSM_CLIENT (client), CSM_CLIENT_FAILED); /* Emitting "disconnected" will eventually cause * IceCloseConnection() to be called. */ csm_client_disconnected (CSM_CLIENT (client)); keep_going = FALSE; break; case IceProcessMessagesConnectionClosed: g_debug ("CsmXSMPClient: IceProcessMessagesConnectionClosed on '%s'", client->priv->description); client->priv->ice_connection = NULL; keep_going = FALSE; break; default: g_assert_not_reached (); } g_object_unref (client); return keep_going; } static SmProp * find_property (CsmXSMPClient *client, const char *name, int *index) { SmProp *prop; int i; for (i = 0; i < client->priv->props->len; i++) { prop = client->priv->props->pdata[i]; if (!strcmp (prop->name, name)) { if (index) { *index = i; } return prop; } } return NULL; } static void set_description (CsmXSMPClient *client) { SmProp *prop; const char *id; prop = find_property (client, SmProgram, NULL); id = csm_client_peek_startup_id (CSM_CLIENT (client)); g_free (client->priv->description); if (prop) { client->priv->description = g_strdup_printf ("%p [%.*s %s]", client, prop->vals[0].length, (char *)prop->vals[0].value, id); } else if (id != NULL) { client->priv->description = g_strdup_printf ("%p [%s]", client, id); } else { client->priv->description = g_strdup_printf ("%p", client); } } static void setup_connection (CsmXSMPClient *client) { GIOChannel *channel; int fd; g_debug ("CsmXSMPClient: Setting up new connection"); fd = IceConnectionNumber (client->priv->ice_connection); fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC); channel = g_io_channel_unix_new (fd); client->priv->watch_id = g_io_add_watch (channel, G_IO_IN | G_IO_ERR, (GIOFunc)client_iochannel_watch, client); g_io_channel_unref (channel); set_description (client); g_debug ("CsmXSMPClient: New client '%s'", client->priv->description); } static GObject * csm_xsmp_client_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsmXSMPClient *client; client = CSM_XSMP_CLIENT (G_OBJECT_CLASS (csm_xsmp_client_parent_class)->constructor (type, n_construct_properties, construct_properties)); setup_connection (client); return G_OBJECT (client); } static void csm_xsmp_client_init (CsmXSMPClient *client) { client->priv = CSM_XSMP_CLIENT_GET_PRIVATE (client); client->priv->props = g_ptr_array_new (); client->priv->current_save_yourself = -1; client->priv->next_save_yourself = -1; client->priv->next_save_yourself_allow_interact = FALSE; } static void delete_property (CsmXSMPClient *client, const char *name) { int index; SmProp *prop; prop = find_property (client, name, &index); if (!prop) { return; } #if 0 /* This is wrong anyway; we can't unconditionally run the current * discard command; if this client corresponds to a CsmAppResumed, * and the current discard command is identical to the app's * discard_command, then we don't run the discard command now, * because that would delete a saved state we may want to resume * again later. */ if (!strcmp (name, SmDiscardCommand)) { csm_client_run_discard (CSM_CLIENT (client)); } #endif g_ptr_array_remove_index_fast (client->priv->props, index); SmFreeProperty (prop); } static void debug_print_property (SmProp *prop) { GString *tmp; int i; switch (prop->type[0]) { case 'C': /* CARD8 */ g_debug ("CsmXSMPClient: %s = %d", prop->name, *(unsigned char *)prop->vals[0].value); break; case 'A': /* ARRAY8 */ g_debug ("CsmXSMPClient: %s = '%s'", prop->name, (char *)prop->vals[0].value); break; case 'L': /* LISTofARRAY8 */ tmp = g_string_new (NULL); for (i = 0; i < prop->num_vals; i++) { g_string_append_printf (tmp, "'%.*s' ", prop->vals[i].length, (char *)prop->vals[i].value); } g_debug ("CsmXSMPClient: %s = %s", prop->name, tmp->str); g_string_free (tmp, TRUE); break; default: g_debug ("CsmXSMPClient: %s = ??? (%s)", prop->name, prop->type); break; } } static void set_properties_callback (SmsConn conn, SmPointer manager_data, int num_props, SmProp **props) { CsmXSMPClient *client = manager_data; int i; g_debug ("CsmXSMPClient: Set properties from client '%s'", client->priv->description); for (i = 0; i < num_props; i++) { delete_property (client, props[i]->name); g_ptr_array_add (client->priv->props, props[i]); debug_print_property (props[i]); if (!strcmp (props[i]->name, SmProgram)) set_description (client); } free (props); } static void delete_properties_callback (SmsConn conn, SmPointer manager_data, int num_props, char **prop_names) { CsmXSMPClient *client = manager_data; int i; g_debug ("CsmXSMPClient: Delete properties from '%s'", client->priv->description); for (i = 0; i < num_props; i++) { delete_property (client, prop_names[i]); g_debug (" %s", prop_names[i]); } free (prop_names); } static void get_properties_callback (SmsConn conn, SmPointer manager_data) { CsmXSMPClient *client = manager_data; g_debug ("CsmXSMPClient: Get properties request from '%s'", client->priv->description); SmsReturnProperties (conn, client->priv->props->len, (SmProp **)client->priv->props->pdata); } static char * prop_to_command (SmProp *prop) { GString *str; int i, j; gboolean need_quotes; str = g_string_new (NULL); for (i = 0; i < prop->num_vals; i++) { char *val = prop->vals[i].value; need_quotes = FALSE; for (j = 0; j < prop->vals[i].length; j++) { if (!g_ascii_isalnum (val[j]) && !strchr ("-_=:./", val[j])) { need_quotes = TRUE; break; } } if (i > 0) { g_string_append_c (str, ' '); } if (!need_quotes) { g_string_append_printf (str, "%.*s", prop->vals[i].length, (char *)prop->vals[i].value); } else { g_string_append_c (str, '\''); while (val < (char *)prop->vals[i].value + prop->vals[i].length) { if (*val == '\'') { g_string_append (str, "'\''"); } else { g_string_append_c (str, *val); } val++; } g_string_append_c (str, '\''); } } return g_string_free (str, FALSE); } static char * xsmp_get_restart_command (CsmClient *client) { SmProp *prop; prop = find_property (CSM_XSMP_CLIENT (client), SmRestartCommand, NULL); if (!prop || strcmp (prop->type, SmLISTofARRAY8) != 0) { return NULL; } return prop_to_command (prop); } static char * xsmp_get_discard_command (CsmClient *client) { SmProp *prop; prop = find_property (CSM_XSMP_CLIENT (client), SmDiscardCommand, NULL); if (!prop || strcmp (prop->type, SmLISTofARRAY8) != 0) { return NULL; } return prop_to_command (prop); } static void do_save_yourself (CsmXSMPClient *client, int save_type, gboolean allow_interact) { g_assert (client->priv->conn != NULL); if (client->priv->next_save_yourself != -1) { /* Either we're currently doing a shutdown and there's a checkpoint * queued after it, or vice versa. Either way, the new SaveYourself * is redundant. */ g_debug ("CsmXSMPClient: skipping redundant SaveYourself for '%s'", client->priv->description); } else if (client->priv->current_save_yourself != -1) { g_debug ("CsmXSMPClient: queuing new SaveYourself for '%s'", client->priv->description); client->priv->next_save_yourself = save_type; client->priv->next_save_yourself_allow_interact = allow_interact; } else { client->priv->current_save_yourself = save_type; /* make sure we don't have anything queued */ client->priv->next_save_yourself = -1; client->priv->next_save_yourself_allow_interact = FALSE; switch (save_type) { case SmSaveLocal: /* Save state */ SmsSaveYourself (client->priv->conn, SmSaveLocal, FALSE, SmInteractStyleNone, FALSE); break; default: /* Logout */ if (!allow_interact) { SmsSaveYourself (client->priv->conn, save_type, /* save type */ TRUE, /* shutdown */ SmInteractStyleNone, /* interact style */ TRUE); /* fast */ } else { SmsSaveYourself (client->priv->conn, save_type, /* save type */ TRUE, /* shutdown */ SmInteractStyleAny, /* interact style */ FALSE /* fast */); } break; } } } static void xsmp_save_yourself_phase2 (CsmClient *client) { CsmXSMPClient *xsmp = (CsmXSMPClient *) client; g_debug ("CsmXSMPClient: xsmp_save_yourself_phase2 ('%s')", xsmp->priv->description); SmsSaveYourselfPhase2 (xsmp->priv->conn); } static void xsmp_interact (CsmClient *client) { CsmXSMPClient *xsmp = (CsmXSMPClient *) client; g_debug ("CsmXSMPClient: xsmp_interact ('%s')", xsmp->priv->description); SmsInteract (xsmp->priv->conn); } static gboolean xsmp_cancel_end_session (CsmClient *client, GError **error) { CsmXSMPClient *xsmp = (CsmXSMPClient *) client; g_debug ("CsmXSMPClient: xsmp_cancel_end_session ('%s')", xsmp->priv->description); if (xsmp->priv->conn == NULL) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Client is not registered"); return FALSE; } SmsShutdownCancelled (xsmp->priv->conn); /* reset the state */ xsmp->priv->current_save_yourself = -1; xsmp->priv->next_save_yourself = -1; xsmp->priv->next_save_yourself_allow_interact = FALSE; return TRUE; } static char * get_desktop_file_path (CsmXSMPClient *client) { SmProp *prop; char *desktop_file_path = NULL; const char *program_name; /* XSMP clients using egcsmclient defines a special property * pointing to their respective desktop entry file */ prop = find_property (client, CsmDesktopFile, NULL); if (prop) { GFile *file = g_file_new_for_uri (prop->vals[0].value); desktop_file_path = g_file_get_path (file); g_object_unref (file); goto out; } /* If we can't get desktop file from CsmDesktopFile then we * try to find the desktop file from its program name */ prop = find_property (client, SmProgram, NULL); if (!prop) { goto out; } program_name = prop->vals[0].value; desktop_file_path = csm_util_find_desktop_file_for_app_name (program_name, TRUE, FALSE); out: g_debug ("CsmXSMPClient: desktop file for client %s is %s", csm_client_peek_id (CSM_CLIENT (client)), desktop_file_path ? desktop_file_path : "(null)"); return desktop_file_path; } static void set_desktop_file_keys_from_client (CsmClient *client, GKeyFile *keyfile) { SmProp *prop; const char *name; char *comment; prop = find_property (CSM_XSMP_CLIENT (client), SmProgram, NULL); if (prop) { name = prop->vals[0].value; } else { /* It'd be really surprising to reach this code: if we're here, * then the XSMP client already has set several XSMP * properties. But it could still be that SmProgram is not set. */ name = _("Remembered Application"); } comment = g_strdup_printf ("Client %s which was automatically saved", csm_client_peek_startup_id (client)); g_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, name); g_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, comment); g_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, CSM_ICON_XSMP_DEFAULT); g_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"); g_key_file_set_boolean (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, TRUE); g_free (comment); } static GKeyFile * create_client_key_file (CsmClient *client, const char *desktop_file_path, GError **error) { GKeyFile *keyfile; keyfile = g_key_file_new (); if (desktop_file_path != NULL) { g_key_file_load_from_file (keyfile, desktop_file_path, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, error); } else { set_desktop_file_keys_from_client (client, keyfile); } return keyfile; } static CsmClientRestartStyle xsmp_get_restart_style_hint (CsmClient *client); static GKeyFile * xsmp_save (CsmClient *client, GError **error) { CsmClientRestartStyle restart_style; GKeyFile *keyfile = NULL; char *desktop_file_path = NULL; char *exec_program = NULL; char *exec_discard = NULL; char *startup_id = NULL; GError *local_error; g_debug ("CsmXSMPClient: saving client with id %s", csm_client_peek_id (client)); local_error = NULL; restart_style = xsmp_get_restart_style_hint (client); if (restart_style == CSM_CLIENT_RESTART_NEVER) { goto out; } exec_program = xsmp_get_restart_command (client); if (!exec_program) { goto out; } desktop_file_path = get_desktop_file_path (CSM_XSMP_CLIENT (client)); /* this can accept desktop_file_path == NULL */ keyfile = create_client_key_file (client, desktop_file_path, &local_error); if (local_error) { goto out; } g_object_get (client, "startup-id", &startup_id, NULL); g_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, CSM_AUTOSTART_APP_STARTUP_ID_KEY, startup_id); g_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, exec_program); exec_discard = xsmp_get_discard_command (client); if (exec_discard) g_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, CSM_AUTOSTART_APP_DISCARD_KEY, exec_discard); out: g_free (desktop_file_path); g_free (exec_program); g_free (exec_discard); g_free (startup_id); if (local_error != NULL) { g_propagate_error (error, local_error); g_key_file_free (keyfile); return NULL; } return keyfile; } static gboolean xsmp_stop (CsmClient *client, GError **error) { CsmXSMPClient *xsmp = (CsmXSMPClient *) client; g_debug ("CsmXSMPClient: xsmp_stop ('%s')", xsmp->priv->description); if (xsmp->priv->conn == NULL) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Client is not registered"); return FALSE; } SmsDie (xsmp->priv->conn); return TRUE; } static gboolean xsmp_query_end_session (CsmClient *client, guint flags, GError **error) { gboolean allow_interact; int save_type; if (CSM_XSMP_CLIENT (client)->priv->conn == NULL) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Client is not registered"); return FALSE; } allow_interact = !(flags & CSM_CLIENT_END_SESSION_FLAG_FORCEFUL); /* we don't want to save the session state, but we just want to know if * there's user data the client has to save and we want to give the * client a chance to tell the user about it. This is consistent with * the manager not setting CSM_CLIENT_END_SESSION_FLAG_SAVE for this * phase. */ save_type = SmSaveGlobal; do_save_yourself (CSM_XSMP_CLIENT (client), save_type, allow_interact); return TRUE; } static gboolean xsmp_end_session (CsmClient *client, guint flags, GError **error) { gboolean phase2; if (CSM_XSMP_CLIENT (client)->priv->conn == NULL) { g_set_error (error, CSM_CLIENT_ERROR, CSM_CLIENT_ERROR_NOT_REGISTERED, "Client is not registered"); return FALSE; } phase2 = (flags & CSM_CLIENT_END_SESSION_FLAG_LAST); if (phase2) { xsmp_save_yourself_phase2 (client); } else { gboolean allow_interact; int save_type; /* we gave a chance to interact to the app during * xsmp_query_end_session(), now it's too late to interact */ allow_interact = FALSE; if (flags & CSM_CLIENT_END_SESSION_FLAG_SAVE) { save_type = SmSaveBoth; } else { save_type = SmSaveGlobal; } do_save_yourself (CSM_XSMP_CLIENT (client), save_type, allow_interact); } return TRUE; } static char * xsmp_get_app_name (CsmClient *client) { SmProp *prop; char *name = NULL; prop = find_property (CSM_XSMP_CLIENT (client), SmProgram, NULL); if (prop) { name = prop_to_command (prop); } return name; } static void csm_client_set_ice_connection (CsmXSMPClient *client, gpointer conn) { client->priv->ice_connection = conn; } static void csm_xsmp_client_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsmXSMPClient *self; self = CSM_XSMP_CLIENT (object); switch (prop_id) { case PROP_ICE_CONNECTION: csm_client_set_ice_connection (self, g_value_get_pointer (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_xsmp_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsmXSMPClient *self; self = CSM_XSMP_CLIENT (object); switch (prop_id) { case PROP_ICE_CONNECTION: g_value_set_pointer (value, self->priv->ice_connection); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_xsmp_client_disconnect (CsmXSMPClient *client) { if (client->priv->watch_id > 0) { g_source_remove (client->priv->watch_id); client->priv->watch_id = 0; } if (client->priv->conn != NULL) { SmsCleanUp (client->priv->conn); } if (client->priv->ice_connection != NULL) { IceSetShutdownNegotiation (client->priv->ice_connection, FALSE); IceCloseConnection (client->priv->ice_connection); } } static void csm_xsmp_client_finalize (GObject *object) { CsmXSMPClient *client = (CsmXSMPClient *) object; g_debug ("CsmXSMPClient: xsmp_finalize (%s)", client->priv->description); csm_xsmp_client_disconnect (client); g_free (client->priv->description); g_ptr_array_foreach (client->priv->props, (GFunc)SmFreeProperty, NULL); g_ptr_array_free (client->priv->props, TRUE); G_OBJECT_CLASS (csm_xsmp_client_parent_class)->finalize (object); } static gboolean _boolean_handled_accumulator (GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer dummy) { gboolean continue_emission; gboolean signal_handled; signal_handled = g_value_get_boolean (handler_return); g_value_set_boolean (return_accu, signal_handled); continue_emission = !signal_handled; return continue_emission; } static CsmClientRestartStyle xsmp_get_restart_style_hint (CsmClient *client) { SmProp *prop; CsmClientRestartStyle hint; g_debug ("CsmXSMPClient: getting restart style"); hint = CSM_CLIENT_RESTART_IF_RUNNING; prop = find_property (CSM_XSMP_CLIENT (client), SmRestartStyleHint, NULL); if (!prop || strcmp (prop->type, SmCARD8) != 0) { return CSM_CLIENT_RESTART_IF_RUNNING; } switch (((unsigned char *)prop->vals[0].value)[0]) { case SmRestartIfRunning: hint = CSM_CLIENT_RESTART_IF_RUNNING; break; case SmRestartAnyway: hint = CSM_CLIENT_RESTART_ANYWAY; break; case SmRestartImmediately: hint = CSM_CLIENT_RESTART_IMMEDIATELY; break; case SmRestartNever: hint = CSM_CLIENT_RESTART_NEVER; break; default: break; } return hint; } static gboolean _parse_value_as_uint (const char *value, guint *uintval) { char *end_of_valid_uint; gulong ulong_value; guint uint_value; errno = 0; ulong_value = strtoul (value, &end_of_valid_uint, 10); if (*value == '\0' || *end_of_valid_uint != '\0') { return FALSE; } uint_value = ulong_value; if (uint_value != ulong_value || errno == ERANGE) { return FALSE; } *uintval = uint_value; return TRUE; } static guint xsmp_get_unix_process_id (CsmClient *client) { SmProp *prop; guint pid; gboolean res; g_debug ("CsmXSMPClient: getting pid"); prop = find_property (CSM_XSMP_CLIENT (client), SmProcessID, NULL); if (!prop || strcmp (prop->type, SmARRAY8) != 0) { return 0; } pid = 0; res = _parse_value_as_uint ((char *)prop->vals[0].value, &pid); if (! res) { pid = 0; } return pid; } static void csm_xsmp_client_class_init (CsmXSMPClientClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CsmClientClass *client_class = CSM_CLIENT_CLASS (klass); object_class->finalize = csm_xsmp_client_finalize; object_class->constructor = csm_xsmp_client_constructor; object_class->get_property = csm_xsmp_client_get_property; object_class->set_property = csm_xsmp_client_set_property; client_class->impl_save = xsmp_save; client_class->impl_stop = xsmp_stop; client_class->impl_query_end_session = xsmp_query_end_session; client_class->impl_end_session = xsmp_end_session; client_class->impl_cancel_end_session = xsmp_cancel_end_session; client_class->impl_get_app_name = xsmp_get_app_name; client_class->impl_get_restart_style_hint = xsmp_get_restart_style_hint; client_class->impl_get_unix_process_id = xsmp_get_unix_process_id; signals[REGISTER_REQUEST] = g_signal_new ("register-request", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmXSMPClientClass, register_request), _boolean_handled_accumulator, NULL, csm_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, G_TYPE_POINTER); signals[LOGOUT_REQUEST] = g_signal_new ("logout-request", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (CsmXSMPClientClass, logout_request), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); g_object_class_install_property (object_class, PROP_ICE_CONNECTION, g_param_spec_pointer ("ice-connection", "ice-connection", "ice-connection", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_type_class_add_private (klass, sizeof (CsmXSMPClientPrivate)); } CsmClient * csm_xsmp_client_new (IceConn ice_conn) { CsmXSMPClient *xsmp; xsmp = g_object_new (CSM_TYPE_XSMP_CLIENT, "ice-connection", ice_conn, NULL); return CSM_CLIENT (xsmp); } static Status register_client_callback (SmsConn conn, SmPointer manager_data, char *previous_id) { CsmXSMPClient *client = manager_data; gboolean handled; char *id; g_debug ("CsmXSMPClient: Client '%s' received RegisterClient(%s)", client->priv->description, previous_id ? previous_id : "NULL"); /* There are three cases: * 1. id is NULL - we'll use a new one * 2. id is known - we'll use known one * 3. id is unknown - this is an error */ id = g_strdup (previous_id); handled = FALSE; g_signal_emit (client, signals[REGISTER_REQUEST], 0, &id, &handled); if (! handled) { g_debug ("CsmXSMPClient: RegisterClient not handled!"); g_free (id); free (previous_id); g_assert_not_reached (); return FALSE; } if (IS_STRING_EMPTY (id)) { g_debug ("CsmXSMPClient: rejected: invalid previous_id"); free (previous_id); return FALSE; } g_object_set (client, "startup-id", id, NULL); set_description (client); g_debug ("CsmXSMPClient: Sending RegisterClientReply to '%s'", client->priv->description); SmsRegisterClientReply (conn, id); if (IS_STRING_EMPTY (previous_id)) { /* Send the initial SaveYourself. */ g_debug ("CsmXSMPClient: Sending initial SaveYourself"); SmsSaveYourself (conn, SmSaveLocal, False, SmInteractStyleNone, False); client->priv->current_save_yourself = SmSaveLocal; } csm_client_set_status (CSM_CLIENT (client), CSM_CLIENT_REGISTERED); g_free (id); free (previous_id); return TRUE; } static void save_yourself_request_callback (SmsConn conn, SmPointer manager_data, int save_type, Bool shutdown, int interact_style, Bool fast, Bool global) { CsmXSMPClient *client = manager_data; g_debug ("CsmXSMPClient: Client '%s' received SaveYourselfRequest(%s, %s, %s, %s, %s)", client->priv->description, save_type == SmSaveLocal ? "SmSaveLocal" : save_type == SmSaveGlobal ? "SmSaveGlobal" : "SmSaveBoth", shutdown ? "Shutdown" : "!Shutdown", interact_style == SmInteractStyleAny ? "SmInteractStyleAny" : interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" : "SmInteractStyleNone", fast ? "Fast" : "!Fast", global ? "Global" : "!Global"); /* Examining the g_debug above, you can see that there are a total * of 72 different combinations of options that this could have been * called with. However, most of them are stupid. * * If @shutdown and @global are both TRUE, that means the caller is * requesting that a logout message be sent to all clients, so we do * that. We use @fast to decide whether or not to show a * confirmation dialog. (This isn't really what @fast is for, but * the old and ksmserver both interpret it that way, * so we do too.) We ignore @save_type because we pick the correct * save_type ourselves later based on user prefs, dialog choices, * etc, and we ignore @interact_style, because clients have not used * it correctly consistently enough to make it worth honoring. * * If @shutdown is TRUE and @global is FALSE, the caller is * confused, so we ignore the request. * * If @shutdown is FALSE and @save_type is SmSaveGlobal or * SmSaveBoth, then the client wants us to ask some or all open * applications to save open files to disk, but NOT quit. This is * silly and so we ignore the request. * * If @shutdown is FALSE and @save_type is SmSaveLocal, then the * client wants us to ask some or all open applications to update * their current saved state, but not log out. At the moment, the * code only supports this for the !global case (ie, a client * requesting that it be allowed to update *its own* saved state, * but not having everyone else update their saved state). */ if (shutdown && global) { g_debug ("CsmXSMPClient: initiating shutdown"); g_signal_emit (client, signals[LOGOUT_REQUEST], 0, !fast); } else if (!shutdown && !global) { g_debug ("CsmXSMPClient: initiating checkpoint"); do_save_yourself (client, SmSaveLocal, TRUE); } else { g_debug ("CsmXSMPClient: ignoring"); } } static void save_yourself_phase2_request_callback (SmsConn conn, SmPointer manager_data) { CsmXSMPClient *client = manager_data; g_debug ("CsmXSMPClient: Client '%s' received SaveYourselfPhase2Request", client->priv->description); client->priv->current_save_yourself = -1; /* this is a valid response to SaveYourself and therefore may be a response to a QES or ES */ csm_client_end_session_response (CSM_CLIENT (client), TRUE, TRUE, FALSE, NULL); } static void interact_request_callback (SmsConn conn, SmPointer manager_data, int dialog_type) { CsmXSMPClient *client = manager_data; #if 0 gboolean res; GError *error; #endif g_debug ("CsmXSMPClient: Client '%s' received InteractRequest(%s)", client->priv->description, dialog_type == SmDialogNormal ? "Dialog" : "Errors"); csm_client_end_session_response (CSM_CLIENT (client), FALSE, FALSE, FALSE, _("This program is blocking logout.")); #if 0 /* Can't just call back with Interact because session client grabs the keyboard! So, we try to get it to release grabs by telling it we've cancelled the shutdown. This grabbing is clearly bullshit and is not supported by the client spec or protocol spec. */ res = xsmp_cancel_end_session (CSM_CLIENT (client), &error); if (! res) { g_warning ("Unable to cancel end session: %s", error->message); g_error_free (error); } #endif xsmp_interact (CSM_CLIENT (client)); } static void interact_done_callback (SmsConn conn, SmPointer manager_data, Bool cancel_shutdown) { CsmXSMPClient *client = manager_data; g_debug ("CsmXSMPClient: Client '%s' received InteractDone(cancel_shutdown = %s)", client->priv->description, cancel_shutdown ? "True" : "False"); csm_client_end_session_response (CSM_CLIENT (client), TRUE, FALSE, cancel_shutdown, NULL); } static void save_yourself_done_callback (SmsConn conn, SmPointer manager_data, Bool success) { CsmXSMPClient *client = manager_data; g_debug ("CsmXSMPClient: Client '%s' received SaveYourselfDone(success = %s)", client->priv->description, success ? "True" : "False"); if (client->priv->current_save_yourself != -1) { SmsSaveComplete (client->priv->conn); client->priv->current_save_yourself = -1; } /* If success is false then the application couldn't save data. Nothing * the session manager can do about, though. FIXME: we could display a * dialog about this, I guess. */ csm_client_end_session_response (CSM_CLIENT (client), TRUE, FALSE, FALSE, NULL); if (client->priv->next_save_yourself) { int save_type = client->priv->next_save_yourself; gboolean allow_interact = client->priv->next_save_yourself_allow_interact; client->priv->next_save_yourself = -1; client->priv->next_save_yourself_allow_interact = -1; do_save_yourself (client, save_type, allow_interact); } } static void close_connection_callback (SmsConn conn, SmPointer manager_data, int count, char **reason_msgs) { CsmXSMPClient *client = manager_data; int i; g_debug ("CsmXSMPClient: Client '%s' received CloseConnection", client->priv->description); for (i = 0; i < count; i++) { g_debug ("CsmXSMPClient: close reason: '%s'", reason_msgs[i]); } SmFreeReasons (count, reason_msgs); csm_client_set_status (CSM_CLIENT (client), CSM_CLIENT_FINISHED); csm_client_disconnected (CSM_CLIENT (client)); } void csm_xsmp_client_connect (CsmXSMPClient *client, SmsConn conn, unsigned long *mask_ret, SmsCallbacks *callbacks_ret) { client->priv->conn = conn; g_debug ("CsmXSMPClient: Initializing client %s", client->priv->description); *mask_ret = 0; *mask_ret |= SmsRegisterClientProcMask; callbacks_ret->register_client.callback = register_client_callback; callbacks_ret->register_client.manager_data = client; *mask_ret |= SmsInteractRequestProcMask; callbacks_ret->interact_request.callback = interact_request_callback; callbacks_ret->interact_request.manager_data = client; *mask_ret |= SmsInteractDoneProcMask; callbacks_ret->interact_done.callback = interact_done_callback; callbacks_ret->interact_done.manager_data = client; *mask_ret |= SmsSaveYourselfRequestProcMask; callbacks_ret->save_yourself_request.callback = save_yourself_request_callback; callbacks_ret->save_yourself_request.manager_data = client; *mask_ret |= SmsSaveYourselfP2RequestProcMask; callbacks_ret->save_yourself_phase2_request.callback = save_yourself_phase2_request_callback; callbacks_ret->save_yourself_phase2_request.manager_data = client; *mask_ret |= SmsSaveYourselfDoneProcMask; callbacks_ret->save_yourself_done.callback = save_yourself_done_callback; callbacks_ret->save_yourself_done.manager_data = client; *mask_ret |= SmsCloseConnectionProcMask; callbacks_ret->close_connection.callback = close_connection_callback; callbacks_ret->close_connection.manager_data = client; *mask_ret |= SmsSetPropertiesProcMask; callbacks_ret->set_properties.callback = set_properties_callback; callbacks_ret->set_properties.manager_data = client; *mask_ret |= SmsDeletePropertiesProcMask; callbacks_ret->delete_properties.callback = delete_properties_callback; callbacks_ret->delete_properties.manager_data = client; *mask_ret |= SmsGetPropertiesProcMask; callbacks_ret->get_properties.callback = get_properties_callback; callbacks_ret->get_properties.manager_data = client; } void csm_xsmp_client_save_state (CsmXSMPClient *client) { g_return_if_fail (CSM_IS_XSMP_CLIENT (client)); } cinnamon-session-3.6.1/cinnamon-session/csm-xsmp-client.h0000644000175000017500000000701713205266677022224 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Novell, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #ifndef __CSM_XSMP_CLIENT_H__ #define __CSM_XSMP_CLIENT_H__ #include "csm-client.h" #include G_BEGIN_DECLS #define CSM_TYPE_XSMP_CLIENT (csm_xsmp_client_get_type ()) #define CSM_XSMP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CSM_TYPE_XSMP_CLIENT, CsmXSMPClient)) #define CSM_XSMP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CSM_TYPE_XSMP_CLIENT, CsmXSMPClientClass)) #define CSM_IS_XSMP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CSM_TYPE_XSMP_CLIENT)) #define CSM_IS_XSMP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CSM_TYPE_XSMP_CLIENT)) #define CSM_XSMP_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CSM_TYPE_XSMP_CLIENT, CsmXSMPClientClass)) typedef struct _CsmXSMPClient CsmXSMPClient; typedef struct _CsmXSMPClientClass CsmXSMPClientClass; typedef struct CsmXSMPClientPrivate CsmXSMPClientPrivate; struct _CsmXSMPClient { CsmClient parent; CsmXSMPClientPrivate *priv; }; struct _CsmXSMPClientClass { CsmClientClass parent_class; /* signals */ gboolean (*register_request) (CsmXSMPClient *client, char **client_id); gboolean (*logout_request) (CsmXSMPClient *client, gboolean prompt); void (*saved_state) (CsmXSMPClient *client); void (*request_phase2) (CsmXSMPClient *client); void (*request_interaction) (CsmXSMPClient *client); void (*interaction_done) (CsmXSMPClient *client, gboolean cancel_shutdown); void (*save_yourself_done) (CsmXSMPClient *client); }; GType csm_xsmp_client_get_type (void) G_GNUC_CONST; CsmClient *csm_xsmp_client_new (IceConn ice_conn); void csm_xsmp_client_connect (CsmXSMPClient *client, SmsConn conn, unsigned long *mask_ret, SmsCallbacks *callbacks_ret); void csm_xsmp_client_save_state (CsmXSMPClient *client); void csm_xsmp_client_save_yourself (CsmXSMPClient *client, gboolean save_state); void csm_xsmp_client_save_yourself_phase2 (CsmXSMPClient *client); void csm_xsmp_client_interact (CsmXSMPClient *client); void csm_xsmp_client_shutdown_cancelled (CsmXSMPClient *client); G_END_DECLS #endif /* __CSM_XSMP_CLIENT_H__ */ cinnamon-session-3.6.1/cinnamon-session/csm-xsmp-server.c0000644000175000017500000006377513205266677022264 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 Novell, Inc. * Copyright (C) 2008 Red Hat, Inc. * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_XTRANS /* Get the proto for _IceTransNoListen */ #define ICE_t #define TRANS_SERVER #include #undef ICE_t #undef TRANS_SERVER #endif /* HAVE_XTRANS */ #include "csm-xsmp-server.h" #include "csm-xsmp-client.h" #include "csm-util.h" /* ICEauthority stuff */ /* Various magic numbers stolen from iceauth.c */ #define CSM_ICE_AUTH_RETRIES 10 #define CSM_ICE_AUTH_INTERVAL 2 /* 2 seconds */ #define CSM_ICE_AUTH_LOCK_TIMEOUT 600 /* 10 minutes */ #define CSM_ICE_MAGIC_COOKIE_AUTH_NAME "MIT-MAGIC-COOKIE-1" #define CSM_ICE_MAGIC_COOKIE_LEN 16 #define CSM_XSMP_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_XSMP_SERVER, CsmXsmpServerPrivate)) struct CsmXsmpServerPrivate { CsmStore *client_store; IceListenObj *xsmp_sockets; int num_xsmp_sockets; int num_local_xsmp_sockets; gboolean stopping; }; enum { PROP_0, PROP_CLIENT_STORE }; static void csm_xsmp_server_finalize (GObject *object); static gpointer xsmp_server_object = NULL; G_DEFINE_TYPE (CsmXsmpServer, csm_xsmp_server, G_TYPE_OBJECT) typedef struct { CsmXsmpServer *server; IceListenObj listener; } CsmIceConnectionData; typedef struct { guint watch_id; guint protocol_timeout; } CsmIceConnectionWatch; static void disconnect_ice_connection (IceConn ice_conn) { IceSetShutdownNegotiation (ice_conn, FALSE); IceCloseConnection (ice_conn); } static void free_ice_connection_watch (CsmIceConnectionWatch *data) { if (data->watch_id) { g_source_remove (data->watch_id); data->watch_id = 0; } if (data->protocol_timeout) { g_source_remove (data->protocol_timeout); data->protocol_timeout = 0; } g_free (data); } static gboolean ice_protocol_timeout (IceConn ice_conn) { CsmIceConnectionWatch *data; g_debug ("CsmXsmpServer: ice_protocol_timeout for IceConn %p with status %d", ice_conn, IceConnectionStatus (ice_conn)); data = ice_conn->context; free_ice_connection_watch (data); disconnect_ice_connection (ice_conn); return FALSE; } static gboolean auth_iochannel_watch (GIOChannel *source, GIOCondition condition, IceConn ice_conn) { CsmIceConnectionWatch *data; gboolean keep_going; data = ice_conn->context; switch (IceProcessMessages (ice_conn, NULL, NULL)) { case IceProcessMessagesSuccess: keep_going = TRUE; break; case IceProcessMessagesIOError: g_debug ("CsmXsmpServer: IceProcessMessages returned IceProcessMessagesIOError"); free_ice_connection_watch (data); disconnect_ice_connection (ice_conn); keep_going = FALSE; break; case IceProcessMessagesConnectionClosed: g_debug ("CsmXsmpServer: IceProcessMessages returned IceProcessMessagesConnectionClosed"); free_ice_connection_watch (data); keep_going = FALSE; break; default: g_assert_not_reached (); } return keep_going; } /* IceAcceptConnection returns a new ICE connection that is in a "pending" state, * this is because authentification may be necessary. * So we've to authenticate it, before accept_xsmp_connection() is called. * Then each CsmXSMPClient will have its own IceConn watcher */ static void auth_ice_connection (IceConn ice_conn) { GIOChannel *channel; CsmIceConnectionWatch *data; int fd; g_debug ("CsmXsmpServer: auth_ice_connection()"); fd = IceConnectionNumber (ice_conn); fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC); channel = g_io_channel_unix_new (fd); data = g_new0 (CsmIceConnectionWatch, 1); ice_conn->context = data; data->protocol_timeout = g_timeout_add_seconds (5, (GSourceFunc)ice_protocol_timeout, ice_conn); data->watch_id = g_io_add_watch (channel, G_IO_IN | G_IO_ERR, (GIOFunc)auth_iochannel_watch, ice_conn); g_io_channel_unref (channel); } /* This is called (by glib via xsmp->ice_connection_watch) when a * connection is first received on the ICE listening socket. */ static gboolean accept_ice_connection (GIOChannel *source, GIOCondition condition, CsmIceConnectionData *data) { IceConn ice_conn; IceAcceptStatus status; g_debug ("CsmXsmpServer: accept_ice_connection()"); ice_conn = IceAcceptConnection (data->listener, &status); if (status != IceAcceptSuccess) { g_debug ("CsmXsmpServer: IceAcceptConnection returned %d", status); return TRUE; } auth_ice_connection (ice_conn); return TRUE; } void csm_xsmp_server_start (CsmXsmpServer *server) { GIOChannel *channel; int i; for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) { CsmIceConnectionData *data; data = g_new0 (CsmIceConnectionData, 1); data->server = server; data->listener = server->priv->xsmp_sockets[i]; channel = g_io_channel_unix_new (IceGetListenConnectionNumber (server->priv->xsmp_sockets[i])); g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_HUP | G_IO_ERR, (GIOFunc)accept_ice_connection, data, (GDestroyNotify)g_free); g_io_channel_unref (channel); } } void csm_xsmp_server_stop_accepting_new_clients (CsmXsmpServer *server) { g_return_if_fail (CSM_IS_XSMP_SERVER (server)); g_debug ("csm_xsmp_server_stop_accepting_new_clients"); server->priv->stopping = TRUE; } void csm_xsmp_server_start_accepting_new_clients (CsmXsmpServer *server) { g_return_if_fail (CSM_IS_XSMP_SERVER (server)); g_debug ("csm_xsmp_server_start"); server->priv->stopping = FALSE; } static void csm_xsmp_server_set_client_store (CsmXsmpServer *xsmp_server, CsmStore *store) { g_return_if_fail (CSM_IS_XSMP_SERVER (xsmp_server)); if (store != NULL) { g_object_ref (store); } if (xsmp_server->priv->client_store != NULL) { g_object_unref (xsmp_server->priv->client_store); } xsmp_server->priv->client_store = store; } static void csm_xsmp_server_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { CsmXsmpServer *self; self = CSM_XSMP_SERVER (object); switch (prop_id) { case PROP_CLIENT_STORE: csm_xsmp_server_set_client_store (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void csm_xsmp_server_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { CsmXsmpServer *self; self = CSM_XSMP_SERVER (object); switch (prop_id) { case PROP_CLIENT_STORE: g_value_set_object (value, self->priv->client_store); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /* This is called (by libSM) when XSMP is initiated on an ICE * connection that was already accepted by accept_ice_connection. */ static Status accept_xsmp_connection (SmsConn sms_conn, CsmXsmpServer *server, unsigned long *mask_ret, SmsCallbacks *callbacks_ret, char **failure_reason_ret) { IceConn ice_conn; CsmClient *client; CsmIceConnectionWatch *data; if (server->priv->stopping) { g_debug ("CsmXsmpServer: In shutdown, rejecting new client"); *failure_reason_ret = strdup (_("Refusing new client connection because the session is currently being shut down\n")); return FALSE; } ice_conn = SmsGetIceConnection (sms_conn); data = ice_conn->context; /* Each CsmXSMPClient has its own IceConn watcher */ free_ice_connection_watch (data); client = csm_xsmp_client_new (ice_conn); csm_store_add (server->priv->client_store, csm_client_peek_id (client), G_OBJECT (client)); /* the store will own the ref */ g_object_unref (client); csm_xsmp_client_connect (CSM_XSMP_CLIENT (client), sms_conn, mask_ret, callbacks_ret); return TRUE; } static void ice_error_handler (IceConn conn, Bool swap, int offending_minor_opcode, unsigned long offending_sequence, int error_class, int severity, IcePointer values) { g_debug ("CsmXsmpServer: ice_error_handler (%p, %s, %d, %lx, %d, %d)", conn, swap ? "TRUE" : "FALSE", offending_minor_opcode, offending_sequence, error_class, severity); if (severity == IceCanContinue) { return; } /* FIXME: the ICElib docs are completely vague about what we're * supposed to do in this case. Need to verify that calling * IceCloseConnection() here is guaranteed to cause neither * free-memory-reads nor leaks. */ IceCloseConnection (conn); } static void ice_io_error_handler (IceConn conn) { g_debug ("CsmXsmpServer: ice_io_error_handler (%p)", conn); /* We don't need to do anything here; the next call to * IceProcessMessages() for this connection will receive * IceProcessMessagesIOError and we can handle the error there. */ } static void sms_error_handler (SmsConn conn, Bool swap, int offending_minor_opcode, unsigned long offending_sequence_num, int error_class, int severity, IcePointer values) { g_debug ("CsmXsmpServer: sms_error_handler (%p, %s, %d, %lx, %d, %d)", conn, swap ? "TRUE" : "FALSE", offending_minor_opcode, offending_sequence_num, error_class, severity); /* We don't need to do anything here; if the connection needs to be * closed, libSM will do that itself. */ } static IceAuthFileEntry * auth_entry_new (const char *protocol, const char *network_id) { IceAuthFileEntry *file_entry; IceAuthDataEntry data_entry; file_entry = malloc (sizeof (IceAuthFileEntry)); file_entry->protocol_name = strdup (protocol); file_entry->protocol_data = NULL; file_entry->protocol_data_length = 0; file_entry->network_id = strdup (network_id); file_entry->auth_name = strdup (CSM_ICE_MAGIC_COOKIE_AUTH_NAME); file_entry->auth_data = IceGenerateMagicCookie (CSM_ICE_MAGIC_COOKIE_LEN); file_entry->auth_data_length = CSM_ICE_MAGIC_COOKIE_LEN; /* Also create an in-memory copy, which is what the server will * actually use for checking client auth. */ data_entry.protocol_name = file_entry->protocol_name; data_entry.network_id = file_entry->network_id; data_entry.auth_name = file_entry->auth_name; data_entry.auth_data = file_entry->auth_data; data_entry.auth_data_length = file_entry->auth_data_length; IceSetPaAuthData (1, &data_entry); return file_entry; } static gboolean update_iceauthority (CsmXsmpServer *server, gboolean adding) { char *filename; char **our_network_ids; FILE *fp; IceAuthFileEntry *auth_entry; GSList *entries; GSList *e; int i; int ret; gboolean ok = FALSE; filename = IceAuthFileName (); do { ret = IceLockAuthFile (filename, CSM_ICE_AUTH_RETRIES, CSM_ICE_AUTH_INTERVAL, CSM_ICE_AUTH_LOCK_TIMEOUT); } while (ret != IceAuthLockSuccess && errno == EINTR); if (ret != IceAuthLockSuccess) { g_warning ("IceLockAuthFile failed: %m"); return FALSE; } our_network_ids = g_malloc (server->priv->num_local_xsmp_sockets * sizeof (char *)); for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) { our_network_ids[i] = IceGetListenConnectionString (server->priv->xsmp_sockets[i]); } entries = NULL; fp = fopen (filename, "r+"); if (fp != NULL) { while ((auth_entry = IceReadAuthFileEntry (fp)) != NULL) { /* Skip/delete entries with no network ID (invalid), or with * our network ID; if we're starting up, an entry with our * ID must be a stale entry left behind by an old process, * and if we're shutting down, it won't be valid in the * future, so either way we want to remove it from the list. */ if (!auth_entry->network_id) { IceFreeAuthFileEntry (auth_entry); continue; } for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) { if (!strcmp (auth_entry->network_id, our_network_ids[i])) { IceFreeAuthFileEntry (auth_entry); break; } } if (i != server->priv->num_local_xsmp_sockets) { continue; } entries = g_slist_prepend (entries, auth_entry); } rewind (fp); } else { int fd; if (errno != ENOENT) { g_warning ("Unable to read ICE authority file %s: %m", filename); goto cleanup; } fd = open (filename, O_CREAT | O_WRONLY, 0600); fp = fdopen (fd, "w"); if (!fp) { g_warning ("Unable to write to ICE authority file: %s", filename); if (fd != -1) { close (fd); } goto cleanup; } } if (adding) { for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) { entries = g_slist_append (entries, auth_entry_new ("ICE", our_network_ids[i])); entries = g_slist_prepend (entries, auth_entry_new ("XSMP", our_network_ids[i])); } } for (e = entries; e; e = e->next) { IceAuthFileEntry *auth_entry = e->data; IceWriteAuthFileEntry (fp, auth_entry); IceFreeAuthFileEntry (auth_entry); } g_slist_free (entries); fclose (fp); ok = TRUE; cleanup: IceUnlockAuthFile (filename); for (i = 0; i < server->priv->num_local_xsmp_sockets; i++) { free (our_network_ids[i]); } g_free (our_network_ids); return ok; } static void setup_listener (CsmXsmpServer *server) { char error[256]; mode_t saved_umask; char *network_id_list; int i; int res; /* Set up sane error handlers */ IceSetErrorHandler (ice_error_handler); IceSetIOErrorHandler (ice_io_error_handler); SmsSetErrorHandler (sms_error_handler); /* Initialize libSM; we pass NULL for hostBasedAuthProc to disable * host-based authentication. */ res = SmsInitialize (PACKAGE, VERSION, (SmsNewClientProc)accept_xsmp_connection, server, NULL, sizeof (error), error); if (! res) { csm_util_init_error (TRUE, "Could not initialize libSM: %s", error); } #if HAVE_XTRANS /* By default, IceListenForConnections will open one socket for each * transport type known to X. We don't want connections from remote * hosts, so for security reasons it would be best if ICE didn't * even open any non-local sockets. So we use an internal ICElib * method to disable them here. Unfortunately, there is no way to * ask X what transport types it knows about, so we're forced to * guess. */ _IceTransNoListen ("tcp"); #endif /* Create the XSMP socket. Older versions of IceListenForConnections * have a bug which causes the umask to be set to 0 on certain types * of failures. Probably not an issue on any modern systems, but * we'll play it safe. */ saved_umask = umask (0); umask (saved_umask); res = IceListenForConnections (&server->priv->num_xsmp_sockets, &server->priv->xsmp_sockets, sizeof (error), error); if (! res) { csm_util_init_error (TRUE, _("Could not create ICE listening socket: %s"), error); } umask (saved_umask); /* Find the local sockets in the returned socket list and move them * to the start of the list. */ for (i = server->priv->num_local_xsmp_sockets = 0; i < server->priv->num_xsmp_sockets; i++) { char *id = IceGetListenConnectionString (server->priv->xsmp_sockets[i]); if (!strncmp (id, "local/", sizeof ("local/") - 1) || !strncmp (id, "unix/", sizeof ("unix/") - 1)) { if (i > server->priv->num_local_xsmp_sockets) { IceListenObj tmp; tmp = server->priv->xsmp_sockets[i]; server->priv->xsmp_sockets[i] = server->priv->xsmp_sockets[server->priv->num_local_xsmp_sockets]; server->priv->xsmp_sockets[server->priv->num_local_xsmp_sockets] = tmp; } server->priv->num_local_xsmp_sockets++; } free (id); } if (server->priv->num_local_xsmp_sockets == 0) { csm_util_init_error (TRUE, "IceListenForConnections did not return a local listener!"); } #ifdef HAVE_XTRANS if (server->priv->num_local_xsmp_sockets != server->priv->num_xsmp_sockets) { /* Xtrans was apparently compiled with support for some * non-local transport besides TCP (which we disabled above); we * won't create IO watches on those extra sockets, so * connections to them will never be noticed, but they're still * there, which is inelegant. * * If the g_warning below is triggering for you and you want to * stop it, the fix is to add additional _IceTransNoListen() * calls above. */ network_id_list = IceComposeNetworkIdList (server->priv->num_xsmp_sockets - server->priv->num_local_xsmp_sockets, server->priv->xsmp_sockets + server->priv->num_local_xsmp_sockets); g_warning ("IceListenForConnections returned %d non-local listeners: %s", server->priv->num_xsmp_sockets - server->priv->num_local_xsmp_sockets, network_id_list); free (network_id_list); } #endif /* Update .ICEauthority with new auth entries for our socket */ if (!update_iceauthority (server, TRUE)) { /* FIXME: is this really fatal? Hm... */ csm_util_init_error (TRUE, "Could not update ICEauthority file %s", IceAuthFileName ()); } network_id_list = IceComposeNetworkIdList (server->priv->num_local_xsmp_sockets, server->priv->xsmp_sockets); csm_util_setenv ("SESSION_MANAGER", network_id_list); g_debug ("CsmXsmpServer: SESSION_MANAGER=%s\n", network_id_list); free (network_id_list); } static GObject * csm_xsmp_server_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { CsmXsmpServer *xsmp_server; xsmp_server = CSM_XSMP_SERVER (G_OBJECT_CLASS (csm_xsmp_server_parent_class)->constructor (type, n_construct_properties, construct_properties)); setup_listener (xsmp_server); return G_OBJECT (xsmp_server); } static void csm_xsmp_server_class_init (CsmXsmpServerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = csm_xsmp_server_get_property; object_class->set_property = csm_xsmp_server_set_property; object_class->constructor = csm_xsmp_server_constructor; object_class->finalize = csm_xsmp_server_finalize; g_object_class_install_property (object_class, PROP_CLIENT_STORE, g_param_spec_object ("client-store", NULL, NULL, CSM_TYPE_STORE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_type_class_add_private (klass, sizeof (CsmXsmpServerPrivate)); } static void csm_xsmp_server_init (CsmXsmpServer *xsmp_server) { xsmp_server->priv = CSM_XSMP_SERVER_GET_PRIVATE (xsmp_server); } static void csm_xsmp_server_finalize (GObject *object) { CsmXsmpServer *xsmp_server; g_return_if_fail (object != NULL); g_return_if_fail (CSM_IS_XSMP_SERVER (object)); xsmp_server = CSM_XSMP_SERVER (object); g_return_if_fail (xsmp_server->priv != NULL); IceFreeListenObjs (xsmp_server->priv->num_xsmp_sockets, xsmp_server->priv->xsmp_sockets); if (xsmp_server->priv->client_store != NULL) { g_object_unref (xsmp_server->priv->client_store); } G_OBJECT_CLASS (csm_xsmp_server_parent_class)->finalize (object); } CsmXsmpServer * csm_xsmp_server_new (CsmStore *client_store) { if (xsmp_server_object != NULL) { g_object_ref (xsmp_server_object); } else { xsmp_server_object = g_object_new (CSM_TYPE_XSMP_SERVER, "client-store", client_store, NULL); g_object_add_weak_pointer (xsmp_server_object, (gpointer *) &xsmp_server_object); } return CSM_XSMP_SERVER (xsmp_server_object); } cinnamon-session-3.6.1/cinnamon-session/csm-xsmp-server.h0000644000175000017500000000441313205266677022251 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __CSM_XSMP_SERVER_H #define __CSM_XSMP_SERVER_H #include #include "csm-store.h" G_BEGIN_DECLS #define CSM_TYPE_XSMP_SERVER (csm_xsmp_server_get_type ()) #define CSM_XSMP_SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CSM_TYPE_XSMP_SERVER, CsmXsmpServer)) #define CSM_XSMP_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), CSM_TYPE_XSMP_SERVER, CsmXsmpServerClass)) #define CSM_IS_XSMP_SERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CSM_TYPE_XSMP_SERVER)) #define CSM_IS_XSMP_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CSM_TYPE_XSMP_SERVER)) #define CSM_XSMP_SERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), CSM_TYPE_XSMP_SERVER, CsmXsmpServerClass)) typedef struct CsmXsmpServerPrivate CsmXsmpServerPrivate; typedef struct { GObject parent; CsmXsmpServerPrivate *priv; } CsmXsmpServer; typedef struct { GObjectClass parent_class; } CsmXsmpServerClass; GType csm_xsmp_server_get_type (void); CsmXsmpServer * csm_xsmp_server_new (CsmStore *client_store); void csm_xsmp_server_start (CsmXsmpServer *server); void csm_xsmp_server_stop_accepting_new_clients (CsmXsmpServer *server); void csm_xsmp_server_start_accepting_new_clients (CsmXsmpServer *server); G_END_DECLS #endif /* __CSM_XSMP_SERVER_H */ cinnamon-session-3.6.1/cinnamon-session/main.c0000644000175000017500000003267213205266677020125 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006 Novell, Inc. * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mdm-signal-handler.h" #include "mdm-log.h" #include "csm-util.h" #include "csm-manager.h" #include "csm-session-fill.h" #include "csm-store.h" #include "csm-system.h" #include "csm-fail-whale-dialog.h" #define CSM_DBUS_NAME "org.gnome.SessionManager" static gboolean failsafe = FALSE; static gboolean show_version = FALSE; static gboolean debug = FALSE; static gboolean please_fail = FALSE; static DBusGProxy *bus_proxy = NULL; static void shutdown_cb (gpointer data); static void on_bus_name_lost (DBusGProxy *bus_proxy, const char *name, gpointer data) { g_warning ("Lost name on bus: %s, exiting", name); exit (1); } static gboolean acquire_name_on_proxy (DBusGProxy *bus_proxy, const char *name) { GError *error; guint result; gboolean res; gboolean ret; ret = FALSE; if (bus_proxy == NULL) { goto out; } error = NULL; res = dbus_g_proxy_call (bus_proxy, "RequestName", &error, G_TYPE_STRING, name, G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &result, G_TYPE_INVALID); if (! res) { if (error != NULL) { g_warning ("Failed to acquire %s: %s", name, error->message); g_error_free (error); } else { g_warning ("Failed to acquire %s", name); } goto out; } if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { if (error != NULL) { g_warning ("Failed to acquire %s: %s", name, error->message); g_error_free (error); } else { g_warning ("Failed to acquire %s", name); } goto out; } /* register for name lost */ dbus_g_proxy_add_signal (bus_proxy, "NameLost", G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal (bus_proxy, "NameLost", G_CALLBACK (on_bus_name_lost), NULL, NULL); ret = TRUE; out: return ret; } static gboolean acquire_name (void) { GError *error; DBusGConnection *connection; error = NULL; connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (connection == NULL) { csm_util_init_error (TRUE, "Could not connect to session bus: %s", error->message); return FALSE; } bus_proxy = dbus_g_proxy_new_for_name_owner (connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, &error); if (error != NULL) { csm_util_init_error (TRUE, "Could not connect to session bus: %s", error->message); return FALSE; } g_signal_connect_swapped (bus_proxy, "destroy", G_CALLBACK (shutdown_cb), NULL); if (! acquire_name_on_proxy (bus_proxy, CSM_DBUS_NAME) ) { csm_util_init_error (TRUE, "%s", "Could not acquire name on session bus"); return FALSE; } return TRUE; } static void shutdown_cb (gpointer data) { CsmManager *manager = (CsmManager *)data; g_debug ("Calling shutdown callback function"); /* * When the signal handler gets a shutdown signal, it calls * this function to inform CsmManager to not restart * applications in the off chance a handler is already queued * to dispatch following the below call to gtk_main_quit. */ if (manager) { csm_manager_set_phase (manager, CSM_MANAGER_PHASE_EXIT); gtk_main_quit (); } } static gboolean require_dbus_session (int argc, char **argv, GError **error) { char **new_argv; int i; if (g_getenv ("DBUS_SESSION_BUS_ADDRESS")) return TRUE; /* Just a sanity check to prevent infinite recursion if * dbus-launch fails to set DBUS_SESSION_BUS_ADDRESS */ g_return_val_if_fail (!g_str_has_prefix (argv[0], "dbus-launch"), TRUE); /* +2 for our new arguments, +1 for NULL */ new_argv = g_malloc ((argc + 3) * sizeof (*argv)); new_argv[0] = "dbus-launch"; new_argv[1] = "--exit-with-session"; for (i = 0; i < argc; i++) { new_argv[i + 2] = argv[i]; } new_argv[i + 2] = NULL; if (!execvp ("dbus-launch", new_argv)) { g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, "No session bus and could not exec dbus-launch: %s", g_strerror (errno)); return FALSE; } /* Should not be reached */ return TRUE; } int main (int argc, char **argv) { struct sigaction sa; GError *error; char *display_str; CsmManager *manager; CsmStore *client_store; static char **override_autostart_dirs = NULL; static char *session_name = NULL; static GOptionEntry entries[] = { { "autostart", 'a', 0, G_OPTION_ARG_STRING_ARRAY, &override_autostart_dirs, N_("Override standard autostart directories"), N_("AUTOSTART_DIR") }, { "session", 0, 0, G_OPTION_ARG_STRING, &session_name, N_("Session to use"), N_("SESSION_NAME") }, { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, N_("Enable debugging code"), NULL }, { "failsafe", 'f', 0, G_OPTION_ARG_NONE, &failsafe, N_("Do not load user-specified applications"), NULL }, { "version", 0, 0, G_OPTION_ARG_NONE, &show_version, N_("Version of this application"), NULL }, /* Translators: the 'fail whale' is the black dialog we show when something goes seriously wrong */ { "whale", 0, 0, G_OPTION_ARG_NONE, &please_fail, N_("Show the fail whale dialog for testing"), NULL }, { NULL, 0, 0, 0, NULL, NULL, NULL } }; char *qt_platform_theme_new = NULL; /* Make sure that we have a session bus */ if (!require_dbus_session (argc, argv, &error)) { csm_util_init_error (TRUE, "%s", error->message); } bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); GSettings *settings; settings = g_settings_new ("org.cinnamon.SessionManager"); if (g_settings_get_boolean (settings, "debug")) { debug = TRUE; } g_clear_object (&settings); sa.sa_handler = SIG_IGN; sa.sa_flags = 0; sigemptyset (&sa.sa_mask); sigaction (SIGPIPE, &sa, 0); error = NULL; gtk_init_with_args (&argc, &argv, (char *) _(" - the Cinnamon session manager"), entries, GETTEXT_PACKAGE, &error); if (error != NULL) { g_warning ("%s", error->message); exit (1); } if (show_version) { g_print ("%s %s\n", argv [0], VERSION); exit (1); } if (please_fail) { csm_fail_whale_dialog_we_failed (TRUE, TRUE); gtk_main (); exit (1); } csm_util_export_activation_environment (NULL); csm_util_export_user_environment (NULL); mdm_log_init (); mdm_log_set_debug (debug); /* Set DISPLAY explicitly for all our children, in case --display * was specified on the command line. */ display_str = gdk_get_display (); csm_util_setenv ("DISPLAY", display_str); g_free (display_str); const gchar *gtk_modules; gchar *new_gtk_modules = NULL; gtk_modules = g_getenv ("GTK_MODULES"); if (gtk_modules != NULL && g_strstr_len (gtk_modules, -1, "overlay-scrollbar")) { int i = 0; new_gtk_modules = g_strconcat ("", NULL); gchar **module_list = g_strsplit (gtk_modules, ":", -1); for (i = 0; i < g_strv_length (module_list); i++) { if (!g_strstr_len (module_list[i], -1, "overlay-scrollbar")) { gchar *tmp = new_gtk_modules; new_gtk_modules = g_strconcat (tmp, ":", module_list[i], NULL); g_free (tmp); } } g_strfreev (module_list); } if (new_gtk_modules) { csm_util_setenv ("GTK_MODULES", new_gtk_modules); } g_free (new_gtk_modules); /* Some third-party programs rely on GNOME_DESKTOP_SESSION_ID to * detect if GNOME is running. We keep this for compatibility reasons. */ csm_util_setenv ("GNOME_DESKTOP_SESSION_ID", "this-is-deprecated"); /* Make QT5 apps follow the GTK style. Starting with QT 5.7, a different * env var has to be set than what worked in previous versions. */ qt_platform_theme_new = HAVE_QT57 ? "qt5ct" : "qgnomeplatform"; if (NULL == g_getenv ("QT_QPA_PLATFORMTHEME")) { csm_util_setenv ("QT_QPA_PLATFORMTHEME", qt_platform_theme_new); } if ( ! HAVE_QT57 && NULL == g_getenv ("QT_STYLE_OVERRIDE") ) { csm_util_setenv ("QT_STYLE_OVERRIDE", "gtk"); } else if (HAVE_QT57 && NULL != g_getenv ("QT_STYLE_OVERRIDE")) { g_unsetenv ("QT_STYLE_OVERRIDE"); } /* GTK Overlay scrollbars */ settings = g_settings_new ("org.cinnamon.desktop.interface"); if (g_settings_get_boolean (settings, "gtk-overlay-scrollbars")) { csm_util_setenv ("GTK_OVERLAY_SCROLLING", "1"); } else { csm_util_setenv ("GTK_OVERLAY_SCROLLING", "0"); } g_clear_object (&settings); client_store = csm_store_new (); /* Talk to logind before acquiring a name, since it does synchronous * calls at initialization time that invoke a main loop and if we * already owned a name, then we would service too early during * that main loop. */ g_object_unref (csm_get_system ()); if (!acquire_name ()) { csm_fail_whale_dialog_we_failed (TRUE, TRUE); gtk_main (); exit (1); } manager = csm_manager_new (client_store, failsafe); if (IS_STRING_EMPTY (session_name)) session_name = _csm_manager_get_default_session (manager); csm_util_set_autostart_dirs (override_autostart_dirs); if (!csm_session_fill (manager, session_name)) { csm_util_init_error (TRUE, "Failed to load session \"%s\"", session_name ? session_name : "(null)"); } csm_manager_start (manager); gtk_main (); if (manager != NULL) { g_debug ("Unreffing manager"); g_object_unref (manager); } if (client_store != NULL) { g_object_unref (client_store); } if (bus_proxy != NULL) { g_object_unref (bus_proxy); } mdm_log_shutdown (); return 0; } cinnamon-session-3.6.1/cinnamon-session/mdm-log.c0000644000175000017500000001400313205266677020521 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Authors: William Jon McCann * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "mdm-log.h" static gboolean initialized = FALSE; static int syslog_levels = (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); static struct timespec tstart={0,0}, tend={0,0}; static void log_level_to_priority_and_prefix (GLogLevelFlags log_level, int *priorityp, const char **prefixp) { int priority; const char *prefix; /* Process the message prefix and priority */ switch (log_level & G_LOG_LEVEL_MASK) { case G_LOG_FLAG_FATAL: priority = LOG_EMERG; prefix = "FATAL"; break; case G_LOG_LEVEL_ERROR: priority = LOG_ERR; prefix = "ERROR"; break; case G_LOG_LEVEL_CRITICAL: priority = LOG_CRIT; prefix = "CRITICAL"; break; case G_LOG_LEVEL_WARNING: priority = LOG_WARNING; prefix = "WARNING"; break; case G_LOG_LEVEL_MESSAGE: priority = LOG_NOTICE; prefix = "MESSAGE"; break; case G_LOG_LEVEL_INFO: priority = LOG_INFO; prefix = "INFO"; break; case G_LOG_LEVEL_DEBUG: /* if debug was requested then bump this up to ERROR * to ensure it is seen in a log */ if (syslog_levels & G_LOG_LEVEL_DEBUG) { priority = LOG_WARNING; prefix = "DEBUG(+)"; } else { priority = LOG_DEBUG; prefix = "DEBUG"; } break; default: priority = LOG_DEBUG; prefix = "UNKNOWN"; break; } if (priorityp != NULL) { *priorityp = priority; } if (prefixp != NULL) { *prefixp = prefix; } } void mdm_log_default_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer unused_data) { GString *gstring; int priority; const char *level_prefix; char *string; gboolean do_log; gboolean is_fatal; is_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; do_log = (log_level & syslog_levels); if (! do_log) { return; } if (! initialized) { mdm_log_init (); } log_level_to_priority_and_prefix (log_level, &priority, &level_prefix); gstring = g_string_new (NULL); if (log_domain != NULL) { g_string_append (gstring, log_domain); g_string_append_c (gstring, '-'); } g_string_append (gstring, level_prefix); g_string_append (gstring, ": "); clock_gettime(CLOCK_MONOTONIC, &tend); gchar * timestring = g_strdup_printf("t+%.5fs", ((double)tend.tv_sec + 1.0e-9*tend.tv_nsec) - ((double)tstart.tv_sec + 1.0e-9*tstart.tv_nsec)); g_string_append (gstring, timestring); g_free (timestring); g_string_append (gstring, ": "); if (message == NULL) { g_string_append (gstring, "(NULL) message"); } else { g_string_append (gstring, message); } if (is_fatal) { g_string_append (gstring, "\naborting...\n"); } else { g_string_append (gstring, "\n"); } string = g_string_free (gstring, FALSE); syslog (priority, "%s", string); g_free (string); } void mdm_log_toggle_debug (void) { if (syslog_levels & G_LOG_LEVEL_DEBUG) { g_debug ("Debugging disabled"); syslog_levels &= ~G_LOG_LEVEL_DEBUG; } else { syslog_levels |= G_LOG_LEVEL_DEBUG; g_debug ("Debugging enabled"); } } void mdm_log_set_debug (gboolean debug) { if (debug) { syslog_levels |= G_LOG_LEVEL_DEBUG; g_debug ("Enabling debugging"); } else { g_debug ("Disabling debugging"); syslog_levels &= ~G_LOG_LEVEL_DEBUG; } } void mdm_log_init (void) { const char *prg_name; int options; clock_gettime(CLOCK_MONOTONIC, &tstart); g_log_set_default_handler (mdm_log_default_handler, NULL); prg_name = g_get_prgname (); options = LOG_PID; #ifdef LOG_PERROR options |= LOG_PERROR; #endif openlog (prg_name, options, LOG_DAEMON); initialized = TRUE; } void mdm_log_shutdown (void) { closelog (); initialized = FALSE; } cinnamon-session-3.6.1/cinnamon-session/mdm-log.h0000644000175000017500000000334713205266677020537 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * * Authors: William Jon McCann * */ #ifndef __MDM_LOG_H #define __MDM_LOG_H #include #include G_BEGIN_DECLS void mdm_log_default_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer unused_data); void mdm_log_set_debug (gboolean debug); void mdm_log_toggle_debug (void); void mdm_log_init (void); void mdm_log_shutdown (void); /* compatibility */ #define mdm_fail g_critical #define mdm_error g_warning #define mdm_info g_message #define mdm_debug g_debug #define mdm_assert g_assert #define mdm_assert_not_reached g_assert_not_reached G_END_DECLS #endif /* __MDM_LOG_H */ cinnamon-session-3.6.1/cinnamon-session/mdm-signal-handler.c0000644000175000017500000004127713205266677022645 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2006 Red Hat, Inc. * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #if HAVE_EXECINFO_H #include #endif #include #include #include #include #include #include #include #include "mdm-signal-handler.h" #define MDM_SIGNAL_HANDLER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MDM_TYPE_SIGNAL_HANDLER, MdmSignalHandlerPrivate)) typedef struct { int signal_number; MdmSignalHandlerFunc func; gpointer data; guint id; } CallbackData; struct MdmSignalHandlerPrivate { GHashTable *lookup; GHashTable *id_lookup; GHashTable *action_lookup; guint next_id; GDestroyNotify fatal_func; gpointer fatal_data; }; static void mdm_signal_handler_finalize (GObject *object); static gpointer signal_handler_object = NULL; static int signal_pipes[2]; static int signals_blocked = 0; static sigset_t signals_block_mask; static sigset_t signals_oldmask; G_DEFINE_TYPE (MdmSignalHandler, mdm_signal_handler, G_TYPE_OBJECT) static void block_signals_push (void) { signals_blocked++; if (signals_blocked == 1) { /* Set signal mask */ sigemptyset (&signals_block_mask); sigfillset (&signals_block_mask); sigprocmask (SIG_BLOCK, &signals_block_mask, &signals_oldmask); } } static void block_signals_pop (void) { signals_blocked--; if (signals_blocked == 0) { /* Set signal mask */ sigprocmask (SIG_SETMASK, &signals_oldmask, NULL); } } static gboolean signal_io_watch (GIOChannel *ioc, GIOCondition condition, MdmSignalHandler *handler) { char buf[256]; gboolean is_fatal; gsize bytes_read; int i; block_signals_push (); g_io_channel_read_chars (ioc, buf, sizeof (buf), &bytes_read, NULL); is_fatal = FALSE; for (i = 0; i < bytes_read; i++) { int signum; GSList *handlers; GSList *l; signum = (gint32)buf[i]; g_debug ("MdmSignalHandler: handling signal %d", signum); handlers = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (signum)); g_debug ("MdmSignalHandler: Found %u callbacks", g_slist_length (handlers)); for (l = handlers; l != NULL; l = l->next) { gboolean res; CallbackData *data; data = g_hash_table_lookup (handler->priv->id_lookup, l->data); if (data != NULL) { if (data->func != NULL) { g_debug ("MdmSignalHandler: running %d handler: %p", signum, data->func); res = data->func (signum, data->data); if (! res) { is_fatal = TRUE; } } } } } block_signals_pop (); if (is_fatal) { if (handler->priv->fatal_func != NULL) { g_debug ("MdmSignalHandler: Caught termination signal - calling fatal func"); handler->priv->fatal_func (handler->priv->fatal_data); } else { g_debug ("MdmSignalHandler: Caught termination signal - exiting"); exit (1); } return FALSE; } g_debug ("MdmSignalHandler: Done handling signals"); return TRUE; } static void fallback_get_backtrace (void) { #if HAVE_EXECINFO_H void * frames[64]; size_t size; char ** strings; size_t i; size = backtrace (frames, G_N_ELEMENTS (frames)); if ((strings = backtrace_symbols (frames, size))) { syslog (LOG_CRIT, "******************* START ********************************"); for (i = 0; i < size; i++) { syslog (LOG_CRIT, "Frame %zd: %s", i, strings[i]); } free (strings); syslog (LOG_CRIT, "******************* END **********************************"); } else { #endif g_warning ("MDM crashed, but symbols couldn't be retrieved."); #if HAVE_EXECINFO_H } #endif } static gboolean crashlogger_get_backtrace (void) { gboolean success = FALSE; int pid; pid = fork (); if (pid > 0) { /* Wait for the child to finish */ int estatus; if (waitpid (pid, &estatus, 0) != -1) { /* Only succeed if the crashlogger succeeded */ if (WIFEXITED (estatus) && (WEXITSTATUS (estatus) == 0)) { success = TRUE; } } } else if (pid == 0) { /* Child process */ execl (LIBEXECDIR "/mdm-crash-logger", LIBEXECDIR "/mdm-crash-logger", NULL); } return success; } static void mdm_signal_handler_backtrace (void) { struct stat s; gboolean fallback = TRUE; /* Try to use gdb via mdm-crash-logger if it exists, since * we get much better information out of it. Otherwise * fall back to execinfo. */ if (g_stat (LIBEXECDIR "/mdm-crash-logger", &s) == 0) { fallback = crashlogger_get_backtrace () ? FALSE : TRUE; } if (fallback) { fallback_get_backtrace (); } } static void signal_handler (int signo) { static int in_fatal = 0; int ignore; guchar signo_byte = signo; /* avoid loops */ if (in_fatal > 0) { return; } ++in_fatal; switch (signo) { case SIGSEGV: case SIGBUS: case SIGILL: case SIGABRT: case SIGTRAP: mdm_signal_handler_backtrace (); exit (1); break; case SIGFPE: case SIGPIPE: /* let the fatal signals interrupt us */ --in_fatal; mdm_signal_handler_backtrace (); ignore = write (signal_pipes [1], &signo_byte, 1); break; default: --in_fatal; ignore = write (signal_pipes [1], &signo_byte, 1); break; } } static void catch_signal (MdmSignalHandler *handler, int signal_number) { struct sigaction action; struct sigaction *old_action; g_debug ("MdmSignalHandler: Registering for %d signals", signal_number); action.sa_handler = signal_handler; sigemptyset (&action.sa_mask); action.sa_flags = 0; old_action = g_new0 (struct sigaction, 1); sigaction (signal_number, &action, old_action); g_hash_table_insert (handler->priv->action_lookup, GINT_TO_POINTER (signal_number), old_action); } static void uncatch_signal (MdmSignalHandler *handler, int signal_number) { struct sigaction *old_action; g_debug ("MdmSignalHandler: Unregistering for %d signals", signal_number); old_action = g_hash_table_lookup (handler->priv->action_lookup, GINT_TO_POINTER (signal_number)); g_hash_table_remove (handler->priv->action_lookup, GINT_TO_POINTER (signal_number)); sigaction (signal_number, old_action, NULL); g_free (old_action); } guint mdm_signal_handler_add (MdmSignalHandler *handler, int signal_number, MdmSignalHandlerFunc callback, gpointer data) { CallbackData *cdata; GSList *list; g_return_val_if_fail (MDM_IS_SIGNAL_HANDLER (handler), 0); cdata = g_new0 (CallbackData, 1); cdata->signal_number = signal_number; cdata->func = callback; cdata->data = data; cdata->id = handler->priv->next_id++; g_debug ("MdmSignalHandler: Adding handler %u: signum=%d %p", cdata->id, cdata->signal_number, cdata->func); if (g_hash_table_lookup (handler->priv->action_lookup, GINT_TO_POINTER (signal_number)) == NULL) { catch_signal (handler, signal_number); } /* ID lookup owns the CallbackData */ g_hash_table_insert (handler->priv->id_lookup, GUINT_TO_POINTER (cdata->id), cdata); list = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (signal_number)); list = g_slist_prepend (list, GUINT_TO_POINTER (cdata->id)); g_hash_table_insert (handler->priv->lookup, GINT_TO_POINTER (signal_number), list); return cdata->id; } void mdm_signal_handler_add_fatal (MdmSignalHandler *handler) { g_return_if_fail (MDM_IS_SIGNAL_HANDLER (handler)); mdm_signal_handler_add (handler, SIGILL, NULL, NULL); mdm_signal_handler_add (handler, SIGBUS, NULL, NULL); /* mdm_signal_handler_add (handler, SIGSEGV, NULL, NULL); */ mdm_signal_handler_add (handler, SIGABRT, NULL, NULL); mdm_signal_handler_add (handler, SIGTRAP, NULL, NULL); } static void callback_data_free (CallbackData *d) { g_free (d); } static void mdm_signal_handler_remove_and_free_data (MdmSignalHandler *handler, CallbackData *cdata) { GSList *list; g_return_if_fail (MDM_IS_SIGNAL_HANDLER (handler)); list = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (cdata->signal_number)); list = g_slist_remove_all (list, GUINT_TO_POINTER (cdata->id)); if (list == NULL) { uncatch_signal (handler, cdata->signal_number); } g_debug ("MdmSignalHandler: Removing handler %u: signum=%d %p", cdata->signal_number, cdata->id, cdata->func); /* put changed list back in */ g_hash_table_insert (handler->priv->lookup, GINT_TO_POINTER (cdata->signal_number), list); g_hash_table_remove (handler->priv->id_lookup, GUINT_TO_POINTER (cdata->id)); } void mdm_signal_handler_remove (MdmSignalHandler *handler, guint id) { CallbackData *found; g_return_if_fail (MDM_IS_SIGNAL_HANDLER (handler)); found = g_hash_table_lookup (handler->priv->id_lookup, GUINT_TO_POINTER (id)); if (found != NULL) { mdm_signal_handler_remove_and_free_data (handler, found); found = NULL; } } static CallbackData * find_callback_data_by_func (MdmSignalHandler *handler, guint signal_number, MdmSignalHandlerFunc callback, gpointer data) { GSList *list; GSList *l; CallbackData *found; found = NULL; list = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (signal_number)); for (l = list; l != NULL; l = l->next) { guint id; CallbackData *d; id = GPOINTER_TO_UINT (l->data); d = g_hash_table_lookup (handler->priv->id_lookup, GUINT_TO_POINTER (id)); if (d != NULL && d->func == callback && d->data == data) { found = d; break; } } return found; } void mdm_signal_handler_remove_func (MdmSignalHandler *handler, guint signal_number, MdmSignalHandlerFunc callback, gpointer data) { CallbackData *found; g_return_if_fail (MDM_IS_SIGNAL_HANDLER (handler)); found = find_callback_data_by_func (handler, signal_number, callback, data); if (found != NULL) { mdm_signal_handler_remove_and_free_data (handler, found); found = NULL; } /* FIXME: once all handlers are removed deregister signum handler */ } static void mdm_signal_handler_class_init (MdmSignalHandlerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = mdm_signal_handler_finalize; g_type_class_add_private (klass, sizeof (MdmSignalHandlerPrivate)); } static void signal_list_free (GSList *list) { g_slist_free (list); } void mdm_signal_handler_set_fatal_func (MdmSignalHandler *handler, MdmShutdownHandlerFunc func, gpointer user_data) { g_return_if_fail (MDM_IS_SIGNAL_HANDLER (handler)); handler->priv->fatal_func = func; handler->priv->fatal_data = user_data; } static void mdm_signal_handler_init (MdmSignalHandler *handler) { GIOChannel *ioc; handler->priv = MDM_SIGNAL_HANDLER_GET_PRIVATE (handler); handler->priv->next_id = 1; handler->priv->lookup = g_hash_table_new (NULL, NULL); handler->priv->id_lookup = g_hash_table_new (NULL, NULL); handler->priv->action_lookup = g_hash_table_new (NULL, NULL); if (pipe (signal_pipes) == -1) { g_error ("Could not create pipe() for signal handling"); } ioc = g_io_channel_unix_new (signal_pipes[0]); g_io_channel_set_flags (ioc, G_IO_FLAG_NONBLOCK, NULL); g_io_add_watch_full (ioc, G_PRIORITY_HIGH, G_IO_IN, (GIOFunc) signal_io_watch, handler, NULL); g_io_channel_set_close_on_unref (ioc, TRUE); g_io_channel_unref (ioc); } static void mdm_signal_handler_finalize (GObject *object) { MdmSignalHandler *handler; GList *l; g_return_if_fail (object != NULL); g_return_if_fail (MDM_IS_SIGNAL_HANDLER (object)); handler = MDM_SIGNAL_HANDLER (object); g_debug ("MdmSignalHandler: Finalizing signal handler"); g_return_if_fail (handler->priv != NULL); for (l = g_hash_table_get_values (handler->priv->lookup); l != NULL; l = l->next) { signal_list_free ((GSList *) l->data); } g_hash_table_destroy (handler->priv->lookup); for (l = g_hash_table_get_values (handler->priv->id_lookup); l != NULL; l = l->next) { callback_data_free ((CallbackData *) l->data); } g_hash_table_destroy (handler->priv->id_lookup); for (l = g_hash_table_get_values (handler->priv->action_lookup); l != NULL; l = l->next) { g_free (l->data); } g_hash_table_destroy (handler->priv->action_lookup); close (signal_pipes [0]); close (signal_pipes [1]); G_OBJECT_CLASS (mdm_signal_handler_parent_class)->finalize (object); } MdmSignalHandler * mdm_signal_handler_new (void) { if (signal_handler_object != NULL) { g_object_ref (signal_handler_object); } else { signal_handler_object = g_object_new (MDM_TYPE_SIGNAL_HANDLER, NULL); g_object_add_weak_pointer (signal_handler_object, (gpointer *) &signal_handler_object); } return MDM_SIGNAL_HANDLER (signal_handler_object); } cinnamon-session-3.6.1/cinnamon-session/mdm-signal-handler.h0000644000175000017500000000677613205266677022657 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2007 William Jon McCann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. * */ #ifndef __MDM_SIGNAL_HANDLER_H #define __MDM_SIGNAL_HANDLER_H #include G_BEGIN_DECLS #define MDM_TYPE_SIGNAL_HANDLER (mdm_signal_handler_get_type ()) #define MDM_SIGNAL_HANDLER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MDM_TYPE_SIGNAL_HANDLER, MdmSignalHandler)) #define MDM_SIGNAL_HANDLER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), MDM_TYPE_SIGNAL_HANDLER, MdmSignalHandlerClass)) #define MDM_IS_SIGNAL_HANDLER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MDM_TYPE_SIGNAL_HANDLER)) #define MDM_IS_SIGNAL_HANDLER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), MDM_TYPE_SIGNAL_HANDLER)) #define MDM_SIGNAL_HANDLER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), MDM_TYPE_SIGNAL_HANDLER, MdmSignalHandlerClass)) typedef gboolean (*MdmSignalHandlerFunc) (int signal, gpointer data); typedef void (*MdmShutdownHandlerFunc) (gpointer data); typedef struct MdmSignalHandlerPrivate MdmSignalHandlerPrivate; typedef struct { GObject parent; MdmSignalHandlerPrivate *priv; } MdmSignalHandler; typedef struct { GObjectClass parent_class; } MdmSignalHandlerClass; GType mdm_signal_handler_get_type (void); MdmSignalHandler * mdm_signal_handler_new (void); void mdm_signal_handler_set_fatal_func (MdmSignalHandler *handler, MdmShutdownHandlerFunc func, gpointer user_data); void mdm_signal_handler_add_fatal (MdmSignalHandler *handler); guint mdm_signal_handler_add (MdmSignalHandler *handler, int signal_number, MdmSignalHandlerFunc callback, gpointer data); void mdm_signal_handler_remove (MdmSignalHandler *handler, guint id); void mdm_signal_handler_remove_func (MdmSignalHandler *handler, guint signal_number, MdmSignalHandlerFunc callback, gpointer data); G_END_DECLS #endif /* __MDM_SIGNAL_HANDLER_H */ cinnamon-session-3.6.1/cinnamon-session/mdm.c0000644000175000017500000003042613205266677017751 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2005 Raffaele Sandrini * Copyright (C) 2005 Red Hat, Inc. * Copyright (C) 2002, 2003 George Lebl * Copyright (C) 2001 Queen of England, * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Authors: * Raffaele Sandrini * George Lebl * Mark McLoughlin */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "mdm.h" #define MDM_PROTOCOL_UPDATE_INTERVAL 1 /* seconds */ #define MDM_PROTOCOL_SOCKET_PATH "/var/run/gdm_socket" #define MDM_PROTOCOL_MSG_CLOSE "CLOSE" #define MDM_PROTOCOL_MSG_VERSION "VERSION" #define MDM_PROTOCOL_MSG_AUTHENTICATE "AUTH_LOCAL" #define MDM_PROTOCOL_MSG_QUERY_ACTION "QUERY_LOGOUT_ACTION" #define MDM_PROTOCOL_MSG_SET_ACTION "SET_SAFE_LOGOUT_ACTION" #define MDM_PROTOCOL_MSG_FLEXI_XSERVER "FLEXI_XSERVER" #define MDM_ACTION_STR_NONE "NONE" #define MDM_ACTION_STR_SHUTDOWN "HALT" #define MDM_ACTION_STR_REBOOT "REBOOT" #define MDM_ACTION_STR_SUSPEND "SUSPEND" typedef struct { int fd; char *auth_cookie; MdmLogoutAction available_actions; MdmLogoutAction current_actions; time_t last_update; } MdmProtocolData; static MdmProtocolData mdm_protocol_data = { 0, NULL, MDM_LOGOUT_ACTION_NONE, MDM_LOGOUT_ACTION_NONE, 0 }; static char * mdm_send_protocol_msg (MdmProtocolData *data, const char *msg) { GString *retval; char buf[256]; char *p; int len; p = g_strconcat (msg, "\n", NULL); if (write (data->fd, p, strlen (p)) < 0) { g_free (p); g_warning ("Failed to send message to MDM: %s", g_strerror (errno)); return NULL; } g_free (p); p = NULL; retval = NULL; while ((len = read (data->fd, buf, sizeof (buf) - 1)) > 0) { buf[len] = '\0'; if (!retval) { retval = g_string_new (buf); } else { retval = g_string_append (retval, buf); } if ((p = strchr (retval->str, '\n'))) { break; } } if (p) { *p = '\0'; } return retval ? g_string_free (retval, FALSE) : NULL; } static char * get_display_number (void) { const char *display_name; char *retval; char *p; display_name = gdk_display_get_name (gdk_display_get_default ()); p = strchr (display_name, ':'); if (!p) { return g_strdup ("0"); } while (*p == ':') { p++; } retval = g_strdup (p); p = strchr (retval, '.'); if (p != NULL) { *p = '\0'; } return retval; } static gboolean mdm_authenticate_connection (MdmProtocolData *data) { #define MDM_MIT_MAGIC_COOKIE_LEN 16 const char *xau_path; FILE *f; Xauth *xau; char *display_number; gboolean retval; if (data->auth_cookie) { char *msg; char *response; msg = g_strdup_printf (MDM_PROTOCOL_MSG_AUTHENTICATE " %s", data->auth_cookie); response = mdm_send_protocol_msg (data, msg); g_free (msg); if (response && !strcmp (response, "OK")) { g_free (response); return TRUE; } else { g_free (response); g_free (data->auth_cookie); data->auth_cookie = NULL; } } if (!(xau_path = XauFileName ())) { return FALSE; } if (!(f = fopen (xau_path, "r"))) { return FALSE; } retval = FALSE; display_number = get_display_number (); while ((xau = XauReadAuth (f))) { char buffer[40]; /* 2*16 == 32, so 40 is enough */ char *msg; char *response; int i; if (xau->family != FamilyLocal || strncmp (xau->number, display_number, xau->number_length) || strncmp (xau->name, "MIT-MAGIC-COOKIE-1", xau->name_length) || xau->data_length != MDM_MIT_MAGIC_COOKIE_LEN) { XauDisposeAuth (xau); continue; } for (i = 0; i < MDM_MIT_MAGIC_COOKIE_LEN; i++) { g_snprintf (buffer + 2*i, 3, "%02x", (guint)(guchar)xau->data[i]); } XauDisposeAuth (xau); msg = g_strdup_printf (MDM_PROTOCOL_MSG_AUTHENTICATE " %s", buffer); response = mdm_send_protocol_msg (data, msg); g_free (msg); if (response && !strcmp (response, "OK")) { data->auth_cookie = g_strdup (buffer); g_free (response); retval = TRUE; break; } g_free (response); } g_free (display_number); fclose (f); return retval; #undef MDM_MIT_MAGIC_COOKIE_LEN } static void mdm_shutdown_protocol_connection (MdmProtocolData *data) { if (data->fd) { close (data->fd); } data->fd = 0; } static gboolean mdm_init_protocol_connection (MdmProtocolData *data) { struct sockaddr_un addr; char *response; g_assert (data->fd <= 0); if (g_file_test (MDM_PROTOCOL_SOCKET_PATH, G_FILE_TEST_EXISTS)) { strcpy (addr.sun_path, MDM_PROTOCOL_SOCKET_PATH); } else if (g_file_test ("/tmp/.mdm_socket", G_FILE_TEST_EXISTS)) { strcpy (addr.sun_path, "/tmp/.mdm_socket"); } else { return FALSE; } data->fd = socket (AF_UNIX, SOCK_STREAM, 0); if (data->fd < 0) { g_warning ("Failed to create MDM socket: %s", g_strerror (errno)); mdm_shutdown_protocol_connection (data); return FALSE; } addr.sun_family = AF_UNIX; if (connect (data->fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { g_warning ("Failed to establish a connection with MDM: %s", g_strerror (errno)); mdm_shutdown_protocol_connection (data); return FALSE; } response = mdm_send_protocol_msg (data, MDM_PROTOCOL_MSG_VERSION); if (!response || strncmp (response, "MDM ", strlen ("MDM ")) != 0) { g_free (response); g_warning ("Failed to get protocol version from MDM"); mdm_shutdown_protocol_connection (data); return FALSE; } g_free (response); if (!mdm_authenticate_connection (data)) { g_warning ("Failed to authenticate with MDM"); mdm_shutdown_protocol_connection (data); return FALSE; } return TRUE; } static void mdm_parse_query_response (MdmProtocolData *data, const char *response) { char **actions; int i; data->available_actions = MDM_LOGOUT_ACTION_NONE; data->current_actions = MDM_LOGOUT_ACTION_NONE; if (strncmp (response, "OK ", 3) != 0) { return; } response += 3; actions = g_strsplit (response, ";", -1); for (i = 0; actions[i]; i++) { MdmLogoutAction action = MDM_LOGOUT_ACTION_NONE; gboolean selected = FALSE; char *str = actions [i]; int len; len = strlen (str); if (!len) { continue; } if (str[len - 1] == '!') { selected = TRUE; str[len - 1] = '\0'; } if (!strcmp (str, MDM_ACTION_STR_SHUTDOWN)) { action = MDM_LOGOUT_ACTION_SHUTDOWN; } else if (!strcmp (str, MDM_ACTION_STR_REBOOT)) { action = MDM_LOGOUT_ACTION_REBOOT; } else if (!strcmp (str, MDM_ACTION_STR_SUSPEND)) { action = MDM_LOGOUT_ACTION_SUSPEND; } data->available_actions |= action; if (selected) { data->current_actions |= action; } } g_strfreev (actions); } static void mdm_update_logout_actions (MdmProtocolData *data) { time_t current_time; char *response; current_time = time (NULL); if (current_time <= (data->last_update + MDM_PROTOCOL_UPDATE_INTERVAL)) { return; } data->last_update = current_time; if (!mdm_init_protocol_connection (data)) { return; } if ((response = mdm_send_protocol_msg (data, MDM_PROTOCOL_MSG_QUERY_ACTION))) { mdm_parse_query_response (data, response); g_free (response); } mdm_shutdown_protocol_connection (data); } gboolean mdm_is_available (void) { if (!mdm_init_protocol_connection (&mdm_protocol_data)) { return FALSE; } mdm_shutdown_protocol_connection (&mdm_protocol_data); return TRUE; } gboolean mdm_supports_logout_action (MdmLogoutAction action) { mdm_update_logout_actions (&mdm_protocol_data); return (mdm_protocol_data.available_actions & action) != 0; } MdmLogoutAction mdm_get_logout_action (void) { mdm_update_logout_actions (&mdm_protocol_data); return mdm_protocol_data.current_actions; } void mdm_set_logout_action (MdmLogoutAction action) { char *action_str = NULL; char *msg; char *response; if (!mdm_init_protocol_connection (&mdm_protocol_data)) { return; } switch (action) { case MDM_LOGOUT_ACTION_NONE: action_str = MDM_ACTION_STR_NONE; break; case MDM_LOGOUT_ACTION_SHUTDOWN: action_str = MDM_ACTION_STR_SHUTDOWN; break; case MDM_LOGOUT_ACTION_REBOOT: action_str = MDM_ACTION_STR_REBOOT; break; case MDM_LOGOUT_ACTION_SUSPEND: action_str = MDM_ACTION_STR_SUSPEND; break; } msg = g_strdup_printf (MDM_PROTOCOL_MSG_SET_ACTION " %s", action_str); response = mdm_send_protocol_msg (&mdm_protocol_data, msg); g_free (msg); g_free (response); mdm_protocol_data.last_update = 0; mdm_shutdown_protocol_connection (&mdm_protocol_data); } void mdm_new_login (void) { char *response; if (!mdm_init_protocol_connection (&mdm_protocol_data)) { return; } response = mdm_send_protocol_msg (&mdm_protocol_data, MDM_PROTOCOL_MSG_FLEXI_XSERVER); g_free (response); mdm_protocol_data.last_update = 0; mdm_shutdown_protocol_connection (&mdm_protocol_data); } cinnamon-session-3.6.1/cinnamon-session/mdm.h0000644000175000017500000000320113205266677017745 0ustar maxymaxy/* mdm.h * Copyright (C) 2005 Raffaele Sandrini * Copyright (C) 2005 Red Hat, Inc. * Copyright (C) 2002, 2003 George Lebl * Copyright (C) 2001 Queen of England, * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * * Authors: * Raffaele Sandrini * George Lebl * Mark McLoughlin */ #ifndef __MDM_LOGOUT_ACTION_H__ #define __MDM_LOGOUT_ACTION_H__ #include G_BEGIN_DECLS typedef enum { MDM_LOGOUT_ACTION_NONE = 0, MDM_LOGOUT_ACTION_SHUTDOWN = 1 << 0, MDM_LOGOUT_ACTION_REBOOT = 1 << 1, MDM_LOGOUT_ACTION_SUSPEND = 1 << 2 } MdmLogoutAction; gboolean mdm_is_available (void); void mdm_new_login (void); void mdm_set_logout_action (MdmLogoutAction action); MdmLogoutAction mdm_get_logout_action (void); gboolean mdm_supports_logout_action (MdmLogoutAction action); G_END_DECLS #endif /* __MDM_LOGOUT_ACTION_H__ */ cinnamon-session-3.6.1/cinnamon-session/org.gnome.SessionManager.App.xml0000644000175000017500000000263613205266677025103 0ustar maxymaxy The identifier for the application Return the application ID. The startup identifier Return the startup ID associated with this application. The application startup phase Return the startup phase of this application. cinnamon-session-3.6.1/cinnamon-session/org.gnome.SessionManager.Client.xml0000644000175000017500000000457413205266677025604 0ustar maxymaxy The identifier for the associated application Return the application ID associated with this client. The startup identifier Return the startup ID associated with this client. The restart style hint Return the restart style hint for this client. The Unix process identifier Return the Unix process identifier for this client. The client status Return the status of this client. Inititate a request to terminate this application via XSMP. cinnamon-session-3.6.1/cinnamon-session/org.gnome.SessionManager.ClientPrivate.xml0000644000175000017500000001150713205266677027131 0ustar maxymaxy Whether or not it is OK to proceed The reason string This method should be used by the client in response to the QueryEndSession and EndSession signals. Stop client The client should stop and remove itself from the session in response to this signal. Flags This signal is used to inform the client that the session is about to end. The client must respond by calling EndSessionResponse within one second of the signal emission. The flags may include: 1 Logout is forced. EndSessionResponse reason and any inhibit from client will be ignored. If the client responds with an EndSessionResponse is-ok argument equal to FALSE and a reason then this reason may be displayed to the user. The client must not attempt to perform any actions or interact with the user in response to this signal. Any actions required for a clean shutdown should take place in response to the EndSession signal. The client should limit operations until either a EndSession CancelEndSession signal is received. Flags This signal is used to inform the client that the session is about to end. The client must respond by calling EndSessionResponse within ten seconds of the signal emission. The client must not attempt to interact with the user in response to this signal. The application will be given a maxium of ten seconds to perform any actions required for a clean shutdown. This signal indicates to the client that a previous emission of QueryEndSession has been cancelled. The client should resume normal operations. cinnamon-session-3.6.1/cinnamon-session/org.gnome.SessionManager.Inhibitor.xml0000644000175000017500000000447413205266677026314 0ustar maxymaxy The identifier for the associated application Return the application ID associated with this inhibit. The object path of the associated client Return the client object path associated with this inhibit. The reason for the inhibit Return the reason for the inhibit The flags that determine the scope of the inhibit Return the flags that determine the scope of the inhibit X11 toplevel window identifier associated with this inhibit. Zero if not set. Return the X11 toplevel window identifier associated with this inhibit. Zero if not set. cinnamon-session-3.6.1/cinnamon-session/org.gnome.SessionManager.Presence.xml0000644000175000017500000000574213205266677026130 0ustar maxymaxy The status of the session. The status parameter must be one of the following: 0 Available 1 Invisible 2 Busy 3 Idle The descriptive status for the session. The status value Set the status value of the session. The descriptive status for the session. Set the descriptive status text for the session. The new status value Indicates that the session status value has changed. The new status text Indicates that the descriptive session status text has changed. cinnamon-session-3.6.1/cinnamon-session/org.gnome.SessionManager.xml0000644000175000017500000003645113205266677024366 0ustar maxymaxy The variable name The value Adds the variable name to the application launch environment with the specified value. May only be used during the Session Manager initialization phase. The error message Whether the error should be treated as fatal May be used by applications launched during the Session Manager initialization phase to indicate there was a problem. The application identifier Client startup identifier The object path of the newly registered client Register the caller as a Session Management client. The object path of the client Unregister the specified client from Session Management. The application identifier The toplevel X window identifier The reason for the inhibit Flags that spefify what should be inhibited The cookie Proactively indicates that the calling application is performing an action that should not be interrupted and sets a reason to be displayed to the user when an interruption is about to take placea. Applications should invoke this method when they begin an operation that should not be interrupted, such as creating a CD or DVD. The types of actions that may be blocked are specified by the flags parameter. When the application completes the operation it should call Uninhibit() or disconnect from the session bus. Applications should not expect that they will always be able to block the action. In most cases, users will be given the option to force the action to take place. Reasons should be short and to the point. The flags parameter must include at least one of the following: 1 Inhibit logging out 2 Inhibit user switching 4 Inhibit suspending the session or computer 8 Inhibit the session being marked as idle 16 Inhibit auto-mounting removable media for the session Values for flags may be bitwise or'ed together. The returned cookie is used to uniquely identify this request. It should be used as an argument to Uninhibit() in order to remove the request. The cookie Cancel a previous call to Inhibit() identified by the cookie. Flags that spefify what should be inhibited Returns TRUE if any of the operations in the bitfield flags are inhibited Determine if operation(s) specified by the flags are currently inhibited. Flags are same as those accepted by the Inhibit() method. an array of client IDs This gets a list of all the Clients that are currently known to the session manager. Each Client ID is an D-Bus object path for the object that implements the Client interface. org.gnome.SessionManager.Client an array of inhibitor IDs This gets a list of all the Inhibitors that are currently known to the session manager. Each Inhibitor ID is an D-Bus object path for the object that implements the Inhibitor interface. org.gnome.SessionManager.Inhibitor The autostart condition string True if condition is handled, false otherwise Allows the caller to determine whether the session manager is handling changes to the specified autostart condition. Request a shutdown dialog. Request a reboot dialog. True if shutdown is available to the user, false otherwise Allows the caller to determine whether or not it's okay to show a shutdown option in the UI The type of logout that is being requested Request a logout dialog Allowed values for the mode parameter are: 0 Normal. 1 No confirmation inferface should be shown. 2 Forcefully logout. No confirmation will be shown and any inhibitors will be ignored. Values for flags may be bitwise or'ed together. True if the session has entered the Running phase, false otherwise Allows the caller to determine whether the session manager has entered the Running phase, in case the client missed the SessionRunning signal. Request a shutdown with no dialog Request a reboot with no dialog The object path for the added client Emitted when a client has been added to the session manager. The object path for the removed client Emitted when a client has been removed from the session manager. The object path for the added inhibitor Emitted when an inhibitor has been added to the session manager. The object path for the removed inhibitor Emitted when an inhibitor has been removed from the session manager. Indicates the session has entered the Running phase. Indicates the session is about to end. The name of the session that has been loaded. A bitmask of flags to indicate which actions are inhibited. See the Inhibit() function's description for a list of possible values. cinnamon-session-3.6.1/cinnamon-session/test-client-dbus.c0000644000175000017500000002042313205266677022356 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #define SM_DBUS_NAME "org.gnome.SessionManager" #define SM_DBUS_PATH "/org/gnome/SessionManager" #define SM_DBUS_INTERFACE "org.gnome.SessionManager" #define SM_CLIENT_DBUS_INTERFACE "org.gnome.SessionManager.ClientPrivate" static DBusGConnection *bus_connection = NULL; static DBusGProxy *sm_proxy = NULL; static char *client_id = NULL; static DBusGProxy *client_proxy = NULL; static GMainLoop *main_loop = NULL; static gboolean session_manager_connect (void) { if (bus_connection == NULL) { GError *error; error = NULL; bus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (bus_connection == NULL) { g_message ("Failed to connect to the session bus: %s", error->message); g_error_free (error); exit (1); } } sm_proxy = dbus_g_proxy_new_for_name (bus_connection, SM_DBUS_NAME, SM_DBUS_PATH, SM_DBUS_INTERFACE); return (sm_proxy != NULL); } static void on_client_query_end_session (DBusGProxy *proxy, guint flags, gpointer data) { GError *error; gboolean is_ok; gboolean res; const char *reason; is_ok = FALSE; reason = "Unsaved files"; g_debug ("Got query end session signal flags=%u", flags); error = NULL; res = dbus_g_proxy_call (proxy, "EndSessionResponse", &error, G_TYPE_BOOLEAN, is_ok, G_TYPE_STRING, reason, G_TYPE_INVALID, G_TYPE_INVALID); if (! res) { g_warning ("Failed to respond to EndSession: %s", error->message); g_error_free (error); } } static void on_client_end_session (DBusGProxy *proxy, guint flags, gpointer data) { g_debug ("Got end session signal flags=%u", flags); } static void on_client_cancel_end_session (DBusGProxy *proxy, gpointer data) { g_debug ("Got end session cancelled signal"); } static void on_client_stop (DBusGProxy *proxy, gpointer data) { g_debug ("Got client stop signal"); g_main_loop_quit (main_loop); } static gboolean register_client (void) { GError *error; gboolean res; const char *startup_id; const char *app_id; startup_id = g_getenv ("DESKTOP_AUTOSTART_ID"); app_id = "gedit"; error = NULL; res = dbus_g_proxy_call (sm_proxy, "RegisterClient", &error, G_TYPE_STRING, app_id, G_TYPE_STRING, startup_id, G_TYPE_INVALID, DBUS_TYPE_G_OBJECT_PATH, &client_id, G_TYPE_INVALID); if (! res) { g_warning ("Failed to register client: %s", error->message); g_error_free (error); return FALSE; } g_debug ("Client registered with session manager: %s", client_id); client_proxy = dbus_g_proxy_new_for_name (bus_connection, SM_DBUS_NAME, client_id, SM_CLIENT_DBUS_INTERFACE); dbus_g_proxy_add_signal (client_proxy, "QueryEndSession", G_TYPE_UINT, G_TYPE_INVALID); dbus_g_proxy_add_signal (client_proxy, "EndSession", G_TYPE_UINT, G_TYPE_INVALID); dbus_g_proxy_add_signal (client_proxy, "CancelEndSession", G_TYPE_UINT, G_TYPE_INVALID); dbus_g_proxy_add_signal (client_proxy, "Stop", G_TYPE_INVALID); dbus_g_proxy_connect_signal (client_proxy, "QueryEndSession", G_CALLBACK (on_client_query_end_session), NULL, NULL); dbus_g_proxy_connect_signal (client_proxy, "EndSession", G_CALLBACK (on_client_end_session), NULL, NULL); dbus_g_proxy_connect_signal (client_proxy, "CancelEndSession", G_CALLBACK (on_client_cancel_end_session), NULL, NULL); dbus_g_proxy_connect_signal (client_proxy, "Stop", G_CALLBACK (on_client_stop), NULL, NULL); return TRUE; } static gboolean session_manager_disconnect (void) { if (sm_proxy != NULL) { g_object_unref (sm_proxy); sm_proxy = NULL; } return TRUE; } static gboolean unregister_client (void) { GError *error; gboolean res; error = NULL; res = dbus_g_proxy_call (sm_proxy, "UnregisterClient", &error, DBUS_TYPE_G_OBJECT_PATH, client_id, G_TYPE_INVALID, G_TYPE_INVALID); if (! res) { g_warning ("Failed to unregister client: %s", error->message); g_error_free (error); return FALSE; } g_free (client_id); client_id = NULL; return TRUE; } static gboolean quit_test (gpointer data) { g_main_loop_quit (main_loop); return FALSE; } int main (int argc, char *argv[]) { gboolean res; g_log_set_always_fatal (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); res = session_manager_connect (); if (! res) { g_warning ("Unable to connect to session manager"); exit (1); } res = register_client (); if (! res) { g_warning ("Unable to register client with session manager"); } main_loop = g_main_loop_new (NULL, FALSE); g_timeout_add_seconds (30, quit_test, NULL); g_main_loop_run (main_loop); g_main_loop_unref (main_loop); unregister_client (); session_manager_disconnect (); return 0; } cinnamon-session-3.6.1/cinnamon-session/test-inhibit.c0000644000175000017500000001330713205266677021576 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * */ #include "config.h" #include #include #include #include #include #include #include #define SM_DBUS_NAME "org.gnome.SessionManager" #define SM_DBUS_PATH "/org/gnome/SessionManager" #define SM_DBUS_INTERFACE "org.gnome.SessionManager" static DBusGConnection *bus_connection = NULL; static DBusGProxy *sm_proxy = NULL; static guint cookie = 0; static gboolean session_manager_connect (void) { if (bus_connection == NULL) { GError *error; error = NULL; bus_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (bus_connection == NULL) { g_message ("Failed to connect to the session bus: %s", error->message); g_error_free (error); exit (1); } } sm_proxy = dbus_g_proxy_new_for_name (bus_connection, SM_DBUS_NAME, SM_DBUS_PATH, SM_DBUS_INTERFACE); return (sm_proxy != NULL); } typedef enum { CSM_INHIBITOR_FLAG_LOGOUT = 1 << 0, CSM_INHIBITOR_FLAG_SWITCH_USER = 1 << 1, CSM_INHIBITOR_FLAG_SUSPEND = 1 << 2 } CsmInhibitFlag; static gboolean do_inhibit_for_window (GdkWindow *window) { GError *error; gboolean res; const char *app_id; const char *reason; guint toplevel_xid; guint flags; #if 1 app_id = "nautilus-cd-burner"; reason = "A CD burn is in progress."; #else app_id = "nautilus"; reason = "A file transfer is in progress."; #endif toplevel_xid = gdk_x11_window_get_xid (window); flags = CSM_INHIBITOR_FLAG_LOGOUT | CSM_INHIBITOR_FLAG_SWITCH_USER | CSM_INHIBITOR_FLAG_SUSPEND; error = NULL; res = dbus_g_proxy_call (sm_proxy, "Inhibit", &error, G_TYPE_STRING, app_id, G_TYPE_UINT, toplevel_xid, G_TYPE_STRING, reason, G_TYPE_UINT, flags, G_TYPE_INVALID, G_TYPE_UINT, &cookie, G_TYPE_INVALID); if (! res) { g_warning ("Failed to inhibit: %s", error->message); g_error_free (error); return FALSE; } g_debug ("Inhibiting session manager: %u", cookie); return TRUE; } static gboolean session_manager_disconnect (void) { if (sm_proxy != NULL) { g_object_unref (sm_proxy); sm_proxy = NULL; } return TRUE; } static gboolean do_uninhibit (void) { GError *error; gboolean res; error = NULL; res = dbus_g_proxy_call (sm_proxy, "Uninhibit", &error, G_TYPE_UINT, cookie, G_TYPE_INVALID, G_TYPE_INVALID); if (! res) { g_warning ("Failed to uninhibit: %s", error->message); g_error_free (error); return FALSE; } cookie = 0; return TRUE; } static void on_widget_show (GtkWidget *dialog, gpointer data) { gboolean res; res = do_inhibit_for_window (gtk_widget_get_window (dialog)); if (! res) { g_warning ("Unable to register client with session manager"); } } int main (int argc, char *argv[]) { gboolean res; GtkWidget *dialog; g_log_set_always_fatal (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); gtk_init (&argc, &argv); res = session_manager_connect (); if (! res) { g_warning ("Unable to connect to session manager"); exit (1); } g_timeout_add_seconds (30, (GSourceFunc)gtk_main_quit, NULL); dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_CANCEL, "Inhibiting logout, switch user, and suspend."); g_signal_connect (dialog, "response", G_CALLBACK (gtk_main_quit), NULL); g_signal_connect (dialog, "show", G_CALLBACK (on_widget_show), NULL); gtk_widget_show (dialog); gtk_main (); do_uninhibit (); session_manager_disconnect (); return 0; } cinnamon-session-3.6.1/cinnamon-session/test-process-helper.c0000644000175000017500000000326613205266677023106 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * Copyright (C) 2010 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA * 02110-1335, USA. * */ #include #include #include "csm-process-helper.h" int main (int argc, char *argv[]) { char *command_line = "xeyes"; int timeout = 500; GError *error = NULL; if (argc > 3) { g_printerr ("Too many arguments.\n"); g_printerr ("Usage: %s [COMMAND] [TIMEOUT]\n", argv[0]); return 1; } if (argc >= 2) command_line = argv[1]; if (argc >= 3) { int i = atoi (argv[2]); if (i > 0) timeout = i; } if (!csm_process_helper (command_line, timeout, &error)) { g_warning ("%s", error->message); g_clear_error (&error); } else { g_print ("Command exited successfully.\n"); } return 0; } cinnamon-session-3.6.1/configure.ac0000644000175000017500000003261513205266677016035 0ustar maxymaxyAC_INIT([cinnamon-session], [3.6.1], [https://github.com/linuxmint/cinnamon-session/issues]) AC_CONFIG_SRCDIR([cinnamon-session]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) m4_ifdef([AX_IS_RELEASE], [AX_IS_RELEASE([always])]) AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz tar-ustar]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) # Check for programs AC_PROG_CC AM_PROG_CC_C_O AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal) PKG_PROG_PKG_CONFIG() # Initialize libtool LT_PREREQ([2.2.6]) LT_INIT([dlopen disable-static]) m4_ifdef([AX_COMPILER_FLAGS], [AX_COMPILER_FLAGS([WARN_CFLAGS],[WARN_LDFLAGS])]) AC_ARG_ENABLE(deprecation_flags, [AS_HELP_STRING([--enable-deprecation-flags], [use *_DISABLE_DEPRECATED flags @<:@default=no@:>@])],, [enable_deprecation_flags=no]) if test "x$enable_deprecation_flags" = "xyes"; then DISABLE_DEPRECATED_CFLAGS=$DISABLE_DEPRECATED AC_SUBST([DISABLE_DEPRECATED_CFLAGS]) fi GLIB_REQUIRED=2.37.3 GTK3_REQUIRED=3.0.0 DBUS_GLIB_REQUIRED=0.88 UPOWER_REQUIRED=0.9.0 dnl ==================================================================== dnl Dependency Checks dnl ==================================================================== dnl Standard vertical stacks PKG_CHECK_MODULES(GIO, gio-2.0) PKG_CHECK_MODULES(GTK3, gtk+-3.0 >= $GTK3_REQUIRED) PKG_CHECK_MODULES(CINNAMON_SESSION, glib-2.0 >= $GLIB_REQUIRED gio-2.0 >= $GLIB_REQUIRED gtk+-3.0 >= $GTK3_REQUIRED dbus-glib-1 >= $DBUS_GLIB_REQUIRED libcanberra ) dnl We can only support old upower dnl https://bugzilla.gnome.org/show_bug.cgi?id=710383 PKG_CHECK_MODULES(UPOWER, upower-glib < 0.99.0, have_old_upower=yes, have_old_upower=no) AS_IF([test x$have_old_upower = xyes], [ AC_DEFINE([HAVE_OLD_UPOWER], [1], [Define if we have an older upower]) ]) AM_CONDITIONAL(HAVE_OLD_UPOWER, test x$have_old_upower = xyes) PKG_CHECK_MODULES(SM, sm) PKG_CHECK_MODULES(ICE, ice) PKG_CHECK_MODULES(XEXT, xext xau) PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1 >= $DBUS_GLIB_REQUIRED) PKG_CHECK_MODULES(EGG_SMCLIENT, gtk+-3.0) PKG_CHECK_MODULES(GL_TEST, xcomposite gl) dnl ==================================================================== dnl Check for gconf dnl ==================================================================== AC_ARG_ENABLE([gconf], AS_HELP_STRING([--enable-gconf], [Support gconf-based autostart]), [enable_gconf=$enableval], [enable_gconf=auto]) PKG_CHECK_MODULES(GCONF, gconf-2.0, [have_gconf=yes], [have_gconf=no]) if test x$enable_gconf = xauto ; then enable_gconf=$have_gconf elif test x$enable_gconf = xyes -a x$have_gconf = xno ; then AC_MSG_ERROR([GConf support explicitly required, but gconf not found]) fi if test x$enable_gconf = xyes ; then AC_DEFINE([HAVE_GCONF], [1], [Define if we support gconf-based autostart]) fi dnl ==================================================================== dnl Check for logind dnl ==================================================================== PKG_CHECK_MODULES(LOGIND, [gio-unix-2.0 libsystemd-login], [have_logind=yes], [ PKG_CHECK_MODULES(LOGIND, [gio-unix-2.0 libsystemd], [have_logind=yes], [have_logind=no]) ]) if test x$have_logind = xyes; then AC_DEFINE(HAVE_LOGIND, 1, [Define if logind is supported]) fi AC_SUBST(LOGIND_CFLAGS) AC_SUBST(LOGIND_LIBS) dnl ==================================================================== dnl Option to disable DBus user session support. dnl ==================================================================== AC_ARG_ENABLE([dbus_user_session], AS_HELP_STRING([--disable-dbus-user-session], [Disable support for DBus user sessions]), [], [enable_dbus_user_session=yes]) if test x$enable_dbus_user_session = xyes; then AC_DEFINE(WITH_DBUS_USER_SESSION, 1, [Define to 1 if support for DBus user session is enabled]) else AC_DEFINE(WITH_DBUS_USER_SESSION, 0, [Define to 0 if support for DBus user session is disabled]) fi dnl ==================================================================== dnl Check for qt 5.7+ to set correct env var for theme/styling dnl ==================================================================== AC_ARG_ENABLE(qt57_theme_support, AS_HELP_STRING([--enable-qt57-theme-support], [Support GTK styles for QT apps with QT 5.7+]), [enable_qt57_theme_support=yes], [enable_qt57_theme_support=no]) if test x$enable_qt57_theme_support = xyes; then AC_DEFINE([HAVE_QT57], [1], [Have QT 5.7+]) else AC_DEFINE([HAVE_QT57], [0], [Have QT 5.7+]) fi dnl ==================================================================== dnl X development libraries check dnl ==================================================================== # If Pango included the shared library dependencies from X11 in # the pkg-config output, then we use that (to avoid duplicates). # but if they were omitted to avoid binary compatibility problems # then we need to repeat the checks. if $PKG_CONFIG --exists pangoxft ; then PANGO_PACKAGES="pangox pangoxft" else PANGO_PACKAGES="pangox" fi x_libs="`$PKG_CONFIG --libs $PANGO_PACKAGES`" case x_libs in *-lX11*) pango_omitted_x_deps=no ;; *) pango_omitted_x_deps=yes ;; esac if test $pango_omitted_x_deps = yes ; then AC_PATH_XTRA if test x$no_x = xyes ; then AC_MSG_ERROR([X development libraries not found]) else X_LIBS="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS" fi fi AC_CHECK_LIB(Xau, XauFileName, [X_LIBS="$X_LIBS -lXau"], [AC_MSG_ERROR([ *** Can't find the Xauth library. It is needed to compile cinnamon-session.])], $X_LIBS) AC_SUBST(X_LIBS) dnl ==================================================================== dnl Check for XSync extension dnl ==================================================================== have_xsync=no AC_CHECK_HEADER(X11/extensions/sync.h, [have_xsync=yes],, [#include ]) if test "$have_xsync" = yes; then AC_DEFINE(HAVE_XSYNC, 1, [Have the SYNC extension library]) fi dnl ==================================================================== dnl Check for XTest extension dnl ==================================================================== have_xtest=no PKG_CHECK_MODULES(XTEST, xtst, have_xtest=yes, have_xtest=no) if test "$have_xtest" = yes; then AC_DEFINE(HAVE_XTEST, 1, [Have the XTest extension library]) fi AC_SUBST(HAVE_XTEST) AC_SUBST(XTEST_CFLAGS) AC_SUBST(XTEST_LIBS) dnl ==================================================================== dnl XRender checks dnl ==================================================================== PKG_CHECK_MODULES(XRENDER, xrender, have_xrender=yes, have_xrender=no) AM_CONDITIONAL(HAVE_XRENDER, test x$have_xrender = xyes) if test $have_xrender=yes; then AC_DEFINE(HAVE_XRENDER, 1, [Have the Render X extension]) fi AC_SUBST(HAVE_XRENDER) AC_SUBST(XRENDER_CFLAGS) AC_SUBST(XRENDER_LIBS) dnl ==================================================================== dnl - DocBook Documentation dnl ==================================================================== AC_ARG_ENABLE(docbook-docs, [AS_HELP_STRING([--enable-docbook-docs], [build documentation (requires xmlto)])], [enable_docbook_docs=$enableval], [enable_docbook_docs=auto]) AC_PATH_PROG(XMLTO, xmlto, no) AC_MSG_CHECKING([whether to build DocBook documentation]) if test x$XMLTO = xno ; then have_docbook=no else have_docbook=yes fi if test x$enable_docbook_docs = xauto ; then if test x$have_docbook = xno ; then enable_docbook_docs=no else enable_docbook_docs=yes fi fi if test x$enable_docbook_docs = xyes; then if test x$have_docbook = xno; then AC_MSG_ERROR([Building DocBook docs explicitly required, but DocBook not found]) fi fi AM_CONDITIONAL(DOCBOOK_DOCS_ENABLED, test x$enable_docbook_docs = xyes) AC_MSG_RESULT($enable_docbook_docs) dnl ==================================================================== dnl Check for xsltproc dnl ==================================================================== AC_PATH_PROG([XSLTPROC], [xsltproc]) dnl ==================================================================== dnl Language Support dnl ==================================================================== IT_PROG_INTLTOOL([0.40.6]) GETTEXT_PACKAGE=cinnamon-session AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [The gettext translation domain]) AC_SUBST(GETTEXT_PACKAGE) AM_GLIB_GNU_GETTEXT GLIB_GSETTINGS dnl ==================================================================== dnl Headers dnl ==================================================================== AC_HEADER_STDC AC_CHECK_HEADERS(syslog.h tcpd.h sys/param.h) dnl ==================================================================== dnl check for backtrace support dnl ==================================================================== AC_CHECK_HEADERS(execinfo.h) AC_CHECK_LIB(execinfo, backtrace, [have_backtrace="yes"], [have_backtrace="no"]) EXECINFO_LIBS="" if test "x$have_backtrace" = "xyes"; then EXECINFO_LIBS="-lexecinfo" fi AC_SUBST(EXECINFO_LIBS) dnl ==================================================================== dnl Check for X transport interface - allows to disable ICE Transports dnl See also https://bugzilla.gnome.org/show_bug.cgi?id=725100 dnl ==================================================================== AC_ARG_WITH([xtrans], [AS_HELP_STRING([--without-xtrans], [Build without xtrans support (results in ICE listening on remote TCP ports)])], [], [with_xtrans=yes]) AS_IF([test "$with_xtrans" != "no"], [PKG_CHECK_MODULES(XTRANS, xtrans, [AC_DEFINE(HAVE_XTRANS, 1, [Have the X Transport library])])]) AC_SUBST(HAVE_XTRANS) dnl ==================================================================== dnl Code for checking whether IPv6 is enabled on the system.... dnl ==================================================================== AC_MSG_CHECKING([whether to enable ipv6]) AC_ARG_ENABLE(ipv6, [AS_HELP_STRING([--enable-ipv6], [enable IPv6 extensions])],, [enable_ipv6=yes]) have_full_ipv6=no if test $enable_ipv6 = yes; then dnl ==================================================================== dnl Code for checking presence of AF_INET6 on the system.... dnl ==================================================================== AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include #include ]], [[ socket(AF_INET6, SOCK_STREAM, 0) ]])], [have_ipv6=yes], [have_ipv6=no] ) AC_MSG_RESULT($have_ipv6) dnl ================================================================= dnl Now we would check for specific function like getaddrinfo. dnl ================================================================= have_getaddrinfo=no if test $have_ipv6=yes; then AC_CHECK_FUNC(getaddrinfo, have_getaddrinfo=yes) if test $have_getaddrinfo != yes; then # getaddrinfo is not in the default libraries. See if it's in some other. for lib in bsd socket inet; do AC_CHECK_LIB($lib, getaddrinfo, [LIBS="$LIBS -l$lib";have_getaddrinfo=yes; break]) done fi if test $have_getaddrinfo=yes; then AC_DEFINE(ENABLE_IPV6, 1, [Define if IPV6 is supported]) have_full_ipv6=yes fi fi fi dnl ============================================================================== dnl End of IPv6 checks dnl ============================================================================== AC_CONFIG_FILES([ Makefile doc/Makefile doc/dbus/Makefile doc/dbus/cinnamon-session.xml doc/man/Makefile data/Makefile data/org.cinnamon.SessionManager.gschema.xml data/icons/Makefile data/icons/16x16/Makefile data/icons/22x22/Makefile data/icons/24x24/Makefile data/icons/32x32/Makefile data/icons/48x48/Makefile data/icons/scalable/Makefile egg/Makefile cinnamon-session/Makefile tools/Makefile po/Makefile.in ]) AC_OUTPUT dnl --------------------------------------------------------------------------- dnl - Show summary dnl --------------------------------------------------------------------------- echo " cinnamon-session $VERSION `echo cinnamon-session $VERSION | sed "s/./=/g"` prefix: ${prefix} exec_prefix: ${exec_prefix} libdir: ${libdir} bindir: ${bindir} sbindir: ${sbindir} sysconfdir: ${sysconfdir} localstatedir: ${localstatedir} datadir: ${datadir} source code location: ${srcdir} compiler: ${CC} cflags: ${CFLAGS} Maintainer mode: ${USE_MAINTAINER_MODE} Use *_DISABLE_DEPRECATED: ${enable_deprecation_flags} GConf support: ${enable_gconf} Logind support: ${have_logind} DBus user session sup.: ${enable_dbus_user_session} Qt 5.7+ theme support: ${enable_qt57_theme_support} IPv6 support: ${have_full_ipv6} Backtrace support: ${have_backtrace} XRender support: ${have_xrender} XSync support: ${have_xsync} XTest support: ${have_xtest} Legacy UPower backend: ${have_old_upower} Build documentation: ${enable_docbook_docs} " cinnamon-session-3.6.1/data/0000755000175000017500000000000013205266677014451 5ustar maxymaxycinnamon-session-3.6.1/data/Makefile.am0000644000175000017500000000077413205266677016515 0ustar maxymaxySUBDIRS = icons uidir = $(pkgdatadir) ui_DATA = \ csm-inhibit-dialog.glade hwcompatdir = $(pkgdatadir) hwcompat_DATA = hardware-compatibility @INTLTOOL_DESKTOP_RULE@ @INTLTOOL_XML_NOMERGE_RULE@ gsettings_SCHEMAS = org.cinnamon.SessionManager.gschema.xml @GSETTINGS_RULES@ EXTRA_DIST = \ $(gsettings_SCHEMAS:.xml=.xml.in) \ $(ui_DATA) \ $(hwcompat_DATA) CLEANFILES = \ $(gsettings_SCHEMAS) \ $(desktop_DATA) DISTCLEANFILES = \ $(gsettings_SCHEMAS) -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/data/csm-inhibit-dialog.glade0000644000175000017500000000532413205266677021116 0ustar maxymaxy True False 6 6 True False Some programs are still running: True 0 False False 0 True True in 200 True True 3 False False False False False 1 True False Waiting for the program to finish. Interrupting the program may cause you to lose work. True 0 0 True True 2 cinnamon-session-3.6.1/data/hardware-compatibility0000644000175000017500000000125513205266677021043 0ustar maxymaxy## ## This file contains a list of blacklist/whitelist regular expressions for ## renderer strings. ## ## The regular expressions are case-insensitive POSIX Extended Regular ## Expressions. See regex(7) for details. ## ## Syntax: ## - Comment lines start with '#' ## - Lines starting with '+' are whitelisting. ## - Lines starting with '-' are blacklisting. ## - Lines not starting with '#', '+', '-' are ignored. ## # Intel 830-865 -Intel\(R\) 8[[:digit:]]{2,2}[^[:digit:]] # Intel IGD -Intel IGD # Pre-R300 radeon -Mesa DRI R[12]00[^[:digit:]] -Mesa DRI R[12]00$ # Old Mesa software GL renderer -software rasterizer # Gallium has softpipe and llvmpipe -softpipe #-llvmpipe cinnamon-session-3.6.1/data/icons/0000755000175000017500000000000013205266677015564 5ustar maxymaxycinnamon-session-3.6.1/data/icons/16x16/0000755000175000017500000000000013205266677016351 5ustar maxymaxycinnamon-session-3.6.1/data/icons/16x16/Makefile.am0000644000175000017500000000105613205266677020407 0ustar maxymaxysize = 16x16 iconsdir = $(datadir)/icons/hicolor/$(size)/apps icons_DATA = cinnamon-session-properties.png icons_SOURCE = cinnamon-session-properties.svg gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor install-data-hook: @-if test -z "$(DESTDIR)"; then \ echo "Updating Gtk icon cache."; \ $(gtk_update_icon_cache); \ else \ echo "*** Icon cache not updated. After install, run this:"; \ echo "*** $(gtk_update_icon_cache)"; \ fi EXTRA_DIST = \ $(icons_DATA) \ $(icons_SOURCE) -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/data/icons/16x16/cinnamon-session-properties.png0000644000175000017500000000112313205266677024531 0ustar maxymaxy‰PNG  IHDRóÿabKGDÿÿÿ ½§“tIME×'ì˨ÓõIDAT8•“ßK“QÇ?Ïû¾§·áØZV®¨."P¡¡Ã6»ñ&ˆaÎ ê*²Ë„þ€°uDtJP ºØMDt“ "Œ¢h" ¡ÖVé eîýÑÅœN×´ž«sxžÏ÷œïóœ#Wï „¿;ø‡DÈÌ1#z ©£+Þ…¦éU…u%–WŽëðúÝ«fcŸö¶vΞî#´Uš+:±äy¦¿äɼÈl轡P«la[Ó¶Dûx–IñõÛwº .]ø+ØàõÓs8Þ¹ÒÓÐÑ=>‚Ñ3ŒfÓÌ Þ„ÝGjì_FƇ™šJKc\ž©aˆœbÎõn  {|ø›Q(.â:Ö’€ªzH"Zz¶v×o€-‡Ž”-ˆ`+]ôDÛÎÕEk÷k­8ÌnŽXëOݶJö9pÿó?¹èJð’MŽù÷>‚þIEND®B`‚cinnamon-session-3.6.1/data/icons/16x16/cinnamon-session-properties.svg0000644000175000017500000003223013205266677024547 0ustar maxymaxy image/svg+xml Jakub Steiner http://jimmac.musichall.cz Gnome Session Properties cinnamon-session-3.6.1/data/icons/16x16/session-properties.png0000644000175000017500000000112313205266677022731 0ustar maxymaxy‰PNG  IHDRóÿabKGDÿÿÿ ½§“tIME×'ì˨ÓõIDAT8•“ßK“QÇ?Ïû¾§·áØZV®¨."P¡¡Ã6»ñ&ˆaÎ ê*²Ë„þ€°uDtJP ºØMDt“ "Œ¢h" ¡ÖVé eîýÑÅœN×´ž«sxžÏ÷œïóœ#Wï „¿;ø‡DÈÌ1#z ©£+Þ…¦éU…u%–WŽëðúÝ«fcŸö¶vΞî#´Uš+:±äy¦¿äɼÈl轡P«la[Ó¶Dûx–IñõÛwº .]ø+ØàõÓs8Þ¹ÒÓÐÑ=>‚Ñ3ŒfÓÌ Þ„ÝGjì_FƇ™šJKc\ž©aˆœbÎõn  {|ø›Q(.â:Ö’€ªzH"Zz¶v×o€-‡Ž”-ˆ`+]ôDÛÎÕEk÷k­8ÌnŽXëOݶJö9pÿó?¹èJð’MŽù÷>‚þIEND®B`‚cinnamon-session-3.6.1/data/icons/16x16/session-properties.svg0000644000175000017500000003223013205266677022747 0ustar maxymaxy image/svg+xml Jakub Steiner http://jimmac.musichall.cz Gnome Session Properties cinnamon-session-3.6.1/data/icons/22x22/0000755000175000017500000000000013205266677016343 5ustar maxymaxycinnamon-session-3.6.1/data/icons/22x22/Makefile.am0000644000175000017500000000105613205266677020401 0ustar maxymaxysize = 22x22 iconsdir = $(datadir)/icons/hicolor/$(size)/apps icons_DATA = cinnamon-session-properties.png icons_SOURCE = cinnamon-session-properties.svg gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor install-data-hook: @-if test -z "$(DESTDIR)"; then \ echo "Updating Gtk icon cache."; \ $(gtk_update_icon_cache); \ else \ echo "*** Icon cache not updated. After install, run this:"; \ echo "*** $(gtk_update_icon_cache)"; \ fi EXTRA_DIST = \ $(icons_DATA) \ $(icons_SOURCE) -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/data/icons/22x22/cinnamon-session-properties.png0000644000175000017500000000136213205266677024530 0ustar maxymaxy‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“tIME× 9X­-”IDAT8Õ“ËKTQÇ?çÜÇgR{Ù‹ˆ¨éB ­ÀÔŠ•Ö®ME´éhU‹ˆ\½ hgaT‚ h DhUTÚÙf¦{çÞ¹÷´ð9ŽåT´è ?Îïs~ç{~?øG§._}²,îÕ ¡/Y@ Ä8*Dðî³}÷ä‰#»Å–Ž%Ûª¾×ÕÔOÞ3+¹¨Ú&¤|ý\o®m¦7„Ý»ÄË©’!s~ȯ†p ™0nöŽ£¹Ef¨ ­ÐAa˜E‚5}O?r2h™…åêÀgäñµ¢+¶Ì)Ü4ØžÐ9Ä³ëø©‘¢Áö\`˘†¾Kb°“¦†Ú¢¡ãŒéWO™7ùŒÐwH tÒ¶g;·ï ¿¿—dßùy¡·r5R¯y`Û”„^š±ëÜÛJsS®ërö̹‰~)%B¤”yKã8\¸t‘·_šyVئäË‹[(Ãg{K ®ëâ8étšT*E*•"“Éàº.Ùlß÷ ‚€0 ÑZ£”bs}*7* <®¨ÙGÊ è¾ÝRŠòòrâñ8±XŒX,F4E)E$Á², تÀ0 ºÐ SÅ)«nç΃[aHÛ¾ý=v=GÏVD•°níºŸ^Ùˆêvî=ìbll ­5Ö†¶yÁž“døM?:—ÍÛ3$Z¹jòx° €ª5ç,XãU_77yù­¨"^s©*Š‚lÜÔȇh³ ¿ ÷” µ° Yp°´|)Ë V›¬Y©ËL =RKÖo•^. µnYѹ”Ìxt,0‡¾zéO§¯öÒãoÀíg¿½¿d&¬X Ø€õ‡\pщý¦çåŸ pK IEND®B`‚cinnamon-session-3.6.1/data/icons/22x22/cinnamon-session-properties.svg0000644000175000017500000004227613205266677024554 0ustar maxymaxy image/svg+xml Jakub Steiner http://jimmac.musichall.cz Gnome Session Properties cinnamon-session-3.6.1/data/icons/22x22/session-properties.png0000644000175000017500000000136213205266677022730 0ustar maxymaxy‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“tIME× 9X­-”IDAT8Õ“ËKTQÇ?çÜÇgR{Ù‹ˆ¨éB ­ÀÔŠ•Ö®ME´éhU‹ˆ\½ hgaT‚ h DhUTÚÙf¦{çÞ¹÷´ð9ŽåT´è ?Îïs~ç{~?øG§._}²,îÕ ¡/Y@ Ä8*Dðî³}÷ä‰#»Å–Ž%Ûª¾×ÕÔOÞ3+¹¨Ú&¤|ý\o®m¦7„Ý»ÄË©’!s~ȯ†p ™0nöŽ£¹Ef¨ ­ÐAa˜E‚5}O?r2h™…åêÀgäñµ¢+¶Ì)Ü4ØžÐ9Ä³ëø©‘¢Áö\`˘†¾Kb°“¦†Ú¢¡ãŒéWO™7ùŒÐwH tÒ¶g;·ï ¿¿—dßùy¡·r5R¯y`Û”„^š±ëÜÛJsS®ërö̹‰~)%B¤”yKã8\¸t‘·_šyVئäË‹[(Ãg{K ®ëâ8étšT*E*•"“Éàº.Ùlß÷ ‚€0 ÑZ£”bs}*7* <®¨ÙGÊ è¾ÝRŠòòrâñ8±XŒX,F4E)E$Á², تÀ0 ºÐ SÅ)«nç΃[aHÛ¾ý=v=GÏVD•°níºŸ^Ùˆêvî=ìbll ­5Ö†¶yÁž“døM?:—ÍÛ3$Z¹jòx° €ª5ç,XãU_77yù­¨"^s©*Š‚lÜÔȇh³ ¿ ÷” µ° Yp°´|)Ë V›¬Y©ËL =RKÖo•^. µnYѹ”Ìxt,0‡¾zéO§¯öÒãoÀíg¿½¿d&¬X Ø€õ‡\pщý¦çåŸ pK IEND®B`‚cinnamon-session-3.6.1/data/icons/22x22/session-properties.svg0000644000175000017500000004227613205266677022754 0ustar maxymaxy image/svg+xml Jakub Steiner http://jimmac.musichall.cz Gnome Session Properties cinnamon-session-3.6.1/data/icons/24x24/0000755000175000017500000000000013205266677016347 5ustar maxymaxycinnamon-session-3.6.1/data/icons/24x24/Makefile.am0000644000175000017500000000075413205266677020411 0ustar maxymaxysize = 24x24 iconsdir = $(datadir)/icons/hicolor/$(size)/apps icons_DATA = cinnamon-session-properties.png gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor install-data-hook: @-if test -z "$(DESTDIR)"; then \ echo "Updating Gtk icon cache."; \ $(gtk_update_icon_cache); \ else \ echo "*** Icon cache not updated. After install, run this:"; \ echo "*** $(gtk_update_icon_cache)"; \ fi EXTRA_DIST = \ $(icons_DATA) -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/data/icons/24x24/cinnamon-session-properties.png0000644000175000017500000000142013205266677024527 0ustar maxymaxy‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs  šœtIME×#åz‰<IDATHÇí•ÏKTQÇ?÷ý˜¹6Î8Z™ý""¬EºHB+(µ¢…E¦¹kSmúZÕ"¢A¿ hg‘T‚ h?( UQþÌ™f¦÷æ½yï¶ÐQÇgÊUÐçpyßÏ=çÜs/üë&²Î¹·^®Ž8õB¨?1%ç#ø2xtö̉ƒ3€—ï–\ÞSõ³®¶~.sŽHÑûƒÞ¨Û4À"Ð[éddÉQXlqó}x2Ïdc#ëÜëñF3+ _ý^"åeºQ$@Ñ÷jÌËÆÚÜEÓ ˆ»Œ¼¸]t¦‘#™ Ì[T‡Øë;¸‰‘¢Ŧ>ú®Ml°“ƆmÔSÏ­‚±Pz¾kè¤íÐöïÝG/ñ¾+Å=4ìŠ hj½X04|'ÉäÀ:·ÐÔØˆmÛ\¼piú¼ƒ¦i!Ð4-çB`YW¯_ãóð;#o&Þv!u—½ÍÍØ¶eY$“I‰‰D‚T*…mÛ¤Ói\×Åó<|ßG)…”’õ Ę̀–·åµ­$,îÝH)‰F£D"Âá0áp˜P(„”’`0ˆišèº>“€®ëTþ2BiM;Ÿváù>m­G8yê8J¾B‚²„êMÕ…›\º|-¢¦ÇÏî399‰R sK[A€cÅùø©•I“'ƒÙ#ªXµ¼¼@ÕÆ­EÓ²uaÞ÷u癃yC*¯"R{M–=[·ïæ[¨ÉÉL|ì)A)еß~X]Śݧ‹È`€´Q¡s¦D±¡ç²ró.ÍÉx´Ô­^ÒmO9””ãS€á¡ïNr¬óü­žc ¡/íSnúÇ×›@jþK± X ²éý…9€ ŒNûÿ­°ýfæ‹#¢¸dIEND®B`‚cinnamon-session-3.6.1/data/icons/24x24/session-properties.png0000644000175000017500000000142013205266677022727 0ustar maxymaxy‰PNG  IHDRàw=øbKGDÿÿÿ ½§“ pHYs  šœtIME×#åz‰<IDATHÇí•ÏKTQÇ?÷ý˜¹6Î8Z™ý""¬EºHB+(µ¢…E¦¹kSmúZÕ"¢A¿ hg‘T‚ h?( UQþÌ™f¦÷æ½yï¶ÐQÇgÊUÐçpyßÏ=çÜs/üë&²Î¹·^®Ž8õB¨?1%ç#ø2xtö̉ƒ3€—ï–\ÞSõ³®¶~.sŽHÑûƒÞ¨Û4À"Ð[éddÉQXlqó}x2Ïdc#ëÜëñF3+ _ý^"åeºQ$@Ñ÷jÌËÆÚÜEÓ ˆ»Œ¼¸]t¦‘#™ Ì[T‡Øë;¸‰‘¢Ŧ>ú®Ml°“ƆmÔSÏ­‚±Pz¾kè¤íÐöïÝG/ñ¾+Å=4ìŠ hj½X04|'ÉäÀ:·ÐÔØˆmÛ\¼piú¼ƒ¦i!Ð4-çB`YW¯_ãóð;#o&Þv!u—½ÍÍØ¶eY$“I‰‰D‚T*…mÛ¤Ói\×Åó<|ßG)…”’õ Ę̀–·åµ­$,îÝH)‰F£D"Âá0áp˜P(„”’`0ˆišèº>“€®ëTþ2BiM;Ÿváù>m­G8yê8J¾B‚²„êMÕ…›\º|-¢¦ÇÏî399‰R sK[A€cÅùø©•I“'ƒÙ#ªXµ¼¼@ÕÆ­EÓ²uaÞ÷u癃yC*¯"R{M–=[·ïæ[¨ÉÉL|ì)A)еß~X]Śݧ‹È`€´Q¡s¦D±¡ç²ró.ÍÉx´Ô­^ÒmO9””ãS€á¡ïNr¬óü­žc ¡/íSnúÇ×›@jþK± X ²éý…9€ ŒNûÿ­°ýfæ‹#¢¸dIEND®B`‚cinnamon-session-3.6.1/data/icons/32x32/0000755000175000017500000000000013205266677016345 5ustar maxymaxycinnamon-session-3.6.1/data/icons/32x32/Makefile.am0000644000175000017500000000105613205266677020403 0ustar maxymaxysize = 32x32 iconsdir = $(datadir)/icons/hicolor/$(size)/apps icons_DATA = cinnamon-session-properties.png icons_SOURCE = cinnamon-session-properties.svg gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor install-data-hook: @-if test -z "$(DESTDIR)"; then \ echo "Updating Gtk icon cache."; \ $(gtk_update_icon_cache); \ else \ echo "*** Icon cache not updated. After install, run this:"; \ echo "*** $(gtk_update_icon_cache)"; \ fi EXTRA_DIST = \ $(icons_DATA) \ $(icons_SOURCE) -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/data/icons/32x32/cinnamon-session-properties.png0000644000175000017500000000212513205266677024530 0ustar maxymaxy‰PNG  IHDR szzôbKGDÿÿÿ ½§“tIME×ýñͯ÷IDATX…å–ßOUÇ?wfÙ²¡ÛL“Š>hc‰‰o‚>™øøÚZ_|"Z~›&m…†Äc[MÓÐ(õA}1H°¦?BY~¤ÁØÚ„5B*° ,ÌîÎvgvö‡Dü&7÷ιçœï7çÞ9¹ð‡hûøJsÝSV·"›òÞ$[™·¾ÒÖqS6g–¤Óçß=Ñë8öL §¾îˆ¤ø”-g‘J–Šöøv¯Ý®nâDlbm˜q¹êÏ™ ! ²â€T[{µTMKšDÖPØlꛄ#€àú/KìS§()Ú“È =fòÙÀI“³:ýãÿy2÷¦Ö’&©ðÒçMïàò9¦es(2ÑÕÂ2—˜+=^¸¢«477ÄßÛÛ ¥Ùý<ød 0“g.bÛvNÄBμózÎB\éªlÛfâÁ\^rõMçJœ2Z–Å·Ýoíš$£(Š+&W8¹v¬€išì„¿ÞÀ¶-_mJÚÒ;ænpr%×VÓ4=Ç­Û·è»~••—=Ÿ ø¼* K©‹aY†adß&ºËÛ'O¡išËG–sodN.ÏF´}ÎqçÎmFF†éìø€úgë3ª”Ï%Üá7Ì<‚m„B#ŒÒÚÒŽ®ë¬­¯óÃßóóà@ÒG‘¨ˆx˜É¸•:3‘Ô Ö¿–)À©Ê)`t4ÄĽ Z[ÚÑ4h4Jðp+—>wsášÓ×¨ìøøŸ\úE¼²{ Ã`t,Ääo“´žnCÓ4t]`yyÙ•X’$dYöÛ{B„ÔÔÔòrCËÃÒ8.†mÛ¬„WèÿêKú¿øšX,–$ÿ§0 ƒ@`?E––ïU€àá 'Oœ¢£³ I’(-Í¡ÉçˆÄ“-qi3î€]TÆÕ«WˆD",,,ÒÙÕι³ ë:ååå®.èIâјlÛ¦¸¸ØeË0ïoHí–ƒúä*S÷‡hïêàüÙs¨ªÊôôÝ/ ÉÂ5yBQjkëø÷¹$Þf²wh‰?ÀÁ皘¹?DGW'/ôPV ,ª0‹îBçŇ‹ÈÚ(eÂT‚»;í$bú÷!ÞkyŸ¦ÆF*kŽâf|8a1VÏÿcž˜®TH€v®€SDõóMÌh*}}×0£‘¼Èd_åÕuÔ=¶mòûI`‡ç¯íã¥ê,)ªÑ^¨bôæO<]¤þÅlþÞxtèMf„á;á6–fFÚ/cd!•å–¢Eàæ`A$,myv¬Ø@1P°' Êœ›[s9^JÇï¹Çˆ°áóßâoÝ"—õVÂ,uIEND®B`‚cinnamon-session-3.6.1/data/icons/32x32/cinnamon-session-properties.svg0000644000175000017500000004664113205266677024556 0ustar maxymaxy image/svg+xml Jakub Steiner http://jimmac.musichall.cz Gnome Session Properties cinnamon-session-3.6.1/data/icons/32x32/session-properties.png0000644000175000017500000000212513205266677022730 0ustar maxymaxy‰PNG  IHDR szzôbKGDÿÿÿ ½§“tIME×ýñͯ÷IDATX…å–ßOUÇ?wfÙ²¡ÛL“Š>hc‰‰o‚>™øøÚZ_|"Z~›&m…†Äc[MÓÐ(õA}1H°¦?BY~¤ÁØÚ„5B*° ,ÌîÎvgvö‡Dü&7÷ιçœï7çÞ9¹ð‡hûøJsÝSV·"›òÞ$[™·¾ÒÖqS6g–¤Óçß=Ñë8öL §¾îˆ¤ø”-g‘J–Šöøv¯Ý®nâDlbm˜q¹êÏ™ ! ²â€T[{µTMKšDÖPØlꛄ#€àú/KìS§()Ú“È =fòÙÀI“³:ýãÿy2÷¦Ö’&©ðÒçMïàò9¦es(2ÑÕÂ2—˜+=^¸¢«477ÄßÛÛ ¥Ùý<ød 0“g.bÛvNÄBμózÎB\éªlÛfâÁ\^rõMçJœ2Z–Å·Ýoíš$£(Š+&W8¹v¬€išì„¿ÞÀ¶-_mJÚÒ;ænpr%×VÓ4=Ç­Û·è»~••—=Ÿ ø¼* K©‹aY†adß&ºËÛ'O¡išËG–sodN.ÏF´}ÎqçÎmFF†éìø€úgë3ª”Ï%Üá7Ì<‚m„B#ŒÒÚÒŽ®ë¬­¯óÃßóóà@ÒG‘¨ˆx˜É¸•:3‘Ô Ö¿–)À©Ê)`t4ÄĽ Z[ÚÑ4h4Jðp+—>wsášÓ×¨ìøøŸ\úE¼²{ Ã`t,Ääo“´žnCÓ4t]`yyÙ•X’$dYöÛ{B„ÔÔÔòrCËÃÒ8.†mÛ¬„WèÿêKú¿øšX,–$ÿ§0 ƒ@`?E––ïU€àá 'Oœ¢£³ I’(-Í¡ÉçˆÄ“-qi3î€]TÆÕ«WˆD",,,ÒÙÕι³ ë:ååå®.èIâјlÛ¦¸¸ØeË0ïoHí–ƒúä*S÷‡hïêàüÙs¨ªÊôôÝ/ ÉÂ5yBQjkëø÷¹$Þf²wh‰?ÀÁ皘¹?DGW'/ôPV ,ª0‹îBçŇ‹ÈÚ(eÂT‚»;í$bú÷!ÞkyŸ¦ÆF*kŽâf|8a1VÏÿcž˜®TH€v®€SDõóMÌh*}}×0£‘¼Èd_åÕuÔ=¶mòûI`‡ç¯íã¥ê,)ªÑ^¨bôæO<]¤þÅlþÞxtèMf„á;á6–fFÚ/cd!•å–¢Eàæ`A$,myv¬Ø@1P°' Êœ›[s9^JÇï¹Çˆ°áóßâoÝ"—õVÂ,uIEND®B`‚cinnamon-session-3.6.1/data/icons/32x32/session-properties.svg0000644000175000017500000004664113205266677022756 0ustar maxymaxy image/svg+xml Jakub Steiner http://jimmac.musichall.cz Gnome Session Properties cinnamon-session-3.6.1/data/icons/48x48/0000755000175000017500000000000013205266677016363 5ustar maxymaxycinnamon-session-3.6.1/data/icons/48x48/Makefile.am0000644000175000017500000000075413205266677020425 0ustar maxymaxysize = 48x48 iconsdir = $(datadir)/icons/hicolor/$(size)/apps icons_DATA = cinnamon-session-properties.png gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor install-data-hook: @-if test -z "$(DESTDIR)"; then \ echo "Updating Gtk icon cache."; \ $(gtk_update_icon_cache); \ else \ echo "*** Icon cache not updated. After install, run this:"; \ echo "*** $(gtk_update_icon_cache)"; \ fi EXTRA_DIST = \ $(icons_DATA) -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/data/icons/48x48/cinnamon-session-properties.png0000644000175000017500000000345713205266677024557 0ustar maxymaxy‰PNG  IHDR00Wù‡sBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<¬IDAThÕ™[lWÆçÌììz/^ß4<œ´Mí¸T@_P¥ª±ëˆR!Q$x€¾Ê%â¡â‘ )JÔ6icÓ4ªx ´TXj#Ò:% J¨Úò@Ó@Që¨@b;‰/õ®7ÞÙs³»ÞËìÌnìÆÉ'ì9gÎ9ß7ÿÿw.³Âí ¹ÙÖ‹[^€]úçàï&?™·^èN™Gl©­IB @4¾/–P0BÏ,Šã‰XäÛ?þÎw¡BÀÊ’óâŽmÉG¶tõáD¢õƒÑTê‹ý˼>š+p y¹eáòØ{ÿɼÜ_ „|í_½{ûNtA¡µþÈT7òÊÃËŠüŠ%½=ýë__BHcŒ.E@&ãí²§»•l¥”ïÀë%F°¦´î…H)‰µµ‘œ½$ðü[`Þ:¿pí®¹¶þþ­HyC-Ð4ŒÑÌ]ãÍw.Xó€™<;·œnÿGÛ}C—q"7çä”w5oŸcòì,T 0Æè/ïw…³ÓŠ¿ž?‡rÝÍäÙV$B²£IcŒÑP1 i‘êè#Û†áæ\)B^-—ÙUX)åMJ߃”Õ†¯`‰âÒ¤‚þÕbg/n·2 ‰Û˜Þå['E€€Zua°³Ù»w/RnœéµÖìß¿°‚" …—g­x@JÉ“GÞÜ´ÀO»?d¼êûú´B%Lÿo¾µë@p Ñò›4Æ0}qž8Váõ„@KšÖÌiŒáÕ§kiHA°ÂL¬MóæÜ·oƘŠÍßú6f ,)(¨µŽÂÌéà½1¥T¹L)…e]ÿ^Êc·†@!br˜9ïˆS¥‡ž}†<þ£–HW"4…Â?@ÔA"NŒd§·'YŽMþ!ZkœXËvZ¤ÚÆ`L’Xœzê)ò™þ{ù[««õî F+ŒÖH;†¦Q½’[¼ô§OO`UcBD€. ½x%€6ÀÅØÚ8-n ¤ä,–€YcŒ'(í¯Ûð´á…Hn&’E.ž€%`ʼn ¿mrQŒ0ÆlÚn­È˨6>d}ÜJø?á»x¤[ļ>IEND®B`‚cinnamon-session-3.6.1/data/icons/48x48/session-properties.png0000644000175000017500000000345713205266677022757 0ustar maxymaxy‰PNG  IHDR00Wù‡sBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<¬IDAThÕ™[lWÆçÌììz/^ß4<œ´Mí¸T@_P¥ª±ëˆR!Q$x€¾Ê%â¡â‘ )JÔ6icÓ4ªx ´TXj#Ò:% J¨Úò@Ó@Që¨@b;‰/õ®7ÞÙs³»ÞËìÌnìÆÉ'ì9gÎ9ß7ÿÿw.³Âí ¹ÙÖ‹[^€]úçàï&?™·^èN™Gl©­IB @4¾/–P0BÏ,Šã‰XäÛ?þÎw¡BÀÊ’óâŽmÉG¶tõáD¢õƒÑTê‹ý˼>š+p y¹eáòØ{ÿɼÜ_ „|í_½{ûNtA¡µþÈT7òÊÃËŠüŠ%½=ýë__BHcŒ.E@&ãí²§»•l¥”ïÀë%F°¦´î…H)‰µµ‘œ½$ðü[`Þ:¿pí®¹¶þþ­HyC-Ð4ŒÑÌ]ãÍw.Xó€™<;·œnÿGÛ}C—q"7çä”w5oŸcòì,T 0Æè/ïw…³ÓŠ¿ž?‡rÝÍäÙV$B²£IcŒÑP1 i‘êè#Û†áæ\)B^-—ÙUX)åMJ߃”Õ†¯`‰âÒ¤‚þÕbg/n·2 ‰Û˜Þå['E€€Zua°³Ù»w/RnœéµÖìß¿°‚" …—g­x@JÉ“GÞÜ´ÀO»?d¼êûú´B%Lÿo¾µë@p Ñò›4Æ0}qž8Váõ„@KšÖÌiŒáÕ§kiHA°ÂL¬MóæÜ·oƘŠÍßú6f ,)(¨µŽÂÌéà½1¥T¹L)…e]ÿ^Êc·†@!br˜9ïˆS¥‡ž}†<þ£–HW"4…Â?@ÔA"NŒd§·'YŽMþ!ZkœXËvZ¤ÚÆ`L’Xœzê)ò™þ{ù[««õî F+ŒÖH;†¦Q½’[¼ô§OO`UcBD€. ½x%€6ÀÅØÚ8-n ¤ä,–€YcŒ'(í¯Ûð´á…Hn&’E.ž€%`ʼn ¿mrQŒ0ÆlÚn­È˨6>d}ÜJø?á»x¤[ļ>IEND®B`‚cinnamon-session-3.6.1/data/icons/Makefile.am0000644000175000017500000000012013205266677017611 0ustar maxymaxySUBDIRS = 16x16 22x22 24x24 32x32 48x48 scalable -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/data/icons/scalable/0000755000175000017500000000000013205266677017332 5ustar maxymaxycinnamon-session-3.6.1/data/icons/scalable/Makefile.am0000644000175000017500000000075713205266677021377 0ustar maxymaxysize = scalable iconsdir = $(datadir)/icons/hicolor/$(size)/apps icons_DATA = cinnamon-session-properties.svg gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor install-data-hook: @-if test -z "$(DESTDIR)"; then \ echo "Updating Gtk icon cache."; \ $(gtk_update_icon_cache); \ else \ echo "*** Icon cache not updated. After install, run this:"; \ echo "*** $(gtk_update_icon_cache)"; \ fi EXTRA_DIST = \ $(icons_DATA) -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/data/icons/scalable/cinnamon-session-properties.svg0000644000175000017500000005120213205266677025530 0ustar maxymaxy image/svg+xml Jakub Steiner http://jimmac.musichall.cz Gnome Session Properties cinnamon-session-3.6.1/data/icons/scalable/session-properties.svg0000644000175000017500000005120213205266677023730 0ustar maxymaxy image/svg+xml Jakub Steiner http://jimmac.musichall.cz Gnome Session Properties cinnamon-session-3.6.1/data/org.cinnamon.SessionManager.gschema.xml.in0000644000175000017500000000525513205266677024522 0ustar maxymaxy false Show debug info If enabled, cinnamon-session will output debug information. false Save sessions If enabled, cinnamon-session will save the session automatically. true Logout prompt If enabled, cinnamon-session will prompt the user before ending a session. true Show the fallback warning If enabled, cinnamon-session will display a warning dialog after login if the session was automatically fallen back. ['gnome-settings-daemon', 'org.gnome.SettingsDaemon', 'gnome-fallback-mount-helper', 'gnome-screensaver', 'mate-screensaver', 'mate-keyring-daemon', 'indicator-session', 'gnome-initial-setup-copy-worker', 'gnome-initial-setup-first-login', 'gnome-welcome-tour', 'xscreensaver-autostart', 'nautilus-autostart', 'caja', 'xfce4-power-manager'] Applications to block from autostarting or appearing in the app system A list of applications or desktop names (without the .desktop extension) to prevent from being accessible during the session. false Toggles if there should be a timer when ending the session Toggles whether or not there's a timer to automatically end the current session 60 The time delay before quitting the system automatically The time delay before the shutdown/logout dialogue quits the system automatically false If your hardware and login service supports 'Hybrid Sleep' then use it instead of normal Suspend Whether or not to attempt to use hybrid sleep mode for suspend. If it is unsupported, normal sleep will be used instead cinnamon-session-3.6.1/debian/0000755000175000017500000000000013205266677014762 5ustar maxymaxycinnamon-session-3.6.1/doc/0000755000175000017500000000000013205266677014305 5ustar maxymaxycinnamon-session-3.6.1/doc/Makefile.am0000644000175000017500000000006213205266677016337 0ustar maxymaxySUBDIRS = dbus man -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/doc/dbus/0000755000175000017500000000000013205266677015242 5ustar maxymaxycinnamon-session-3.6.1/doc/dbus/Makefile.am0000644000175000017500000000403013205266677017273 0ustar maxymaxySPEC_XML_FILES = \ cinnamon-session.xml \ org.gnome.SessionManager.ref.xml \ org.gnome.SessionManager.Client.ref.xml \ org.gnome.SessionManager.ClientPrivate.ref.xml \ org.gnome.SessionManager.Inhibitor.ref.xml \ org.gnome.SessionManager.Presence.ref.xml if DOCBOOK_DOCS_ENABLED htmldocdir = $(docdir)/dbus htmldoc_DATA = cinnamon-session.html cinnamon-session.html: $(SPEC_XML_FILES) $(AM_V_GEN)$(XMLTO) xhtml-nochunks -m $(top_srcdir)/doc/dbus/config.xsl cinnamon-session.xml endif # DOCBOOK_DOCS_ENABLED org.gnome.SessionManager.ref.xml: $(top_srcdir)/cinnamon-session/org.gnome.SessionManager.xml spec-to-docbook.xsl $(AM_V_GEN)$(XSLTPROC) $(top_srcdir)/doc/dbus/spec-to-docbook.xsl $< | tail -n +2 > $@ org.gnome.SessionManager.Client.ref.xml: $(top_srcdir)/cinnamon-session/org.gnome.SessionManager.Client.xml spec-to-docbook.xsl $(AM_V_GEN)$(XSLTPROC) $(top_srcdir)/doc/dbus/spec-to-docbook.xsl $< | tail -n +2 > $@ org.gnome.SessionManager.ClientPrivate.ref.xml: $(top_srcdir)/cinnamon-session/org.gnome.SessionManager.ClientPrivate.xml spec-to-docbook.xsl $(AM_V_GEN)$(XSLTPROC) $(top_srcdir)/doc/dbus/spec-to-docbook.xsl $< | tail -n +2 > $@ org.gnome.SessionManager.Inhibitor.ref.xml: $(top_srcdir)/cinnamon-session/org.gnome.SessionManager.Inhibitor.xml spec-to-docbook.xsl $(AM_V_GEN)$(XSLTPROC) $(top_srcdir)/doc/dbus/spec-to-docbook.xsl $< | tail -n +2 > $@ org.gnome.SessionManager.Presence.ref.xml: $(top_srcdir)/cinnamon-session/org.gnome.SessionManager.Presence.xml spec-to-docbook.xsl $(AM_V_GEN)$(XSLTPROC) $(top_srcdir)/doc/dbus/spec-to-docbook.xsl $< | tail -n +2 > $@ BUILT_SOURCES = \ org.gnome.SessionManager.ref.xml \ org.gnome.SessionManager.Client.ref.xml \ org.gnome.SessionManager.ClientPrivate.ref.xml \ org.gnome.SessionManager.Inhibitor.ref.xml \ org.gnome.SessionManager.Presence.ref.xml CLEANFILES = \ $(BUILT_SOURCES) \ $(htmldoc_DATA) EXTRA_DIST = \ cinnamon-session.xml.in \ config.xsl \ docbook.css \ dbus-introspect-docs.dtd \ spec-to-docbook.xsl -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/doc/dbus/cinnamon-session.xml.in0000644000175000017500000000262113205266677021655 0ustar maxymaxy ]> Cinnamon Session @VERSION@ Documentation Version @VERSION@ Clement Lefebvre
root@linuxmint.com
Reference D-Bus API Reference This API is not yet stable and is likely to change in the future. &dbus-Manager; &dbus-Client; &dbus-ClientPrivate; &dbus-Inhibitor; &dbus-Presence; Index
cinnamon-session-3.6.1/doc/dbus/config.xsl0000644000175000017500000000040213205266677017233 0ustar maxymaxy cinnamon-session-3.6.1/doc/dbus/dbus-introspect-docs.dtd0000644000175000017500000000213713205266677022015 0ustar maxymaxy cinnamon-session-3.6.1/doc/dbus/docbook.css0000644000175000017500000000171113205266677017374 0ustar maxymaxybody { font-family: sans-serif; } h1.title { } .permission { color: #ee0000; text-decoration: underline; } .synopsis, .classsynopsis { background: #eeeeee; border: solid 1px #aaaaaa; padding: 0.5em; } .programlisting { background: #eeeeff; border: solid 1px #aaaaff; padding: 0.5em; } .variablelist { padding: 4px; margin-left: 3em; } .variablelist td:first-child { vertical-align: top; } td.shortcuts { color: #770000; font-size: 80%; } div.refnamediv { margin-top: 2em; } div.toc { border: 2em; } a { text-decoration: none; } a:hover { text-decoration: underline; color: #FF0000; } div.table table { border-collapse: collapse; border-spacing: 0px; border-style: solid; border-color: #777777; border-width: 1px; } div.table table td, div.table table th { border-style: solid; border-color: #777777; border-width: 1px; padding: 3px; vertical-align: top; } div.table table th { background-color: #eeeeee; } cinnamon-session-3.6.1/doc/dbus/spec-to-docbook.xsl0000644000175000017500000004727613205266677021002 0ustar maxymaxy interface Methods Signals Implemented Interfaces Objects implementing also implements org.freedesktop.DBus.Introspectable, org.freedesktop.DBus.Properties Properties Description Details Signal Details Property Details : <anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$interface"/>:<xsl:value-of select="@name"/></xsl:attribute></anchor>The "<xsl:value-of select="@name"/>" property '' : <anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$interface"/>::<xsl:value-of select="@name"/></xsl:attribute></anchor>The <xsl:value-of select="@name"/> signal () : Since /> is deprecated since version and should not be used in newly-written code. Use : :: . instead. See also: : Errors : Permissions <anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$interface"/>.<xsl:value-of select="@name"/></xsl:attribute></anchor><xsl:value-of select="@name"/> () () :'' ::() .() '' , '' , '' cinnamon-session-3.6.1/doc/man/0000755000175000017500000000000013205266677015060 5ustar maxymaxycinnamon-session-3.6.1/doc/man/Makefile.am0000644000175000017500000000017713205266677017121 0ustar maxymaxyman_MANS = \ cinnamon-session.1 \ cinnamon-session-quit.1 EXTRA_DIST = \ $(man_MANS) -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/doc/man/cinnamon-session-quit.10000644000175000017500000000155413205266677021412 0ustar maxymaxy.\" .\" cinnamon-session-quit manual page. .\" (C) 2000 Miguel de Icaza (miguel@helixcode.com) .\" (C) 2009-2010 Vincent Untz (vuntz@gnome.org) .\" .TH GNOME-SESSION-QUIT 1 "GNOME" .SH NAME cinnamon-session-quit \- End the current GNOME session .SH SYNOPSIS .B cinnamon-session-quit [\-\-logout|\-\-power-off|\-\-reboot] [\-\-force] [\-\-no-prompt] .SH DESCRIPTION The \fIcinnamon-session-quit\fP program can be used to end a GNOME session. .SH OPTIONS The following options are supported: .TP .I "--logout" Prompt the user to confirm logout. This is the default behavior. .TP .I "--power-off" Prompt the user to confirm system power off. .TP .I "--reboot" Prompt the user to confirm system reboot. .TP .I "--force" Ignore any inhibitors. .TP .I "--no-prompt" End the session without user interaction. This only works with \fI--logout\fP. .SH SEE ALSO .BR cinnamon-session(1) cinnamon-session-3.6.1/doc/man/cinnamon-session.10000644000175000017500000001057413205266677020434 0ustar maxymaxy.\" .\" cinnamon-session manual page. .\" (C) 2000 Miguel de Icaza (miguel@helixcode.com) .\" (C) 2009-2010 Vincent Untz (vuntz@gnome.org) .\" .TH GNOME-SESSION 1 "GNOME" .SH NAME cinnamon-session \- Start the GNOME desktop environment .SH SYNOPSIS .B cinnamon-session [\-a|\-\-autostart=DIR] [\-\-session=SESSION] [\-\-failsafe|\-f] [\-\-debug] [\-\-whale] .SH DESCRIPTION The \fIcinnamon-session\fP program starts up the GNOME desktop environment. This command is typically executed by your login manager (either mdm, xdm, or from your X startup scripts). It will load either your saved session, or it will provide a default session for the user as defined by the system administrator (or the default GNOME installation on your system). .PP The default session is defined in \fBgnome.session\fP, a .desktop-like file that is looked for in \fB$XDG_CONFIG_HOME/cinnamon-session/sessions\fP, \fB$XDG_CONFIG_DIRS/cinnamon-session/sessions\fP and \fB$XDG_DATA_DIRS/cinnamon-session/sessions\fP. .PP When saving a session, \fIcinnamon-session\fP saves the currently running applications in the \fB$XDG_CONFIG_HOME/cinnamon-session/saved-session\fP directory. .PP \fIcinnamon-session\fP is an X11R6 session manager. It can manage GNOME applications as well as any X11R6 SM compliant application. .SH OPTIONS The following options are supported: .TP .I "--autostart=DIR" Start all applications defined in \fIDIR\fP, instead of starting the applications defined in \fBgnome.session\fP, or via the \fI--session\fP option. Multiple \fI--autostart\fP options can be passed. .TP .I "--session=SESSION" Use the applications defined in \fBSESSION.session\fP. If not specified, \fBgnome.session\fP will be used. .TP .I "--failsafe" Run in fail-safe mode. User-specified applications will not be started. .TP .I "--debug" Enable debugging code. .TP .I "--whale" Show the fail whale in a dialog for debugging it. .SH SESSION DEFINITION Sessions are defined in \fB.session\fP files, that are using a .desktop-like format, with the following keys in the \fBGNOME Session\fP group: .TP .I Name Name of the session. This can be localized. .TP .I RequiredComponents List of component identifiers (desktop files) that are required by the session. The required components will always run in the session. .TP .I RequiredProviders List of task providers that are required by the session. A default provider for each task has to be defined with a \fIDefaultProvider-TASK\fP key; the provider can be overridden by required components, the saved session or autostart applications. The task providers will always run in the session. .TP .I DefaultProvider-TASK Identifier (desktop file) of the default provider for \fBTASK\fP. If no provider for \fBTASK\fP is found in the required components, the saved session and in the autostart applications, the default provider will be started. .PP Here is an example of a session definition: .PP .in +4n .nf [GNOME Session] Name=GNOME fallback RequiredComponents=gnome-panel;metacity;gnome-settings-daemon; RequiredProviders=notifications; DefaultProvider-notifications=notification-daemon .in .fi .PP The \fB.session\fP files are looked for in \fB$XDG_CONFIG_HOME/cinnamon-session/sessions\fP, \fB$XDG_CONFIG_DIRS/cinnamon-session/sessions\fP and \fB$XDG_DATA_DIRS/cinnamon-session/sessions\fP. .SH ENVIRONMENT \fIcinnamon-session\fP sets several environment variables for the use of its child processes: .PP .B SESSION_MANAGER .IP This variable is used by session-manager aware clients to contact cinnamon-session. .PP .B DISPLAY .IP This variable is set to the X display being used by \fIcinnamon-session\fP. Note that if the \fI--display\fP option is used this might be different from the setting of the environment variable when cinnamon-session is invoked. .SH FILES .PP .B $XDG_CONFIG_HOME/config/autostart .B $XDG_CONFIG_DIRS/config/autostart .B /usr/share/gnome/autostart .IP The applications defined in those directories will be started on login. \fIcinnamon-settings(1)\fP can be used to easily configure them. .PP .B $XDG_CONFIG_HOME/cinnamon-session/sessions .B $XDG_CONFIG_DIRS/cinnamon-session/sessions .B $XDG_DATA_DIRS/cinnamon-session/sessions .IP These directories contain the \fB.session\fP files that can be used with the \fI--session\fP option. .PP .B $XDG_CONFIG_HOME/cinnamon-session/saved-session .IP This directory contains the list of applications of the saved session. .SH SEE ALSO .BR cinnamon-settings(1) .BR cinnamon-session-quit(1) cinnamon-session-3.6.1/egg/0000755000175000017500000000000013205266677014302 5ustar maxymaxycinnamon-session-3.6.1/egg/Makefile.am0000644000175000017500000000251713205266677016343 0ustar maxymaxyplatform_defines = -DEGG_SM_CLIENT_BACKEND_XSMP platform_ltlibraries = \ libeggdesktopfile.la \ libeggsmclient-gnome.la platform_libs = \ libeggdesktopfile.la \ $(SM_LIBS) \ $(ICE_LIBS) platform_sources = eggsmclient-xsmp.c INCLUDES = \ -DG_LOG_DOMAIN=\""EggSMClient"\" \ $(platform_defines) \ $(EGG_SMCLIENT_CFLAGS) \ $(SM_CFLAGS) \ $(ICE_CFLAGS) \ $(WARN_CFLAGS) \ $(DISABLE_DEPRECATED_CFLAGS) noinst_LTLIBRARIES = \ libeggsmclient.la \ $(platform_ltlibraries) libeggsmclient_la_LIBADD = \ $(EGG_SMCLIENT_LIBS) \ $(SM_LIBS) \ $(ICE_LIBS) \ $(platform_libs) libeggsmclient_la_SOURCES = \ eggsmclient.c \ eggsmclient.h \ eggsmclient-private.h \ $(platform_sources) libeggsmclient_gnome_la_LIBADD = \ $(libeggsmclient_la_LIBADD) libeggsmclient_gnome_la_SOURCES = \ eggsmclient.c \ eggsmclient.h \ eggsmclient-private.h \ $(platform_sources) libeggdesktopfile_la_LIBADD = \ $(EGG_SMCLIENT_LIBS) libeggdesktopfile_la_SOURCES = \ eggdesktopfile.c \ eggdesktopfile.h -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/egg/eggdesktopfile.c0000644000175000017500000011605513205266677017452 0ustar maxymaxy/* eggdesktopfile.c - Freedesktop.Org Desktop Files * Copyright (C) 2007 Novell, Inc. * * Based on gnome-desktop-item.c * Copyright (C) 1999, 2000 Red Hat Inc. * Copyright (C) 2001 George Lebl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - * Suite 500, Boston, MA 02110-1335, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "eggdesktopfile.h" #include #include #include #include #include struct EggDesktopFile { GKeyFile *key_file; char *source; char *name, *icon; EggDesktopFileType type; char document_code; }; /** * egg_desktop_file_new: * @desktop_file_path: path to a Freedesktop-style Desktop file * @error: error pointer * * Creates a new #EggDesktopFile for @desktop_file. * * Return value: the new #EggDesktopFile, or %NULL on error. **/ EggDesktopFile * egg_desktop_file_new (const char *desktop_file_path, GError **error) { GKeyFile *key_file; key_file = g_key_file_new (); if (!g_key_file_load_from_file (key_file, desktop_file_path, 0, error)) { g_key_file_free (key_file); return NULL; } return egg_desktop_file_new_from_key_file (key_file, desktop_file_path, error); } /** * egg_desktop_file_new_from_data_dirs: * @desktop_file_path: relative path to a Freedesktop-style Desktop file * @error: error pointer * * Looks for @desktop_file_path in the paths returned from * g_get_user_data_dir() and g_get_system_data_dirs(), and creates * a new #EggDesktopFile from it. * * Return value: the new #EggDesktopFile, or %NULL on error. **/ EggDesktopFile * egg_desktop_file_new_from_data_dirs (const char *desktop_file_path, GError **error) { EggDesktopFile *desktop_file; GKeyFile *key_file; char *full_path; key_file = g_key_file_new (); if (!g_key_file_load_from_data_dirs (key_file, desktop_file_path, &full_path, 0, error)) { g_key_file_free (key_file); return NULL; } desktop_file = egg_desktop_file_new_from_key_file (key_file, full_path, error); g_free (full_path); return desktop_file; } /** * egg_desktop_file_new_from_dirs: * @desktop_file_path: relative path to a Freedesktop-style Desktop file * @search_dirs: NULL-terminated array of directories to search * @error: error pointer * * Looks for @desktop_file_path in the paths returned from * g_get_user_data_dir() and g_get_system_data_dirs(), and creates * a new #EggDesktopFile from it. * * Return value: the new #EggDesktopFile, or %NULL on error. **/ EggDesktopFile * egg_desktop_file_new_from_dirs (const char *desktop_file_path, const char **search_dirs, GError **error) { EggDesktopFile *desktop_file; GKeyFile *key_file; char *full_path; key_file = g_key_file_new (); if (!g_key_file_load_from_dirs (key_file, desktop_file_path, search_dirs, &full_path, 0, error)) { g_key_file_free (key_file); return NULL; } desktop_file = egg_desktop_file_new_from_key_file (key_file, full_path, error); g_free (full_path); return desktop_file; } /** * egg_desktop_file_new_from_key_file: * @key_file: a #GKeyFile representing a desktop file * @source: the path or URI that @key_file was loaded from, or %NULL * @error: error pointer * * Creates a new #EggDesktopFile for @key_file. Assumes ownership of * @key_file (on success or failure); you should consider @key_file to * be freed after calling this function. * * Return value: the new #EggDesktopFile, or %NULL on error. **/ EggDesktopFile * egg_desktop_file_new_from_key_file (GKeyFile *key_file, const char *source, GError **error) { EggDesktopFile *desktop_file; char *version, *type; if (!g_key_file_has_group (key_file, EGG_DESKTOP_FILE_GROUP)) { g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_INVALID, _("File is not a valid .desktop file")); g_key_file_free (key_file); return NULL; } version = g_key_file_get_value (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_VERSION, NULL); if (version) { double version_num; char *end; version_num = g_ascii_strtod (version, &end); if (*end) { g_warning ("Invalid Version string '%s' in %s", version, source ? source : "(unknown)"); } else if (version_num > 1.0) { g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_INVALID, /* translators: 'Version' is from a desktop file, and * should not be translated. '%s' would probably be a * version number. */ _("Unrecognized desktop file Version '%s'"), version); g_free (version); g_key_file_free (key_file); return NULL; } g_free (version); } desktop_file = g_new0 (EggDesktopFile, 1); desktop_file->key_file = key_file; if (g_path_is_absolute (source)) desktop_file->source = g_filename_to_uri (source, NULL, NULL); else desktop_file->source = g_strdup (source); desktop_file->name = g_key_file_get_locale_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_NAME, NULL, error); if (!desktop_file->name) { egg_desktop_file_free (desktop_file); return NULL; } type = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_TYPE, error); if (!type) { egg_desktop_file_free (desktop_file); return NULL; } if (!strcmp (type, "Application")) { char *exec, *p; desktop_file->type = EGG_DESKTOP_FILE_TYPE_APPLICATION; exec = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_EXEC, error); if (!exec) { egg_desktop_file_free (desktop_file); g_free (type); return NULL; } /* See if it takes paths or URIs or neither */ for (p = exec; *p; p++) { if (*p == '%') { if (p[1] == '\0' || strchr ("FfUu", p[1])) { desktop_file->document_code = p[1]; break; } p++; } } g_free (exec); } else if (!strcmp (type, "Link")) { char *url; desktop_file->type = EGG_DESKTOP_FILE_TYPE_LINK; url = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_URL, error); if (!url) { egg_desktop_file_free (desktop_file); g_free (type); return NULL; } g_free (url); } else if (!strcmp (type, "Directory")) desktop_file->type = EGG_DESKTOP_FILE_TYPE_DIRECTORY; else desktop_file->type = EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED; g_free (type); /* Check the Icon key */ desktop_file->icon = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_ICON, NULL); if (desktop_file->icon && !g_path_is_absolute (desktop_file->icon)) { char *ext; /* Lots of .desktop files still get this wrong */ ext = strrchr (desktop_file->icon, '.'); if (ext && (!strcmp (ext, ".png") || !strcmp (ext, ".xpm") || !strcmp (ext, ".svg"))) { g_warning ("Desktop file '%s' has malformed Icon key '%s'" "(should not include extension)", source ? source : "(unknown)", desktop_file->icon); *ext = '\0'; } } return desktop_file; } /** * egg_desktop_file_free: * @desktop_file: an #EggDesktopFile * * Frees @desktop_file. **/ void egg_desktop_file_free (EggDesktopFile *desktop_file) { g_key_file_free (desktop_file->key_file); g_free (desktop_file->source); g_free (desktop_file->name); g_free (desktop_file->icon); g_free (desktop_file); } /** * egg_desktop_file_get_source: * @desktop_file: an #EggDesktopFile * * Gets the URI that @desktop_file was loaded from. * * Return value: @desktop_file's source URI **/ const char * egg_desktop_file_get_source (EggDesktopFile *desktop_file) { return desktop_file->source; } /** * egg_desktop_file_get_desktop_file_type: * @desktop_file: an #EggDesktopFile * * Gets the desktop file type of @desktop_file. * * Return value: @desktop_file's type **/ EggDesktopFileType egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file) { return desktop_file->type; } /** * egg_desktop_file_get_name: * @desktop_file: an #EggDesktopFile * * Gets the (localized) value of @desktop_file's "Name" key. * * Return value: the application/link name **/ const char * egg_desktop_file_get_name (EggDesktopFile *desktop_file) { return desktop_file->name; } /** * egg_desktop_file_get_icon: * @desktop_file: an #EggDesktopFile * * Gets the value of @desktop_file's "Icon" key. * * If the icon string is a full path (that is, if g_path_is_absolute() * returns %TRUE when called on it), it points to a file containing an * unthemed icon. If the icon string is not a full path, it is the * name of a themed icon, which can be looked up with %GtkIconTheme, * or passed directly to a theme-aware widget like %GtkImage or * %GtkCellRendererPixbuf. * * Return value: the icon path or name **/ const char * egg_desktop_file_get_icon (EggDesktopFile *desktop_file) { return desktop_file->icon; } gboolean egg_desktop_file_has_key (EggDesktopFile *desktop_file, const char *key, GError **error) { return g_key_file_has_key (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, error); } char * egg_desktop_file_get_string (EggDesktopFile *desktop_file, const char *key, GError **error) { return g_key_file_get_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, error); } char * egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file, const char *key, const char *locale, GError **error) { return g_key_file_get_locale_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, locale, error); } gboolean egg_desktop_file_get_boolean (EggDesktopFile *desktop_file, const char *key, GError **error) { return g_key_file_get_boolean (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, error); } double egg_desktop_file_get_numeric (EggDesktopFile *desktop_file, const char *key, GError **error) { return g_key_file_get_double (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, error); } int egg_desktop_file_get_integer (EggDesktopFile *desktop_file, const char *key, GError **error) { return g_key_file_get_integer (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, error); } char ** egg_desktop_file_get_string_list (EggDesktopFile *desktop_file, const char *key, gsize *length, GError **error) { return g_key_file_get_string_list (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, length, error); } char ** egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file, const char *key, const char *locale, gsize *length, GError **error) { return g_key_file_get_locale_string_list (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, key, locale, length, error); } /** * egg_desktop_file_can_launch: * @desktop_file: an #EggDesktopFile * @desktop_environment: the name of the running desktop environment, * or %NULL * * Tests if @desktop_file can/should be launched in the current * environment. If @desktop_environment is non-%NULL, @desktop_file's * "OnlyShowIn" and "NotShowIn" keys are checked to make sure that * this desktop_file is appropriate for the named environment. * * Furthermore, if @desktop_file has type * %EGG_DESKTOP_FILE_TYPE_APPLICATION, its "TryExec" key (if any) is * also checked, to make sure the binary it points to exists. * * egg_desktop_file_can_launch() does NOT check the value of the * "Hidden" key. * * Return value: %TRUE if @desktop_file can be launched **/ gboolean egg_desktop_file_can_launch (EggDesktopFile *desktop_file, const char *desktop_environment) { char *try_exec, *found_program; char **only_show_in, **not_show_in; gboolean found; int i; if (desktop_file->type != EGG_DESKTOP_FILE_TYPE_APPLICATION && desktop_file->type != EGG_DESKTOP_FILE_TYPE_LINK) return FALSE; if (desktop_environment) { only_show_in = g_key_file_get_string_list (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN, NULL, NULL); if (only_show_in) { for (i = 0, found = FALSE; only_show_in[i] && !found; i++) { if (!strcmp (only_show_in[i], "GNOME") || !strcmp (only_show_in[i], "X-Cinnamon")) found = TRUE; } g_strfreev (only_show_in); if (!found) return FALSE; } not_show_in = g_key_file_get_string_list (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN, NULL, NULL); if (not_show_in) { for (i = 0, found = FALSE; not_show_in[i] && !found; i++) { if (!strcmp (not_show_in[i], desktop_environment)) found = TRUE; } g_strfreev (not_show_in); if (found) return FALSE; } } if (desktop_file->type == EGG_DESKTOP_FILE_TYPE_APPLICATION) { try_exec = g_key_file_get_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_TRY_EXEC, NULL); if (try_exec) { found_program = g_find_program_in_path (try_exec); g_free (try_exec); if (!found_program) return FALSE; g_free (found_program); } } return TRUE; } /** * egg_desktop_file_accepts_documents: * @desktop_file: an #EggDesktopFile * * Tests if @desktop_file represents an application that can accept * documents on the command line. * * Return value: %TRUE or %FALSE **/ gboolean egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file) { return desktop_file->document_code != 0; } /** * egg_desktop_file_accepts_multiple: * @desktop_file: an #EggDesktopFile * * Tests if @desktop_file can accept multiple documents at once. * * If this returns %FALSE, you can still pass multiple documents to * egg_desktop_file_launch(), but that will result in multiple copies * of the application being launched. See egg_desktop_file_launch() * for more details. * * Return value: %TRUE or %FALSE **/ gboolean egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file) { return (desktop_file->document_code == 'F' || desktop_file->document_code == 'U'); } /** * egg_desktop_file_accepts_uris: * @desktop_file: an #EggDesktopFile * * Tests if @desktop_file can accept (non-"file:") URIs as documents to * open. * * Return value: %TRUE or %FALSE **/ gboolean egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file) { return (desktop_file->document_code == 'U' || desktop_file->document_code == 'u'); } static void append_quoted_word (GString *str, const char *s, gboolean in_single_quotes, gboolean in_double_quotes) { const char *p; if (!in_single_quotes && !in_double_quotes) g_string_append_c (str, '\''); else if (!in_single_quotes && in_double_quotes) g_string_append (str, "\"'"); if (!strchr (s, '\'')) g_string_append (str, s); else { for (p = s; *p != '\0'; p++) { if (*p == '\'') g_string_append (str, "'\\''"); else g_string_append_c (str, *p); } } if (!in_single_quotes && !in_double_quotes) g_string_append_c (str, '\''); else if (!in_single_quotes && in_double_quotes) g_string_append (str, "'\""); } static void do_percent_subst (EggDesktopFile *desktop_file, char code, GString *str, GSList **documents, gboolean in_single_quotes, gboolean in_double_quotes) { GSList *d; char *doc; switch (code) { case '%': g_string_append_c (str, '%'); break; case 'F': case 'U': for (d = *documents; d; d = d->next) { doc = d->data; g_string_append (str, " "); append_quoted_word (str, doc, in_single_quotes, in_double_quotes); } *documents = NULL; break; case 'f': case 'u': if (*documents) { doc = (*documents)->data; g_string_append (str, " "); append_quoted_word (str, doc, in_single_quotes, in_double_quotes); *documents = (*documents)->next; } break; case 'i': if (desktop_file->icon) { g_string_append (str, "--icon "); append_quoted_word (str, desktop_file->icon, in_single_quotes, in_double_quotes); } break; case 'c': if (desktop_file->name) { append_quoted_word (str, desktop_file->name, in_single_quotes, in_double_quotes); } break; case 'k': if (desktop_file->source) { append_quoted_word (str, desktop_file->source, in_single_quotes, in_double_quotes); } break; case 'D': case 'N': case 'd': case 'n': case 'v': case 'm': /* Deprecated; skip */ break; default: g_warning ("Unrecognized %%-code '%%%c' in Exec", code); break; } } static char * parse_exec (EggDesktopFile *desktop_file, GSList **documents, GError **error) { char *exec, *p, *command; gboolean escape, single_quot, double_quot; GString *gs; exec = g_key_file_get_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_EXEC, error); if (!exec) return NULL; /* Build the command */ gs = g_string_new (NULL); escape = single_quot = double_quot = FALSE; for (p = exec; *p != '\0'; p++) { if (escape) { escape = FALSE; g_string_append_c (gs, *p); } else if (*p == '\\') { if (!single_quot) escape = TRUE; g_string_append_c (gs, *p); } else if (*p == '\'') { g_string_append_c (gs, *p); if (!single_quot && !double_quot) single_quot = TRUE; else if (single_quot) single_quot = FALSE; } else if (*p == '"') { g_string_append_c (gs, *p); if (!single_quot && !double_quot) double_quot = TRUE; else if (double_quot) double_quot = FALSE; } else if (*p == '%' && p[1]) { do_percent_subst (desktop_file, p[1], gs, documents, single_quot, double_quot); p++; } else g_string_append_c (gs, *p); } g_free (exec); command = g_string_free (gs, FALSE); /* Prepend "xdg-terminal " if needed (FIXME: use gvfs) */ if (g_key_file_has_key (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_TERMINAL, NULL)) { GError *terminal_error = NULL; gboolean use_terminal = g_key_file_get_boolean (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_TERMINAL, &terminal_error); if (terminal_error) { g_free (command); g_propagate_error (error, terminal_error); return NULL; } if (use_terminal) { gs = g_string_new ("xdg-terminal "); append_quoted_word (gs, command, FALSE, FALSE); g_free (command); command = g_string_free (gs, FALSE); } } return command; } static GSList * translate_document_list (EggDesktopFile *desktop_file, GSList *documents) { gboolean accepts_uris = egg_desktop_file_accepts_uris (desktop_file); GSList *ret, *d; for (d = documents, ret = NULL; d; d = d->next) { const char *document = d->data; gboolean is_uri = !g_path_is_absolute (document); char *translated; if (accepts_uris) { if (is_uri) translated = g_strdup (document); else translated = g_filename_to_uri (document, NULL, NULL); } else { if (is_uri) translated = g_filename_from_uri (document, NULL, NULL); else translated = g_strdup (document); } if (translated) ret = g_slist_prepend (ret, translated); } return g_slist_reverse (ret); } static void free_document_list (GSList *documents) { GSList *d; for (d = documents; d; d = d->next) g_free (d->data); g_slist_free (documents); } /** * egg_desktop_file_parse_exec: * @desktop_file: a #EggDesktopFile * @documents: a list of document paths or URIs * @error: error pointer * * Parses @desktop_file's Exec key, inserting @documents into it, and * returns the result. * * If @documents contains non-file: URIs and @desktop_file does not * accept URIs, those URIs will be ignored. Likewise, if @documents * contains more elements than @desktop_file accepts, the extra * documents will be ignored. * * Return value: the parsed Exec string **/ char * egg_desktop_file_parse_exec (EggDesktopFile *desktop_file, GSList *documents, GError **error) { GSList *translated, *docs; char *command; docs = translated = translate_document_list (desktop_file, documents); command = parse_exec (desktop_file, &docs, error); free_document_list (translated); return command; } static gboolean parse_link (EggDesktopFile *desktop_file, EggDesktopFile **app_desktop_file, GSList **documents, GError **error) { char *url; GKeyFile *key_file; url = g_key_file_get_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_URL, error); if (!url) return FALSE; *documents = g_slist_prepend (NULL, url); /* FIXME: use gvfs */ key_file = g_key_file_new (); g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_NAME, "xdg-open"); g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_TYPE, "Application"); g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_EXEC, "xdg-open %u"); *app_desktop_file = egg_desktop_file_new_from_key_file (key_file, NULL, NULL); return TRUE; } static char * start_startup_notification (GdkDisplay *display, EggDesktopFile *desktop_file, const char *argv0, int screen, int workspace, guint32 launch_time) { static int sequence = 0; char *startup_id; char *description, *wmclass; char *screen_str, *workspace_str; if (g_key_file_has_key (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY, NULL)) { if (!g_key_file_get_boolean (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY, NULL)) return NULL; wmclass = NULL; } else { wmclass = g_key_file_get_string (desktop_file->key_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS, NULL); if (!wmclass) return NULL; } if (launch_time == (guint32)-1) launch_time = gdk_x11_display_get_user_time (display); startup_id = g_strdup_printf ("%s-%lu-%s-%s-%d_TIME%lu", g_get_prgname (), (unsigned long)getpid (), g_get_host_name (), argv0, sequence++, (unsigned long)launch_time); description = g_strdup_printf (_("Starting %s"), desktop_file->name); screen_str = g_strdup_printf ("%d", screen); workspace_str = workspace == -1 ? NULL : g_strdup_printf ("%d", workspace); gdk_x11_display_broadcast_startup_message (display, "new", "ID", startup_id, "NAME", desktop_file->name, "SCREEN", screen_str, "BIN", argv0, "ICON", desktop_file->icon, "DESKTOP", workspace_str, "DESCRIPTION", description, "WMCLASS", wmclass, NULL); g_free (description); g_free (wmclass); g_free (screen_str); g_free (workspace_str); return startup_id; } static void end_startup_notification (GdkDisplay *display, const char *startup_id) { gdk_x11_display_broadcast_startup_message (display, "remove", "ID", startup_id, NULL); } #define EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH (30 /* seconds */) typedef struct { GdkDisplay *display; char *startup_id; } StartupNotificationData; static gboolean startup_notification_timeout (gpointer data) { StartupNotificationData *sn_data = data; end_startup_notification (sn_data->display, sn_data->startup_id); g_object_unref (sn_data->display); g_free (sn_data->startup_id); g_free (sn_data); return FALSE; } static void set_startup_notification_timeout (GdkDisplay *display, const char *startup_id) { StartupNotificationData *sn_data; sn_data = g_new (StartupNotificationData, 1); sn_data->display = g_object_ref (display); sn_data->startup_id = g_strdup (startup_id); g_timeout_add_seconds (EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH, startup_notification_timeout, sn_data); } static GPtrArray * array_putenv (GPtrArray *env, char *variable) { guint i, keylen; if (!env) { char **envp; env = g_ptr_array_new (); envp = g_listenv (); for (i = 0; envp[i]; i++) { const char *value; value = g_getenv (envp[i]); g_ptr_array_add (env, g_strdup_printf ("%s=%s", envp[i], value ? value : "")); } g_strfreev (envp); } keylen = strcspn (variable, "="); /* Remove old value of key */ for (i = 0; i < env->len; i++) { char *envvar = env->pdata[i]; if (!strncmp (envvar, variable, keylen) && envvar[keylen] == '=') { g_free (envvar); g_ptr_array_remove_index_fast (env, i); break; } } /* Add new value */ g_ptr_array_add (env, g_strdup (variable)); return env; } static gboolean egg_desktop_file_launchv (EggDesktopFile *desktop_file, GSList *documents, va_list args, GError **error) { EggDesktopFileLaunchOption option; GSList *translated_documents = NULL, *docs = NULL; char *command, **argv; int argc, i, screen_num; gboolean success, current_success; GdkDisplay *display; char *startup_id; GPtrArray *env = NULL; char **variables = NULL; GdkScreen *screen = NULL; int workspace = -1; const char *directory = NULL; guint32 launch_time = (guint32)-1; GSpawnFlags flags = G_SPAWN_SEARCH_PATH; GSpawnChildSetupFunc setup_func = NULL; gpointer setup_data = NULL; GPid *ret_pid = NULL; int *ret_stdin = NULL, *ret_stdout = NULL, *ret_stderr = NULL; char **ret_startup_id = NULL; if (documents && desktop_file->document_code == 0) { g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, _("Application does not accept documents on command line")); return FALSE; } /* Read the options: technically it's incorrect for the caller to * NULL-terminate the list of options (rather than 0-terminating * it), but NULL-terminating lets us use G_GNUC_NULL_TERMINATED, * it's more consistent with other glib/gtk methods, and it will * work as long as sizeof (int) <= sizeof (NULL), and NULL is * represented as 0. (Which is true everywhere we care about.) */ while ((option = va_arg (args, EggDesktopFileLaunchOption))) { switch (option) { case EGG_DESKTOP_FILE_LAUNCH_CLEARENV: if (env) g_ptr_array_free (env, TRUE); env = g_ptr_array_new (); break; case EGG_DESKTOP_FILE_LAUNCH_PUTENV: variables = va_arg (args, char **); for (i = 0; variables[i]; i++) env = array_putenv (env, variables[i]); break; case EGG_DESKTOP_FILE_LAUNCH_SCREEN: screen = va_arg (args, GdkScreen *); break; case EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: workspace = va_arg (args, int); break; case EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: directory = va_arg (args, const char *); break; case EGG_DESKTOP_FILE_LAUNCH_TIME: launch_time = va_arg (args, guint32); break; case EGG_DESKTOP_FILE_LAUNCH_FLAGS: flags |= va_arg (args, GSpawnFlags); /* Make sure they didn't set any flags that don't make sense. */ flags &= ~G_SPAWN_FILE_AND_ARGV_ZERO; break; case EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC: setup_func = va_arg (args, GSpawnChildSetupFunc); setup_data = va_arg (args, gpointer); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_PID: ret_pid = va_arg (args, GPid *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE: ret_stdin = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE: ret_stdout = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE: ret_stderr = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID: ret_startup_id = va_arg (args, char **); break; default: g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION, _("Unrecognized launch option: %d"), GPOINTER_TO_INT (option)); success = FALSE; goto out; } } if (screen) { char *display_name = gdk_screen_make_display_name (screen); char *display_env = g_strdup_printf ("DISPLAY=%s", display_name); env = array_putenv (env, display_env); g_free (display_name); g_free (display_env); display = gdk_screen_get_display (screen); } else { display = gdk_display_get_default (); screen = gdk_display_get_default_screen (display); } screen_num = gdk_screen_get_number (screen); translated_documents = translate_document_list (desktop_file, documents); docs = translated_documents; success = FALSE; do { command = parse_exec (desktop_file, &docs, error); if (!command) goto out; if (!g_shell_parse_argv (command, &argc, &argv, error)) { g_free (command); goto out; } g_free (command); startup_id = start_startup_notification (display, desktop_file, argv[0], screen_num, workspace, launch_time); if (startup_id) { char *startup_id_env = g_strdup_printf ("DESKTOP_STARTUP_ID=%s", startup_id); env = array_putenv (env, startup_id_env); g_free (startup_id_env); } if (env != NULL) g_ptr_array_add (env, NULL); current_success = g_spawn_async_with_pipes (directory, argv, env ? (char **)(env->pdata) : NULL, flags, setup_func, setup_data, ret_pid, ret_stdin, ret_stdout, ret_stderr, error); g_strfreev (argv); if (startup_id) { if (current_success) { set_startup_notification_timeout (display, startup_id); if (ret_startup_id) *ret_startup_id = startup_id; else g_free (startup_id); } else g_free (startup_id); } else if (ret_startup_id) *ret_startup_id = NULL; if (current_success) { /* If we successfully launch any instances of the app, make * sure we return TRUE and don't set @error. */ success = TRUE; error = NULL; /* Also, only set the output params on the first one */ ret_pid = NULL; ret_stdin = ret_stdout = ret_stderr = NULL; ret_startup_id = NULL; } } while (docs && current_success); out: if (env) { g_ptr_array_foreach (env, (GFunc)g_free, NULL); g_ptr_array_free (env, TRUE); } free_document_list (translated_documents); return success; } /** * egg_desktop_file_launch: * @desktop_file: an #EggDesktopFile * @documents: a list of URIs or paths to documents to open * @error: error pointer * @...: additional options * * Launches @desktop_file with the given arguments. Additional options * can be specified as follows: * * %EGG_DESKTOP_FILE_LAUNCH_CLEARENV: (no arguments) * clears the environment in the child process * %EGG_DESKTOP_FILE_LAUNCH_PUTENV: (char **variables) * adds the NAME=VALUE strings in the given %NULL-terminated * array to the child process's environment * %EGG_DESKTOP_FILE_LAUNCH_SCREEN: (GdkScreen *screen) * causes the application to be launched on the given screen * %EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: (int workspace) * causes the application to be launched on the given workspace * %EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: (char *dir) * causes the application to be launched in the given directory * %EGG_DESKTOP_FILE_LAUNCH_TIME: (guint32 launch_time) * sets the "launch time" for the application. If the user * interacts with another window after @launch_time but before * the launched application creates its first window, the window * manager may choose to not give focus to the new application. * Passing 0 for @launch_time will explicitly request that the * application not receive focus. * %EGG_DESKTOP_FILE_LAUNCH_FLAGS (GSpawnFlags flags) * Sets additional #GSpawnFlags to use. See g_spawn_async() for * more details. * %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC (GSpawnChildSetupFunc, gpointer) * Sets the child setup callback and the data to pass to it. * (See g_spawn_async() for more details.) * * %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID (GPid **pid) * On a successful launch, sets *@pid to the PID of the launched * application. * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID (char **startup_id) * On a successful launch, sets *@startup_id to the Startup * Notification "startup id" of the launched application. * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE (int *fd) * On a successful launch, sets *@fd to the file descriptor of * a pipe connected to the application's stdin. * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE (int *fd) * On a successful launch, sets *@fd to the file descriptor of * a pipe connected to the application's stdout. * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE (int *fd) * On a successful launch, sets *@fd to the file descriptor of * a pipe connected to the application's stderr. * * The options should be terminated with a single %NULL. * * If @documents contains multiple documents, but * egg_desktop_file_accepts_multiple() returns %FALSE for * @desktop_file, then egg_desktop_file_launch() will actually launch * multiple instances of the application. In that case, the return * value (as well as any values passed via * %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, etc) will only reflect the * first instance of the application that was launched (but the * %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC will be called for each * instance). * * Return value: %TRUE if the application was successfully launched. **/ gboolean egg_desktop_file_launch (EggDesktopFile *desktop_file, GSList *documents, GError **error, ...) { va_list args; gboolean success; EggDesktopFile *app_desktop_file; switch (desktop_file->type) { case EGG_DESKTOP_FILE_TYPE_APPLICATION: va_start (args, error); success = egg_desktop_file_launchv (desktop_file, documents, args, error); va_end (args); break; case EGG_DESKTOP_FILE_TYPE_LINK: if (documents) { g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, /* translators: The 'Type=Link' string is found in a * desktop file, and should not be translated. */ _("Can't pass document URIs to a 'Type=Link' desktop entry")); return FALSE; } if (!parse_link (desktop_file, &app_desktop_file, &documents, error)) return FALSE; va_start (args, error); success = egg_desktop_file_launchv (app_desktop_file, documents, args, error); va_end (args); egg_desktop_file_free (app_desktop_file); free_document_list (documents); break; case EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED: case EGG_DESKTOP_FILE_TYPE_DIRECTORY: default: g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, _("Not a launchable item")); success = FALSE; break; } return success; } GQuark egg_desktop_file_error_quark (void) { return g_quark_from_static_string ("egg-desktop_file-error-quark"); } G_LOCK_DEFINE_STATIC (egg_desktop_file); static EggDesktopFile *egg_desktop_file; static void egg_set_desktop_file_internal (const char *desktop_file_path, gboolean set_defaults) { GError *error = NULL; G_LOCK (egg_desktop_file); if (egg_desktop_file) egg_desktop_file_free (egg_desktop_file); egg_desktop_file = egg_desktop_file_new (desktop_file_path, &error); if (error) { g_warning ("Could not load desktop file '%s': %s", desktop_file_path, error->message); g_error_free (error); } if (set_defaults && egg_desktop_file != NULL) { /* Set localized application name and default window icon */ if (egg_desktop_file->name) g_set_application_name (egg_desktop_file->name); if (egg_desktop_file->icon) { if (g_path_is_absolute (egg_desktop_file->icon)) gtk_window_set_default_icon_from_file (egg_desktop_file->icon, NULL); else gtk_window_set_default_icon_name (egg_desktop_file->icon); } } G_UNLOCK (egg_desktop_file); } /** * egg_set_desktop_file: * @desktop_file_path: path to the application's desktop file * * Creates an #EggDesktopFile for the application from the data at * @desktop_file_path. This will also call g_set_application_name() * with the localized application name from the desktop file, and * gtk_window_set_default_icon_name() or * gtk_window_set_default_icon_from_file() with the application's * icon. Other code may use additional information from the desktop * file. * See egg_set_desktop_file_without_defaults() for a variant of this * function that does not set the application name and default window * icon. * * Note that for thread safety reasons, this function can only * be called once, and is mutually exclusive with calling * egg_set_desktop_file_without_defaults(). **/ void egg_set_desktop_file (const char *desktop_file_path) { egg_set_desktop_file_internal (desktop_file_path, TRUE); } /** * egg_set_desktop_file_without_defaults: * @desktop_file_path: path to the application's desktop file * * Creates an #EggDesktopFile for the application from the data at * @desktop_file_path. * See egg_set_desktop_file() for a variant of this function that * sets the application name and default window icon from the information * in the desktop file. * * Note that for thread safety reasons, this function can only * be called once, and is mutually exclusive with calling * egg_set_desktop_file(). **/ void egg_set_desktop_file_without_defaults (const char *desktop_file_path) { egg_set_desktop_file_internal (desktop_file_path, FALSE); } /** * egg_get_desktop_file: * * Gets the application's #EggDesktopFile, as set by * egg_set_desktop_file(). * * Return value: the #EggDesktopFile, or %NULL if it hasn't been set. **/ EggDesktopFile * egg_get_desktop_file (void) { EggDesktopFile *retval; G_LOCK (egg_desktop_file); retval = egg_desktop_file; G_UNLOCK (egg_desktop_file); return retval; } cinnamon-session-3.6.1/egg/eggdesktopfile.h0000644000175000017500000001447113205266677017456 0ustar maxymaxy/* eggdesktopfile.h - Freedesktop.Org Desktop Files * Copyright (C) 2007 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING.LIB. If not, * write to the Free Software Foundation, Inc., 51 Franklin Street - * Suite 500, Boston, MA 02110-1335, USA. */ #ifndef __EGG_DESKTOP_FILE_H__ #define __EGG_DESKTOP_FILE_H__ #include G_BEGIN_DECLS typedef struct EggDesktopFile EggDesktopFile; typedef enum { EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED, EGG_DESKTOP_FILE_TYPE_APPLICATION, EGG_DESKTOP_FILE_TYPE_LINK, EGG_DESKTOP_FILE_TYPE_DIRECTORY } EggDesktopFileType; EggDesktopFile *egg_desktop_file_new (const char *desktop_file_path, GError **error); EggDesktopFile *egg_desktop_file_new_from_data_dirs (const char *desktop_file_path, GError **error); EggDesktopFile *egg_desktop_file_new_from_dirs (const char *desktop_file_path, const char **search_dirs, GError **error); EggDesktopFile *egg_desktop_file_new_from_key_file (GKeyFile *key_file, const char *source, GError **error); void egg_desktop_file_free (EggDesktopFile *desktop_file); const char *egg_desktop_file_get_source (EggDesktopFile *desktop_file); EggDesktopFileType egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file); const char *egg_desktop_file_get_name (EggDesktopFile *desktop_file); const char *egg_desktop_file_get_icon (EggDesktopFile *desktop_file); gboolean egg_desktop_file_can_launch (EggDesktopFile *desktop_file, const char *desktop_environment); gboolean egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file); gboolean egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file); gboolean egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file); char *egg_desktop_file_parse_exec (EggDesktopFile *desktop_file, GSList *documents, GError **error); gboolean egg_desktop_file_launch (EggDesktopFile *desktop_file, GSList *documents, GError **error, ...) G_GNUC_NULL_TERMINATED; typedef enum { EGG_DESKTOP_FILE_LAUNCH_CLEARENV = 1, EGG_DESKTOP_FILE_LAUNCH_PUTENV, EGG_DESKTOP_FILE_LAUNCH_SCREEN, EGG_DESKTOP_FILE_LAUNCH_WORKSPACE, EGG_DESKTOP_FILE_LAUNCH_DIRECTORY, EGG_DESKTOP_FILE_LAUNCH_TIME, EGG_DESKTOP_FILE_LAUNCH_FLAGS, EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC, EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE, EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE, EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE, EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID } EggDesktopFileLaunchOption; /* Standard Keys */ #define EGG_DESKTOP_FILE_GROUP "Desktop Entry" #define EGG_DESKTOP_FILE_KEY_TYPE "Type" #define EGG_DESKTOP_FILE_KEY_VERSION "Version" #define EGG_DESKTOP_FILE_KEY_NAME "Name" #define EGG_DESKTOP_FILE_KEY_GENERIC_NAME "GenericName" #define EGG_DESKTOP_FILE_KEY_NO_DISPLAY "NoDisplay" #define EGG_DESKTOP_FILE_KEY_COMMENT "Comment" #define EGG_DESKTOP_FILE_KEY_ICON "Icon" #define EGG_DESKTOP_FILE_KEY_HIDDEN "Hidden" #define EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN "OnlyShowIn" #define EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN "NotShowIn" #define EGG_DESKTOP_FILE_KEY_TRY_EXEC "TryExec" #define EGG_DESKTOP_FILE_KEY_EXEC "Exec" #define EGG_DESKTOP_FILE_KEY_PATH "Path" #define EGG_DESKTOP_FILE_KEY_TERMINAL "Terminal" #define EGG_DESKTOP_FILE_KEY_MIME_TYPE "MimeType" #define EGG_DESKTOP_FILE_KEY_CATEGORIES "Categories" #define EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY "StartupNotify" #define EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS "StartupWMClass" #define EGG_DESKTOP_FILE_KEY_URL "URL" /* Accessors */ gboolean egg_desktop_file_has_key (EggDesktopFile *desktop_file, const char *key, GError **error); char *egg_desktop_file_get_string (EggDesktopFile *desktop_file, const char *key, GError **error) G_GNUC_MALLOC; char *egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file, const char *key, const char *locale, GError **error) G_GNUC_MALLOC; gboolean egg_desktop_file_get_boolean (EggDesktopFile *desktop_file, const char *key, GError **error); double egg_desktop_file_get_numeric (EggDesktopFile *desktop_file, const char *key, GError **error); int egg_desktop_file_get_integer (EggDesktopFile *desktop_file, const char *key, GError **error); char **egg_desktop_file_get_string_list (EggDesktopFile *desktop_file, const char *key, gsize *length, GError **error) G_GNUC_MALLOC; char **egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file, const char *key, const char *locale, gsize *length, GError **error) G_GNUC_MALLOC; /* Errors */ #define EGG_DESKTOP_FILE_ERROR egg_desktop_file_error_quark() GQuark egg_desktop_file_error_quark (void); typedef enum { EGG_DESKTOP_FILE_ERROR_INVALID, EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION } EggDesktopFileError; /* Global application desktop file */ void egg_set_desktop_file (const char *desktop_file_path); void egg_set_desktop_file_without_defaults (const char *desktop_file_path); EggDesktopFile *egg_get_desktop_file (void); G_END_DECLS #endif /* __EGG_DESKTOP_FILE_H__ */ cinnamon-session-3.6.1/egg/eggsmclient-private.h0000644000175000017500000000345713205266677020435 0ustar maxymaxy/* eggsmclient-private.h * Copyright (C) 2007 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef __EGG_SM_CLIENT_PRIVATE_H__ #define __EGG_SM_CLIENT_PRIVATE_H__ #include #include "eggsmclient.h" G_BEGIN_DECLS GKeyFile *egg_sm_client_save_state (EggSMClient *client); void egg_sm_client_quit_requested (EggSMClient *client); void egg_sm_client_quit_cancelled (EggSMClient *client); void egg_sm_client_quit (EggSMClient *client); #if defined (GDK_WINDOWING_X11) # ifdef EGG_SM_CLIENT_BACKEND_XSMP GType egg_sm_client_xsmp_get_type (void); EggSMClient *egg_sm_client_xsmp_new (void); # endif # ifdef EGG_SM_CLIENT_BACKEND_DBUS GType egg_sm_client_dbus_get_type (void); EggSMClient *egg_sm_client_dbus_new (void); # endif #elif defined (GDK_WINDOWING_WIN32) GType egg_sm_client_win32_get_type (void); EggSMClient *egg_sm_client_win32_new (void); #elif defined (GDK_WINDOWING_QUARTZ) GType egg_sm_client_osx_get_type (void); EggSMClient *egg_sm_client_osx_new (void); #endif G_END_DECLS #endif /* __EGG_SM_CLIENT_PRIVATE_H__ */ cinnamon-session-3.6.1/egg/eggsmclient-xsmp.c0000644000175000017500000011361613205266677017744 0ustar maxymaxy/* * Copyright (C) 2007 Novell, Inc. * * Inspired by various other pieces of code including GsmClient (C) * 2001 Havoc Pennington, GnomeClient (C) 1998 Carsten Schaar, and twm * session code (C) 1998 The Open Group. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ #include "config.h" #include "eggsmclient.h" #include "eggsmclient-private.h" #include "eggdesktopfile.h" #include #include #include #include #include #include #include #include #define EGG_TYPE_SM_CLIENT_XSMP (egg_sm_client_xsmp_get_type ()) #define EGG_SM_CLIENT_XSMP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMP)) #define EGG_SM_CLIENT_XSMP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass)) #define EGG_IS_SM_CLIENT_XSMP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_XSMP)) #define EGG_IS_SM_CLIENT_XSMP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_XSMP)) #define EGG_SM_CLIENT_XSMP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass)) typedef struct _EggSMClientXSMP EggSMClientXSMP; typedef struct _EggSMClientXSMPClass EggSMClientXSMPClass; /* These mostly correspond to the similarly-named states in section * 9.1 of the XSMP spec. Some of the states there aren't represented * here, because we don't need them. SHUTDOWN_CANCELLED is slightly * different from the spec; we use it when the client is IDLE after a * ShutdownCancelled message, but the application is still interacting * and doesn't know the shutdown has been cancelled yet. */ typedef enum { XSMP_STATE_IDLE, XSMP_STATE_SAVE_YOURSELF, XSMP_STATE_INTERACT_REQUEST, XSMP_STATE_INTERACT, XSMP_STATE_SAVE_YOURSELF_DONE, XSMP_STATE_SHUTDOWN_CANCELLED, XSMP_STATE_CONNECTION_CLOSED } EggSMClientXSMPState; static const char *state_names[] = { "idle", "save-yourself", "interact-request", "interact", "save-yourself-done", "shutdown-cancelled", "connection-closed" }; #define EGG_SM_CLIENT_XSMP_STATE(xsmp) (state_names[(xsmp)->state]) struct _EggSMClientXSMP { EggSMClient parent; SmcConn connection; char *client_id; EggSMClientXSMPState state; char **restart_command; gboolean set_restart_command; int restart_style; guint idle; /* Current SaveYourself state */ guint expecting_initial_save_yourself : 1; guint need_save_state : 1; guint need_quit_requested : 1; guint interact_errors : 1; guint shutting_down : 1; /* Todo list */ guint waiting_to_set_initial_properties : 1; guint waiting_to_emit_quit : 1; guint waiting_to_emit_quit_cancelled : 1; guint waiting_to_save_myself : 1; }; struct _EggSMClientXSMPClass { EggSMClientClass parent_class; }; static void sm_client_xsmp_startup (EggSMClient *client, const char *client_id); static void sm_client_xsmp_set_restart_command (EggSMClient *client, int argc, const char **argv); static void sm_client_xsmp_will_quit (EggSMClient *client, gboolean will_quit); static gboolean sm_client_xsmp_end_session (EggSMClient *client, EggSMClientEndStyle style, gboolean request_confirmation); static void xsmp_save_yourself (SmcConn smc_conn, SmPointer client_data, int save_style, Bool shutdown, int interact_style, Bool fast); static void xsmp_die (SmcConn smc_conn, SmPointer client_data); static void xsmp_save_complete (SmcConn smc_conn, SmPointer client_data); static void xsmp_shutdown_cancelled (SmcConn smc_conn, SmPointer client_data); static void xsmp_interact (SmcConn smc_conn, SmPointer client_data); static SmProp *array_prop (const char *name, ...); static SmProp *ptrarray_prop (const char *name, GPtrArray *values); static SmProp *string_prop (const char *name, const char *value); static SmProp *card8_prop (const char *name, unsigned char value); static void set_properties (EggSMClientXSMP *xsmp, ...); static void delete_properties (EggSMClientXSMP *xsmp, ...); static GPtrArray *generate_command (char **restart_command, const char *client_id, const char *state_file); static void save_state (EggSMClientXSMP *xsmp); static void do_save_yourself (EggSMClientXSMP *xsmp); static void update_pending_events (EggSMClientXSMP *xsmp); static void ice_init (void); static gboolean process_ice_messages (IceConn ice_conn); static void smc_error_handler (SmcConn smc_conn, Bool swap, int offending_minor_opcode, unsigned long offending_sequence, int error_class, int severity, SmPointer values); G_DEFINE_TYPE (EggSMClientXSMP, egg_sm_client_xsmp, EGG_TYPE_SM_CLIENT) static void egg_sm_client_xsmp_init (EggSMClientXSMP *xsmp) { xsmp->state = XSMP_STATE_CONNECTION_CLOSED; xsmp->connection = NULL; xsmp->restart_style = SmRestartIfRunning; } static void egg_sm_client_xsmp_class_init (EggSMClientXSMPClass *klass) { EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass); sm_client_class->startup = sm_client_xsmp_startup; sm_client_class->set_restart_command = sm_client_xsmp_set_restart_command; sm_client_class->will_quit = sm_client_xsmp_will_quit; sm_client_class->end_session = sm_client_xsmp_end_session; } EggSMClient * egg_sm_client_xsmp_new (void) { if (!g_getenv ("SESSION_MANAGER")) return NULL; return g_object_new (EGG_TYPE_SM_CLIENT_XSMP, NULL); } static gboolean sm_client_xsmp_set_initial_properties (gpointer user_data) { EggSMClientXSMP *xsmp = user_data; EggDesktopFile *desktop_file; GPtrArray *clone, *restart; char pid_str[64]; if (xsmp->idle) { g_source_remove (xsmp->idle); xsmp->idle = 0; } xsmp->waiting_to_set_initial_properties = FALSE; if (egg_sm_client_get_mode () == EGG_SM_CLIENT_MODE_NO_RESTART) xsmp->restart_style = SmRestartNever; /* Parse info out of desktop file */ desktop_file = egg_get_desktop_file (); if (desktop_file) { GError *err = NULL; char *cmdline, **argv; int argc; if (xsmp->restart_style == SmRestartIfRunning) { if (egg_desktop_file_get_boolean (desktop_file, "X-GNOME-AutoRestart", NULL)) xsmp->restart_style = SmRestartImmediately; } if (!xsmp->set_restart_command) { cmdline = egg_desktop_file_parse_exec (desktop_file, NULL, &err); if (cmdline && g_shell_parse_argv (cmdline, &argc, &argv, &err)) { egg_sm_client_set_restart_command (EGG_SM_CLIENT (xsmp), argc, (const char **)argv); g_strfreev (argv); } else { g_warning ("Could not parse Exec line in desktop file: %s", err->message); g_error_free (err); } g_free (cmdline); } } if (!xsmp->set_restart_command) xsmp->restart_command = g_strsplit (g_get_prgname (), " ", -1); clone = generate_command (xsmp->restart_command, NULL, NULL); restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL); g_debug ("Setting initial properties"); /* Program, CloneCommand, RestartCommand, and UserID are required. * ProcessID isn't required, but the SM may be able to do something * useful with it. */ g_snprintf (pid_str, sizeof (pid_str), "%lu", (gulong) getpid ()); set_properties (xsmp, string_prop (SmProgram, g_get_prgname ()), ptrarray_prop (SmCloneCommand, clone), ptrarray_prop (SmRestartCommand, restart), string_prop (SmUserID, g_get_user_name ()), string_prop (SmProcessID, pid_str), card8_prop (SmRestartStyleHint, xsmp->restart_style), NULL); g_ptr_array_free (clone, TRUE); g_ptr_array_free (restart, TRUE); if (desktop_file) { set_properties (xsmp, string_prop ("_GSM_DesktopFile", egg_desktop_file_get_source (desktop_file)), NULL); } update_pending_events (xsmp); return FALSE; } /* This gets called from two different places: xsmp_die() (when the * server asks us to disconnect) and process_ice_messages() (when the * server disconnects unexpectedly). */ static void sm_client_xsmp_disconnect (EggSMClientXSMP *xsmp) { SmcConn connection; if (!xsmp->connection) return; g_debug ("Disconnecting"); connection = xsmp->connection; xsmp->connection = NULL; SmcCloseConnection (connection, 0, NULL); xsmp->state = XSMP_STATE_CONNECTION_CLOSED; xsmp->waiting_to_save_myself = FALSE; update_pending_events (xsmp); } static void sm_client_xsmp_startup (EggSMClient *client, const char *client_id) { EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; SmcCallbacks callbacks; char *ret_client_id; char error_string_ret[256]; xsmp->client_id = g_strdup (client_id); ice_init (); SmcSetErrorHandler (smc_error_handler); callbacks.save_yourself.callback = xsmp_save_yourself; callbacks.die.callback = xsmp_die; callbacks.save_complete.callback = xsmp_save_complete; callbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled; callbacks.save_yourself.client_data = xsmp; callbacks.die.client_data = xsmp; callbacks.save_complete.client_data = xsmp; callbacks.shutdown_cancelled.client_data = xsmp; client_id = NULL; error_string_ret[0] = '\0'; xsmp->connection = SmcOpenConnection (NULL, xsmp, SmProtoMajor, SmProtoMinor, SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask, &callbacks, xsmp->client_id, &ret_client_id, sizeof (error_string_ret), error_string_ret); if (!xsmp->connection) { g_warning ("Failed to connect to the session manager: %s\n", error_string_ret[0] ? error_string_ret : "no error message given"); xsmp->state = XSMP_STATE_CONNECTION_CLOSED; return; } /* We expect a pointless initial SaveYourself if either (a) we * didn't have an initial client ID, or (b) we DID have an initial * client ID, but the server rejected it and gave us a new one. */ if (!xsmp->client_id || (ret_client_id && strcmp (xsmp->client_id, ret_client_id) != 0)) xsmp->expecting_initial_save_yourself = TRUE; if (ret_client_id) { g_free (xsmp->client_id); xsmp->client_id = g_strdup (ret_client_id); free (ret_client_id); gdk_threads_enter (); gdk_x11_set_sm_client_id (xsmp->client_id); gdk_threads_leave (); g_debug ("Got client ID \"%s\"", xsmp->client_id); } xsmp->state = XSMP_STATE_IDLE; /* Do not set the initial properties until we reach the main loop, * so that the application has a chance to call * egg_set_desktop_file(). (This may also help the session manager * have a better idea of when the application is fully up and * running.) */ xsmp->waiting_to_set_initial_properties = TRUE; xsmp->idle = g_idle_add (sm_client_xsmp_set_initial_properties, client); } static void sm_client_xsmp_set_restart_command (EggSMClient *client, int argc, const char **argv) { EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; int i; g_strfreev (xsmp->restart_command); xsmp->restart_command = g_new (char *, argc + 1); for (i = 0; i < argc; i++) xsmp->restart_command[i] = g_strdup (argv[i]); xsmp->restart_command[i] = NULL; xsmp->set_restart_command = TRUE; } static void sm_client_xsmp_will_quit (EggSMClient *client, gboolean will_quit) { EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; if (xsmp->state == XSMP_STATE_CONNECTION_CLOSED) { /* The session manager has already exited! Schedule a quit * signal. */ xsmp->waiting_to_emit_quit = TRUE; update_pending_events (xsmp); return; } else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED) { /* We received a ShutdownCancelled message while the application * was interacting; Schedule a quit_cancelled signal. */ xsmp->waiting_to_emit_quit_cancelled = TRUE; update_pending_events (xsmp); return; } g_return_if_fail (xsmp->state == XSMP_STATE_INTERACT); g_debug ("Sending InteractDone(%s)", will_quit ? "False" : "True"); SmcInteractDone (xsmp->connection, !will_quit); if (will_quit && xsmp->need_save_state) save_state (xsmp); g_debug ("Sending SaveYourselfDone(%s)", will_quit ? "True" : "False"); SmcSaveYourselfDone (xsmp->connection, will_quit); xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; } static gboolean sm_client_xsmp_end_session (EggSMClient *client, EggSMClientEndStyle style, gboolean request_confirmation) { EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; int save_type; /* To end the session via XSMP, we have to send a * SaveYourselfRequest. We aren't allowed to do that if anything * else is going on, but we don't want to expose this fact to the * application. So we do our best to patch things up here... * * In the worst case, this method might block for some length of * time in process_ice_messages, but the only time that code path is * honestly likely to get hit is if the application tries to end the * session as the very first thing it does, in which case it * probably won't actually block anyway. It's not worth gunking up * the API to try to deal nicely with the other 0.01% of cases where * this happens. */ while (xsmp->state != XSMP_STATE_IDLE || xsmp->expecting_initial_save_yourself) { /* If we're already shutting down, we don't need to do anything. */ if (xsmp->shutting_down) return TRUE; switch (xsmp->state) { case XSMP_STATE_CONNECTION_CLOSED: return FALSE; case XSMP_STATE_SAVE_YOURSELF: /* Trying to log out from the save_state callback? Whatever. * Abort the save_state. */ SmcSaveYourselfDone (xsmp->connection, FALSE); xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; break; case XSMP_STATE_INTERACT_REQUEST: case XSMP_STATE_INTERACT: case XSMP_STATE_SHUTDOWN_CANCELLED: /* Already in a shutdown-related state, just ignore * the new shutdown request... */ return TRUE; case XSMP_STATE_IDLE: if (xsmp->waiting_to_set_initial_properties) sm_client_xsmp_set_initial_properties (xsmp); if (!xsmp->expecting_initial_save_yourself) break; /* else fall through */ case XSMP_STATE_SAVE_YOURSELF_DONE: /* We need to wait for some response from the server.*/ process_ice_messages (SmcGetIceConnection (xsmp->connection)); break; default: /* Hm... shouldn't happen */ return FALSE; } } /* xfce4-session will do the wrong thing if we pass SmSaveGlobal and * the user chooses to save the session. But cinnamon-session will do * the wrong thing if we pass SmSaveBoth and the user chooses NOT to * save the session... Sigh. */ if (!strcmp (SmcVendor (xsmp->connection), "xfce4-session")) save_type = SmSaveBoth; else save_type = SmSaveGlobal; g_debug ("Sending SaveYourselfRequest(SmSaveGlobal, Shutdown, SmInteractStyleAny, %sFast)", request_confirmation ? "!" : ""); SmcRequestSaveYourself (xsmp->connection, save_type, True, /* shutdown */ SmInteractStyleAny, !request_confirmation, /* fast */ True /* global */); return TRUE; } static gboolean idle_do_pending_events (gpointer data) { EggSMClientXSMP *xsmp = data; EggSMClient *client = data; gdk_threads_enter (); xsmp->idle = 0; if (xsmp->waiting_to_emit_quit) { xsmp->waiting_to_emit_quit = FALSE; egg_sm_client_quit (client); goto out; } if (xsmp->waiting_to_emit_quit_cancelled) { xsmp->waiting_to_emit_quit_cancelled = FALSE; egg_sm_client_quit_cancelled (client); xsmp->state = XSMP_STATE_IDLE; } if (xsmp->waiting_to_save_myself) { xsmp->waiting_to_save_myself = FALSE; do_save_yourself (xsmp); } out: gdk_threads_leave (); return FALSE; } static void update_pending_events (EggSMClientXSMP *xsmp) { gboolean want_idle = xsmp->waiting_to_emit_quit || xsmp->waiting_to_emit_quit_cancelled || xsmp->waiting_to_save_myself; if (want_idle) { if (xsmp->idle == 0) xsmp->idle = g_idle_add (idle_do_pending_events, xsmp); } else { if (xsmp->idle != 0) { g_source_remove (xsmp->idle); xsmp->idle = 0; } } } static void fix_broken_state (EggSMClientXSMP *xsmp, const char *message, gboolean send_interact_done, gboolean send_save_yourself_done) { g_warning ("Received XSMP %s message in state %s: client or server error", message, EGG_SM_CLIENT_XSMP_STATE (xsmp)); /* Forget any pending SaveYourself plans we had */ xsmp->waiting_to_save_myself = FALSE; update_pending_events (xsmp); if (send_interact_done) SmcInteractDone (xsmp->connection, False); if (send_save_yourself_done) SmcSaveYourselfDone (xsmp->connection, True); xsmp->state = send_save_yourself_done ? XSMP_STATE_SAVE_YOURSELF_DONE : XSMP_STATE_IDLE; } /* SM callbacks */ static void xsmp_save_yourself (SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast) { EggSMClientXSMP *xsmp = client_data; gboolean wants_quit_requested; g_debug ("Received SaveYourself(%s, %s, %s, %s) in state %s", save_type == SmSaveLocal ? "SmSaveLocal" : save_type == SmSaveGlobal ? "SmSaveGlobal" : "SmSaveBoth", shutdown ? "Shutdown" : "!Shutdown", interact_style == SmInteractStyleAny ? "SmInteractStyleAny" : interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" : "SmInteractStyleNone", fast ? "Fast" : "!Fast", EGG_SM_CLIENT_XSMP_STATE (xsmp)); if (xsmp->state != XSMP_STATE_IDLE && xsmp->state != XSMP_STATE_SHUTDOWN_CANCELLED) { fix_broken_state (xsmp, "SaveYourself", FALSE, TRUE); return; } if (xsmp->waiting_to_set_initial_properties) sm_client_xsmp_set_initial_properties (xsmp); /* If this is the initial SaveYourself, ignore it; we've already set * properties and there's no reason to actually save state too. */ if (xsmp->expecting_initial_save_yourself) { xsmp->expecting_initial_save_yourself = FALSE; if (save_type == SmSaveLocal && interact_style == SmInteractStyleNone && !shutdown && !fast) { g_debug ("Sending SaveYourselfDone(True) for initial SaveYourself"); SmcSaveYourselfDone (xsmp->connection, True); /* As explained in the comment at the end of * do_save_yourself(), SAVE_YOURSELF_DONE is the correct * state here, not IDLE. */ xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; return; } else g_warning ("First SaveYourself was not the expected one!"); } /* Even ignoring the "fast" flag completely, there are still 18 * different combinations of save_type, shutdown and interact_style. * We interpret them as follows: * * Type Shutdown Interact Interpretation * G F A/E/N do nothing (1) * G T N do nothing (1)* * G T A/E quit_requested (2) * L/B F A/E/N save_state (3) * L/B T N save_state (3)* * L/B T A/E quit_requested, then save_state (4) * * 1. Do nothing, because the SM asked us to do something * uninteresting (save open files, but then don't quit * afterward) or rude (save open files without asking the user * for confirmation). * * 2. Request interaction and then emit ::quit_requested. This * perhaps isn't quite correct for the SmInteractStyleErrors * case, but we don't care. * * 3. Emit ::save_state. The SmSaveBoth SaveYourselfs in these * rows essentially get demoted to SmSaveLocal, because their * Global halves correspond to "do nothing". * * 4. Request interaction, emit ::quit_requested, and then emit * ::save_state after interacting. This is the SmSaveBoth * equivalent of #2, but we also promote SmSaveLocal shutdown * SaveYourselfs to SmSaveBoth here, because we want to give * the user a chance to save open files before quitting. * * (* It would be nice if we could do something useful when the * session manager sends a SaveYourself with shutdown True and * SmInteractStyleNone. But we can't, so we just pretend it didn't * even tell us it was shutting down. The docs for ::quit mention * that it might not always be preceded by ::quit_requested.) */ /* As an optimization, we don't actually request interaction and * emit ::quit_requested if the application isn't listening to the * signal. */ wants_quit_requested = g_signal_has_handler_pending (xsmp, g_signal_lookup ("quit_requested", EGG_TYPE_SM_CLIENT), 0, FALSE); xsmp->need_save_state = (save_type != SmSaveGlobal); xsmp->need_quit_requested = (shutdown && wants_quit_requested && interact_style != SmInteractStyleNone); xsmp->interact_errors = (interact_style == SmInteractStyleErrors); xsmp->shutting_down = shutdown; do_save_yourself (xsmp); } static void do_save_yourself (EggSMClientXSMP *xsmp) { if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED) { /* The SM cancelled a previous SaveYourself, but we haven't yet * had a chance to tell the application, so we can't start * processing this SaveYourself yet. */ xsmp->waiting_to_save_myself = TRUE; update_pending_events (xsmp); return; } if (xsmp->need_quit_requested) { xsmp->state = XSMP_STATE_INTERACT_REQUEST; g_debug ("Sending InteractRequest(%s)", xsmp->interact_errors ? "Error" : "Normal"); SmcInteractRequest (xsmp->connection, xsmp->interact_errors ? SmDialogError : SmDialogNormal, xsmp_interact, xsmp); return; } if (xsmp->need_save_state) { save_state (xsmp); /* Though unlikely, the client could have been disconnected * while the application was saving its state. */ if (!xsmp->connection) return; } g_debug ("Sending SaveYourselfDone(True)"); SmcSaveYourselfDone (xsmp->connection, True); /* The client state diagram in the XSMP spec says that after a * non-shutdown SaveYourself, we go directly back to "idle". But * everything else in both the XSMP spec and the libSM docs * disagrees. */ xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; } static void save_state (EggSMClientXSMP *xsmp) { GKeyFile *state_file; char *state_file_path, *data; EggDesktopFile *desktop_file; GPtrArray *restart; int offset, fd; /* We set xsmp->state before emitting save_state, but our caller is * responsible for setting it back afterward. */ xsmp->state = XSMP_STATE_SAVE_YOURSELF; state_file = egg_sm_client_save_state ((EggSMClient *)xsmp); if (!state_file) { restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL); set_properties (xsmp, ptrarray_prop (SmRestartCommand, restart), NULL); g_ptr_array_free (restart, TRUE); delete_properties (xsmp, SmDiscardCommand, NULL); return; } desktop_file = egg_get_desktop_file (); if (desktop_file) { GKeyFile *merged_file; char *desktop_file_path; merged_file = g_key_file_new (); desktop_file_path = g_filename_from_uri (egg_desktop_file_get_source (desktop_file), NULL, NULL); if (desktop_file_path && g_key_file_load_from_file (merged_file, desktop_file_path, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, NULL)) { guint g, k, i; char **groups, **keys, *value, *exec; groups = g_key_file_get_groups (state_file, NULL); for (g = 0; groups[g]; g++) { keys = g_key_file_get_keys (state_file, groups[g], NULL, NULL); for (k = 0; keys[k]; k++) { value = g_key_file_get_value (state_file, groups[g], keys[k], NULL); if (value) { g_key_file_set_value (merged_file, groups[g], keys[k], value); g_free (value); } } g_strfreev (keys); } g_strfreev (groups); g_key_file_free (state_file); state_file = merged_file; /* Update Exec key using "--sm-client-state-file %k" */ restart = generate_command (xsmp->restart_command, NULL, "%k"); for (i = 0; i < restart->len; i++) restart->pdata[i] = g_shell_quote (restart->pdata[i]); g_ptr_array_add (restart, NULL); exec = g_strjoinv (" ", (char **)restart->pdata); g_strfreev ((char **)restart->pdata); g_ptr_array_free (restart, FALSE); g_key_file_set_string (state_file, EGG_DESKTOP_FILE_GROUP, EGG_DESKTOP_FILE_KEY_EXEC, exec); g_free (exec); } else desktop_file = NULL; g_free (desktop_file_path); } /* Now write state_file to disk. (We can't use mktemp(), because * that requires the filename to end with "XXXXXX", and we want * it to end with ".desktop".) */ data = g_key_file_to_data (state_file, NULL, NULL); g_key_file_free (state_file); offset = 0; while (1) { state_file_path = g_strdup_printf ("%s%csession-state%c%s-%ld.%s", g_get_user_config_dir (), G_DIR_SEPARATOR, G_DIR_SEPARATOR, g_get_prgname (), (long)time (NULL) + offset, desktop_file ? "desktop" : "state"); fd = open (state_file_path, O_WRONLY | O_CREAT | O_EXCL, 0644); if (fd == -1) { if (errno == EEXIST) { offset++; g_free (state_file_path); continue; } else if (errno == ENOTDIR || errno == ENOENT) { char *sep = strrchr (state_file_path, G_DIR_SEPARATOR); *sep = '\0'; if (g_mkdir_with_parents (state_file_path, 0755) != 0) { g_warning ("Could not create directory '%s'", state_file_path); g_free (state_file_path); state_file_path = NULL; break; } continue; } g_warning ("Could not create file '%s': %s", state_file_path, g_strerror (errno)); g_free (state_file_path); state_file_path = NULL; break; } close (fd); g_file_set_contents (state_file_path, data, -1, NULL); break; } g_free (data); restart = generate_command (xsmp->restart_command, xsmp->client_id, state_file_path); set_properties (xsmp, ptrarray_prop (SmRestartCommand, restart), NULL); g_ptr_array_free (restart, TRUE); if (state_file_path) { set_properties (xsmp, array_prop (SmDiscardCommand, "/bin/rm", "-rf", state_file_path, NULL), NULL); g_free (state_file_path); } } static void xsmp_interact (SmcConn smc_conn, SmPointer client_data) { EggSMClientXSMP *xsmp = client_data; EggSMClient *client = client_data; g_debug ("Received Interact message in state %s", EGG_SM_CLIENT_XSMP_STATE (xsmp)); if (xsmp->state != XSMP_STATE_INTERACT_REQUEST) { fix_broken_state (xsmp, "Interact", TRUE, TRUE); return; } xsmp->state = XSMP_STATE_INTERACT; egg_sm_client_quit_requested (client); } static void xsmp_die (SmcConn smc_conn, SmPointer client_data) { EggSMClientXSMP *xsmp = client_data; EggSMClient *client = client_data; g_debug ("Received Die message in state %s", EGG_SM_CLIENT_XSMP_STATE (xsmp)); sm_client_xsmp_disconnect (xsmp); egg_sm_client_quit (client); } static void xsmp_save_complete (SmcConn smc_conn, SmPointer client_data) { EggSMClientXSMP *xsmp = client_data; g_debug ("Received SaveComplete message in state %s", EGG_SM_CLIENT_XSMP_STATE (xsmp)); if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE) xsmp->state = XSMP_STATE_IDLE; else fix_broken_state (xsmp, "SaveComplete", FALSE, FALSE); } static void xsmp_shutdown_cancelled (SmcConn smc_conn, SmPointer client_data) { EggSMClientXSMP *xsmp = client_data; EggSMClient *client = client_data; g_debug ("Received ShutdownCancelled message in state %s", EGG_SM_CLIENT_XSMP_STATE (xsmp)); xsmp->shutting_down = FALSE; if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE) { /* We've finished interacting and now the SM has agreed to * cancel the shutdown. */ xsmp->state = XSMP_STATE_IDLE; egg_sm_client_quit_cancelled (client); } else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED) { /* Hm... ok, so we got a shutdown SaveYourself, which got * cancelled, but the application was still interacting, so we * didn't tell it yet, and then *another* SaveYourself arrived, * which we must still be waiting to tell the app about, except * that now that SaveYourself has been cancelled too! Dizzy yet? */ xsmp->waiting_to_save_myself = FALSE; update_pending_events (xsmp); } else { g_debug ("Sending SaveYourselfDone(False)"); SmcSaveYourselfDone (xsmp->connection, False); if (xsmp->state == XSMP_STATE_INTERACT) { /* The application is currently interacting, so we can't * tell it about the cancellation yet; we will wait until * after it calls egg_sm_client_will_quit(). */ xsmp->state = XSMP_STATE_SHUTDOWN_CANCELLED; } else { /* The shutdown was cancelled before the application got a * chance to interact. */ xsmp->state = XSMP_STATE_IDLE; } } } /* Utilities */ /* Create a restart/clone/Exec command based on @restart_command. * If @client_id is non-%NULL, add "--sm-client-id @client_id". * If @state_file is non-%NULL, add "--sm-client-state-file @state_file". * * None of the input strings are g_strdup()ed; the caller must keep * them around until it is done with the returned GPtrArray, and must * then free the array, but not its contents. */ static GPtrArray * generate_command (char **restart_command, const char *client_id, const char *state_file) { GPtrArray *cmd; int i; cmd = g_ptr_array_new (); g_ptr_array_add (cmd, restart_command[0]); if (client_id) { g_ptr_array_add (cmd, (char *)"--sm-client-id"); g_ptr_array_add (cmd, (char *)client_id); } if (state_file) { g_ptr_array_add (cmd, (char *)"--sm-client-state-file"); g_ptr_array_add (cmd, (char *)state_file); } for (i = 1; restart_command[i]; i++) g_ptr_array_add (cmd, restart_command[i]); return cmd; } /* Takes a NULL-terminated list of SmProp * values, created by * array_prop, ptrarray_prop, string_prop, card8_prop, sets them, and * frees them. */ static void set_properties (EggSMClientXSMP *xsmp, ...) { GPtrArray *props; SmProp *prop; va_list ap; guint i; props = g_ptr_array_new (); va_start (ap, xsmp); while ((prop = va_arg (ap, SmProp *))) g_ptr_array_add (props, prop); va_end (ap); if (xsmp->connection) { SmcSetProperties (xsmp->connection, props->len, (SmProp **)props->pdata); } for (i = 0; i < props->len; i++) { prop = props->pdata[i]; g_free (prop->vals); g_free (prop); } g_ptr_array_free (props, TRUE); } /* Takes a NULL-terminated list of property names and deletes them. */ static void delete_properties (EggSMClientXSMP *xsmp, ...) { GPtrArray *props; char *prop; va_list ap; if (!xsmp->connection) return; props = g_ptr_array_new (); va_start (ap, xsmp); while ((prop = va_arg (ap, char *))) g_ptr_array_add (props, prop); va_end (ap); SmcDeleteProperties (xsmp->connection, props->len, (char **)props->pdata); g_ptr_array_free (props, TRUE); } /* Takes an array of strings and creates a LISTofARRAY8 property. The * strings are neither dupped nor freed; they need to remain valid * until you're done with the SmProp. */ static SmProp * array_prop (const char *name, ...) { SmProp *prop; SmPropValue pv; GArray *vals; char *value; va_list ap; prop = g_new (SmProp, 1); prop->name = (char *)name; prop->type = (char *)SmLISTofARRAY8; vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue)); va_start (ap, name); while ((value = va_arg (ap, char *))) { pv.length = strlen (value); pv.value = value; g_array_append_val (vals, pv); } va_end (ap); prop->num_vals = vals->len; prop->vals = (SmPropValue *)vals->data; g_array_free (vals, FALSE); return prop; } /* Takes a GPtrArray of strings and creates a LISTofARRAY8 property. * The array contents are neither dupped nor freed; they need to * remain valid until you're done with the SmProp. */ static SmProp * ptrarray_prop (const char *name, GPtrArray *values) { SmProp *prop; SmPropValue pv; GArray *vals; guint i; prop = g_new (SmProp, 1); prop->name = (char *)name; prop->type = (char *)SmLISTofARRAY8; vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue)); for (i = 0; i < values->len; i++) { pv.length = strlen (values->pdata[i]); pv.value = values->pdata[i]; g_array_append_val (vals, pv); } prop->num_vals = vals->len; prop->vals = (SmPropValue *)vals->data; g_array_free (vals, FALSE); return prop; } /* Takes a string and creates an ARRAY8 property. The string is * neither dupped nor freed; it needs to remain valid until you're * done with the SmProp. */ static SmProp * string_prop (const char *name, const char *value) { SmProp *prop; prop = g_new (SmProp, 1); prop->name = (char *)name; prop->type = (char *)SmARRAY8; prop->num_vals = 1; prop->vals = g_new (SmPropValue, 1); prop->vals[0].length = strlen (value); prop->vals[0].value = (char *)value; return prop; } /* Takes a char and creates a CARD8 property. */ static SmProp * card8_prop (const char *name, unsigned char value) { SmProp *prop; char *card8val; /* To avoid having to allocate and free prop->vals[0], we cheat and * make vals a 2-element-long array and then use the second element * to store value. */ prop = g_new (SmProp, 1); prop->name = (char *)name; prop->type = (char *)SmCARD8; prop->num_vals = 1; prop->vals = g_new (SmPropValue, 2); card8val = (char *)(&prop->vals[1]); card8val[0] = value; prop->vals[0].length = 1; prop->vals[0].value = card8val; return prop; } /* ICE code. This makes no effort to play nice with anyone else trying * to use libICE. Fortunately, no one uses libICE for anything other * than SM. (DCOP uses ICE, but it has its own private copy of * libICE.) * * When this moves to gtk, it will need to be cleverer, to avoid * tripping over old apps that use GnomeClient or that use libSM * directly. */ #include #include static void ice_error_handler (IceConn ice_conn, Bool swap, int offending_minor_opcode, unsigned long offending_sequence, int error_class, int severity, IcePointer values); static void ice_io_error_handler (IceConn ice_conn); static void ice_connection_watch (IceConn ice_conn, IcePointer client_data, Bool opening, IcePointer *watch_data); static void ice_init (void) { IceSetIOErrorHandler (ice_io_error_handler); IceSetErrorHandler (ice_error_handler); IceAddConnectionWatch (ice_connection_watch, NULL); } static gboolean process_ice_messages (IceConn ice_conn) { IceProcessMessagesStatus status; gdk_threads_enter (); status = IceProcessMessages (ice_conn, NULL, NULL); gdk_threads_leave (); switch (status) { case IceProcessMessagesSuccess: return TRUE; case IceProcessMessagesIOError: sm_client_xsmp_disconnect (IceGetConnectionContext (ice_conn)); return FALSE; case IceProcessMessagesConnectionClosed: return FALSE; default: g_assert_not_reached (); } } static gboolean ice_iochannel_watch (GIOChannel *channel, GIOCondition condition, gpointer client_data) { return process_ice_messages (client_data); } static void ice_connection_watch (IceConn ice_conn, IcePointer client_data, Bool opening, IcePointer *watch_data) { guint watch_id; if (opening) { GIOChannel *channel; int fd = IceConnectionNumber (ice_conn); fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC); channel = g_io_channel_unix_new (fd); watch_id = g_io_add_watch (channel, G_IO_IN | G_IO_ERR, ice_iochannel_watch, ice_conn); g_io_channel_unref (channel); *watch_data = GUINT_TO_POINTER (watch_id); } else { watch_id = GPOINTER_TO_UINT (*watch_data); if (watch_id) { g_source_remove (watch_id); watch_id = 0; } } } static void ice_error_handler (IceConn ice_conn, Bool swap, int offending_minor_opcode, unsigned long offending_sequence, int error_class, int severity, IcePointer values) { /* Do nothing */ } static void ice_io_error_handler (IceConn ice_conn) { /* Do nothing */ } static void smc_error_handler (SmcConn smc_conn, Bool swap, int offending_minor_opcode, unsigned long offending_sequence, int error_class, int severity, SmPointer values) { /* Do nothing */ } cinnamon-session-3.6.1/egg/eggsmclient.c0000644000175000017500000004516213205266677016757 0ustar maxymaxy/* * Copyright (C) 2007 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ #include "config.h" #include #include #include "eggsmclient.h" #include "eggsmclient-private.h" static void egg_sm_client_debug_handler (const char *log_domain, GLogLevelFlags log_level, const char *message, gpointer user_data); enum { SAVE_STATE, QUIT_REQUESTED, QUIT_CANCELLED, QUIT, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; struct _EggSMClientPrivate { GKeyFile *state_file; }; #define EGG_SM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_SM_CLIENT, EggSMClientPrivate)) G_DEFINE_TYPE (EggSMClient, egg_sm_client, G_TYPE_OBJECT) static EggSMClient *global_client; static EggSMClientMode global_client_mode = EGG_SM_CLIENT_MODE_NORMAL; static void egg_sm_client_init (EggSMClient *client) { ; } static void egg_sm_client_class_init (EggSMClientClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (EggSMClientPrivate)); /** * EggSMClient::save_state: * @client: the client * @state_file: a #GKeyFile to save state information into * * Emitted when the session manager has requested that the * application save information about its current state. The * application should save its state into @state_file, and then the * session manager may then restart the application in a future * session and tell it to initialize itself from that state. * * You should not save any data into @state_file's "start group" * (ie, the %NULL group). Instead, applications should save their * data into groups with names that start with the application name, * and libraries that connect to this signal should save their data * into groups with names that start with the library name. * * Alternatively, rather than (or in addition to) using @state_file, * the application can save its state by calling * egg_sm_client_set_restart_command() during the processing of this * signal (eg, to include a list of files to open). **/ signals[SAVE_STATE] = g_signal_new ("save_state", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggSMClientClass, save_state), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); /** * EggSMClient::quit_requested: * @client: the client * * Emitted when the session manager requests that the application * exit (generally because the user is logging out). The application * should decide whether or not it is willing to quit (perhaps after * asking the user what to do with documents that have unsaved * changes) and then call egg_sm_client_will_quit(), passing %TRUE * or %FALSE to give its answer to the session manager. (It does not * need to give an answer before returning from the signal handler; * it can interact with the user asynchronously and then give its * answer later on.) If the application does not connect to this * signal, then #EggSMClient will automatically return %TRUE on its * behalf. * * The application should not save its session state as part of * handling this signal; if the user has requested that the session * be saved when logging out, then ::save_state will be emitted * separately. * * If the application agrees to quit, it should then wait for either * the ::quit_cancelled or ::quit signals to be emitted. **/ signals[QUIT_REQUESTED] = g_signal_new ("quit_requested", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggSMClientClass, quit_requested), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * EggSMClient::quit_cancelled: * @client: the client * * Emitted when the session manager decides to cancel a logout after * the application has already agreed to quit. After receiving this * signal, the application can go back to what it was doing before * receiving the ::quit_requested signal. **/ signals[QUIT_CANCELLED] = g_signal_new ("quit_cancelled", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggSMClientClass, quit_cancelled), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); /** * EggSMClient::quit: * @client: the client * * Emitted when the session manager wants the application to quit * (generally because the user is logging out). The application * should exit as soon as possible after receiving this signal; if * it does not, the session manager may choose to forcibly kill it. * * Normally a GUI application would only be sent a ::quit if it * agreed to quit in response to a ::quit_requested signal. However, * this is not guaranteed; in some situations the session manager * may decide to end the session without giving applications a * chance to object. **/ signals[QUIT] = g_signal_new ("quit", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (EggSMClientClass, quit), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static gboolean sm_client_disable = FALSE; static char *sm_client_state_file = NULL; static char *sm_client_id = NULL; static char *sm_config_prefix = NULL; static gboolean sm_client_post_parse_func (GOptionContext *context, GOptionGroup *group, gpointer data, GError **error) { EggSMClient *client = egg_sm_client_get (); if (sm_client_id == NULL) { const gchar *desktop_autostart_id; desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID"); if (desktop_autostart_id != NULL) sm_client_id = g_strdup (desktop_autostart_id); } /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to * use the same client id. */ g_unsetenv ("DESKTOP_AUTOSTART_ID"); if (global_client_mode != EGG_SM_CLIENT_MODE_DISABLED && EGG_SM_CLIENT_GET_CLASS (client)->startup) EGG_SM_CLIENT_GET_CLASS (client)->startup (client, sm_client_id); return TRUE; } /** * egg_sm_client_get_option_group: * * Creates a %GOptionGroup containing the session-management-related * options. You should add this group to the application's * %GOptionContext if you want to use #EggSMClient. * * Return value: the %GOptionGroup **/ GOptionGroup * egg_sm_client_get_option_group (void) { const GOptionEntry entries[] = { { "sm-client-disable", 0, 0, G_OPTION_ARG_NONE, &sm_client_disable, N_("Disable connection to session manager"), NULL }, { "sm-client-state-file", 0, 0, G_OPTION_ARG_FILENAME, &sm_client_state_file, N_("Specify file containing saved configuration"), N_("FILE") }, { "sm-client-id", 0, 0, G_OPTION_ARG_STRING, &sm_client_id, N_("Specify session management ID"), N_("ID") }, /* GnomeClient compatibility option */ { "sm-disable", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &sm_client_disable, NULL, NULL }, /* GnomeClient compatibility option. This is a dummy option that only * exists so that sessions saved by apps with GnomeClient can be restored * later when they've switched to EggSMClient. See bug #575308. */ { "sm-config-prefix", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &sm_config_prefix, NULL, NULL }, { NULL } }; GOptionGroup *group; /* Use our own debug handler for the "EggSMClient" domain. */ g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, egg_sm_client_debug_handler, NULL); group = g_option_group_new ("sm-client", _("Session management options:"), _("Show session management options"), NULL, NULL); g_option_group_add_entries (group, entries); g_option_group_set_parse_hooks (group, NULL, sm_client_post_parse_func); return group; } /** * egg_sm_client_set_mode: * @mode: an #EggSMClient mode * * Sets the "mode" of #EggSMClient as follows: * * %EGG_SM_CLIENT_MODE_DISABLED: Session management is completely * disabled, until the mode is changed again. The application will * not even connect to the session manager. (egg_sm_client_get() * will still return an #EggSMClient object.) * * %EGG_SM_CLIENT_MODE_NO_RESTART: The application will connect to * the session manager (and thus will receive notification when the * user is logging out, etc), but will request to not be * automatically restarted with saved state in future sessions. * * %EGG_SM_CLIENT_MODE_NORMAL: The default. #EggSMCLient will * function normally. * * This must be called before the application's main loop begins and * before any call to egg_sm_client_get(), unless the mode was set * earlier to %EGG_SM_CLIENT_MODE_DISABLED and this call enables * session management. Note that option parsing will call * egg_sm_client_get(). **/ void egg_sm_client_set_mode (EggSMClientMode mode) { EggSMClientMode old_mode = global_client_mode; g_return_if_fail (global_client == NULL || global_client_mode == EGG_SM_CLIENT_MODE_DISABLED); g_return_if_fail (!(global_client != NULL && mode == EGG_SM_CLIENT_MODE_DISABLED)); global_client_mode = mode; if (global_client != NULL && old_mode == EGG_SM_CLIENT_MODE_DISABLED) { if (EGG_SM_CLIENT_GET_CLASS (global_client)->startup) EGG_SM_CLIENT_GET_CLASS (global_client)->startup (global_client, sm_client_id); } } /** * egg_sm_client_get_mode: * * Gets the global #EggSMClientMode. See egg_sm_client_set_mode() * for details. * * Return value: the global #EggSMClientMode **/ EggSMClientMode egg_sm_client_get_mode (void) { return global_client_mode; } /** * egg_sm_client_get: * * Returns the master #EggSMClient for the application. * * On platforms that support saved sessions (ie, POSIX/X11), the * application will only request to be restarted by the session * manager if you call egg_set_desktop_file() to set an application * desktop file. In particular, if the desktop file contains the key * "X * * Return value: the master #EggSMClient. **/ EggSMClient * egg_sm_client_get (void) { if (!global_client) { if (!sm_client_disable) { #if defined (GDK_WINDOWING_WIN32) global_client = egg_sm_client_win32_new (); #elif defined (GDK_WINDOWING_QUARTZ) global_client = egg_sm_client_osx_new (); #else /* If both D-Bus and XSMP are compiled in, try XSMP first * (since it supports state saving) and fall back to D-Bus * if XSMP isn't available. */ # ifdef EGG_SM_CLIENT_BACKEND_XSMP global_client = egg_sm_client_xsmp_new (); # endif # ifdef EGG_SM_CLIENT_BACKEND_DBUS if (!global_client) global_client = egg_sm_client_dbus_new (); # endif #endif } /* Fallback: create a dummy client, so that callers don't have * to worry about a %NULL return value. */ if (!global_client) global_client = g_object_new (EGG_TYPE_SM_CLIENT, NULL); } return global_client; } /** * egg_sm_client_is_resumed: * @client: the client * * Checks whether or not the current session has been resumed from * a previous saved session. If so, the application should call * egg_sm_client_get_state_file() and restore its state from the * returned #GKeyFile. * * Return value: %TRUE if the session has been resumed **/ gboolean egg_sm_client_is_resumed (EggSMClient *client) { g_return_val_if_fail (client == global_client, FALSE); return sm_client_state_file != NULL; } /** * egg_sm_client_get_state_file: * @client: the client * * If the application was resumed by the session manager, this will * return the #GKeyFile containing its state from the previous * session. * * Note that other libraries and #EggSMClient itself may also store * state in the key file, so if you call egg_sm_client_get_groups(), * on it, the return value will likely include groups that you did not * put there yourself. (It is also not guaranteed that the first * group created by the application will still be the "start group" * when it is resumed.) * * Return value: the #GKeyFile containing the application's earlier * state, or %NULL on error. You should not free this key file; it * is owned by @client. **/ GKeyFile * egg_sm_client_get_state_file (EggSMClient *client) { EggSMClientPrivate *priv = EGG_SM_CLIENT_GET_PRIVATE (client); char *state_file_path; GError *err = NULL; g_return_val_if_fail (client == global_client, NULL); if (!sm_client_state_file) return NULL; if (priv->state_file) return priv->state_file; if (!strncmp (sm_client_state_file, "file://", 7)) state_file_path = g_filename_from_uri (sm_client_state_file, NULL, NULL); else state_file_path = g_strdup (sm_client_state_file); priv->state_file = g_key_file_new (); if (!g_key_file_load_from_file (priv->state_file, state_file_path, 0, &err)) { g_warning ("Could not load SM state file '%s': %s", sm_client_state_file, err->message); g_clear_error (&err); g_key_file_free (priv->state_file); priv->state_file = NULL; } g_free (state_file_path); return priv->state_file; } /** * egg_sm_client_set_restart_command: * @client: the client * @argc: the length of @argv * @argv: argument vector * * Sets the command used to restart @client if it does not have a * .desktop file that can be used to find its restart command. * * This can also be used when handling the ::save_state signal, to * save the current state via an updated command line. (Eg, providing * a list of filenames to open when the application is resumed.) **/ void egg_sm_client_set_restart_command (EggSMClient *client, int argc, const char **argv) { g_return_if_fail (EGG_IS_SM_CLIENT (client)); if (EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command) EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command (client, argc, argv); } /** * egg_sm_client_will_quit: * @client: the client * @will_quit: whether or not the application is willing to quit * * This MUST be called in response to the ::quit_requested signal, to * indicate whether or not the application is willing to quit. The * application may call it either directly from the signal handler, or * at some later point (eg, after asynchronously interacting with the * user). * * If the application does not connect to ::quit_requested, * #EggSMClient will call this method on its behalf (passing %TRUE * for @will_quit). * * After calling this method, the application should wait to receive * either ::quit_cancelled or ::quit. **/ void egg_sm_client_will_quit (EggSMClient *client, gboolean will_quit) { g_return_if_fail (EGG_IS_SM_CLIENT (client)); if (EGG_SM_CLIENT_GET_CLASS (client)->will_quit) EGG_SM_CLIENT_GET_CLASS (client)->will_quit (client, will_quit); } /** * egg_sm_client_end_session: * @style: a hint at how to end the session * @request_confirmation: whether or not the user should get a chance * to confirm the action * * Requests that the session manager end the current session. @style * indicates how the session should be ended, and * @request_confirmation indicates whether or not the user should be * given a chance to confirm the logout/reboot/shutdown. Both of these * flags are merely hints though; the session manager may choose to * ignore them. * * Return value: %TRUE if the request was sent; %FALSE if it could not * be (eg, because it could not connect to the session manager). **/ gboolean egg_sm_client_end_session (EggSMClientEndStyle style, gboolean request_confirmation) { EggSMClient *client = egg_sm_client_get (); g_return_val_if_fail (EGG_IS_SM_CLIENT (client), FALSE); if (EGG_SM_CLIENT_GET_CLASS (client)->end_session) { return EGG_SM_CLIENT_GET_CLASS (client)->end_session (client, style, request_confirmation); } else return FALSE; } /* Signal-emitting callbacks from platform-specific code */ GKeyFile * egg_sm_client_save_state (EggSMClient *client) { GKeyFile *state_file; char *group; g_return_val_if_fail (client == global_client, NULL); state_file = g_key_file_new (); g_debug ("Emitting save_state"); g_signal_emit (client, signals[SAVE_STATE], 0, state_file); g_debug ("Done emitting save_state"); group = g_key_file_get_start_group (state_file); if (group) { g_free (group); return state_file; } else { g_key_file_free (state_file); return NULL; } } void egg_sm_client_quit_requested (EggSMClient *client) { g_return_if_fail (client == global_client); if (!g_signal_has_handler_pending (client, signals[QUIT_REQUESTED], 0, FALSE)) { g_debug ("Not emitting quit_requested because no one is listening"); egg_sm_client_will_quit (client, TRUE); return; } g_debug ("Emitting quit_requested"); g_signal_emit (client, signals[QUIT_REQUESTED], 0); g_debug ("Done emitting quit_requested"); } void egg_sm_client_quit_cancelled (EggSMClient *client) { g_return_if_fail (client == global_client); g_debug ("Emitting quit_cancelled"); g_signal_emit (client, signals[QUIT_CANCELLED], 0); g_debug ("Done emitting quit_cancelled"); } void egg_sm_client_quit (EggSMClient *client) { g_return_if_fail (client == global_client); g_debug ("Emitting quit"); g_signal_emit (client, signals[QUIT], 0); g_debug ("Done emitting quit"); /* FIXME: should we just call gtk_main_quit() here? */ } static void egg_sm_client_debug_handler (const char *log_domain, GLogLevelFlags log_level, const char *message, gpointer user_data) { static int debug = -1; if (debug < 0) debug = (g_getenv ("EGG_SM_CLIENT_DEBUG") != NULL); if (debug) g_log_default_handler (log_domain, log_level, message, NULL); } cinnamon-session-3.6.1/egg/eggsmclient.h0000644000175000017500000000771013205266677016761 0ustar maxymaxy/* eggsmclient.h * Copyright (C) 2007 Novell, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street - Suite 500, * Boston, MA 02110-1335, USA. */ #ifndef __EGG_SM_CLIENT_H__ #define __EGG_SM_CLIENT_H__ #include G_BEGIN_DECLS #define EGG_TYPE_SM_CLIENT (egg_sm_client_get_type ()) #define EGG_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT, EggSMClient)) #define EGG_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT, EggSMClientClass)) #define EGG_IS_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT)) #define EGG_IS_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT)) #define EGG_SM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT, EggSMClientClass)) typedef struct _EggSMClient EggSMClient; typedef struct _EggSMClientClass EggSMClientClass; typedef struct _EggSMClientPrivate EggSMClientPrivate; typedef enum { EGG_SM_CLIENT_END_SESSION_DEFAULT, EGG_SM_CLIENT_LOGOUT, EGG_SM_CLIENT_REBOOT, EGG_SM_CLIENT_SHUTDOWN } EggSMClientEndStyle; typedef enum { EGG_SM_CLIENT_MODE_DISABLED, EGG_SM_CLIENT_MODE_NO_RESTART, EGG_SM_CLIENT_MODE_NORMAL } EggSMClientMode; struct _EggSMClient { GObject parent; }; struct _EggSMClientClass { GObjectClass parent_class; /* signals */ void (*save_state) (EggSMClient *client, GKeyFile *state_file); void (*quit_requested) (EggSMClient *client); void (*quit_cancelled) (EggSMClient *client); void (*quit) (EggSMClient *client); /* virtual methods */ void (*startup) (EggSMClient *client, const char *client_id); void (*set_restart_command) (EggSMClient *client, int argc, const char **argv); void (*will_quit) (EggSMClient *client, gboolean will_quit); gboolean (*end_session) (EggSMClient *client, EggSMClientEndStyle style, gboolean request_confirmation); /* Padding for future expansion */ void (*_egg_reserved1) (void); void (*_egg_reserved2) (void); void (*_egg_reserved3) (void); void (*_egg_reserved4) (void); }; GType egg_sm_client_get_type (void) G_GNUC_CONST; GOptionGroup *egg_sm_client_get_option_group (void); /* Initialization */ void egg_sm_client_set_mode (EggSMClientMode mode); EggSMClientMode egg_sm_client_get_mode (void); EggSMClient *egg_sm_client_get (void); /* Resuming a saved session */ gboolean egg_sm_client_is_resumed (EggSMClient *client); GKeyFile *egg_sm_client_get_state_file (EggSMClient *client); /* Alternate means of saving state */ void egg_sm_client_set_restart_command (EggSMClient *client, int argc, const char **argv); /* Handling "quit_requested" signal */ void egg_sm_client_will_quit (EggSMClient *client, gboolean will_quit); /* Initiate a logout/reboot/shutdown */ gboolean egg_sm_client_end_session (EggSMClientEndStyle style, gboolean request_confirmation); G_END_DECLS #endif /* __EGG_SM_CLIENT_H__ */ cinnamon-session-3.6.1/makepot0000755000175000017500000000033213205266677015124 0ustar maxymaxy#!/bin/bash intltool-extract --type=gettext/glade data/*.glade xgettext --language=C --keyword=_ --keyword=N_ --output=cinnamon-session.pot cinnamon-session/*.c tools/*.c egg/*.c data/*.glade.h rm -f data/*.glade.h cinnamon-session-3.6.1/po/0000755000175000017500000000000013205266677014156 5ustar maxymaxycinnamon-session-3.6.1/po/LINGUAS0000644000175000017500000000000013205266677015171 0ustar maxymaxycinnamon-session-3.6.1/po/Makefile.in.in0000644000175000017500000001604613205266677016637 0ustar maxymaxy# Makefile for program source directory in GNU NLS utilities package. # Copyright (C) 1995, 1996, 1997 by Ulrich Drepper # Copyright (C) 2004-2008 Rodney Dawes # # This file may be copied and used freely without restrictions. It may # be used in projects which are not available under a GNU Public License, # but which still want to provide support for the GNU gettext functionality. # # - Modified by Owen Taylor to use GETTEXT_PACKAGE # instead of PACKAGE and to look for po2tbl in ./ not in intl/ # # - Modified by jacob berkman to install # Makefile.in.in and po2tbl.sed.in for use with glib-gettextize # # - Modified by Rodney Dawes for use with intltool # # We have the following line for use by intltoolize: # INTLTOOL_MAKEFILE GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ PACKAGE = @PACKAGE@ VERSION = @VERSION@ SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ datadir = @datadir@ datarootdir = @datarootdir@ libdir = @libdir@ DATADIRNAME = @DATADIRNAME@ itlocaledir = $(prefix)/$(DATADIRNAME)/locale subdir = po install_sh = @install_sh@ # Automake >= 1.8 provides @mkdir_p@. # Until it can be supposed, use the safe fallback: mkdir_p = $(install_sh) -d INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ GMSGFMT = @GMSGFMT@ MSGFMT = @MSGFMT@ XGETTEXT = @XGETTEXT@ INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ MSGMERGE = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist GENPOT = INTLTOOL_EXTRACT="$(INTLTOOL_EXTRACT)" XGETTEXT="$(XGETTEXT)" srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot ALL_LINGUAS = @ALL_LINGUAS@ PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi) USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep \^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep \^$$lang$$`"; then printf "$$lang "; fi; done; fi) USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done) POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done) DISTFILES = Makefile.in.in POTFILES.in $(POFILES) EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS POTFILES = \ # This comment gets stripped out CATALOGS=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) .SUFFIXES: .SUFFIXES: .po .pox .gmo .mo .msg .cat AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ INTLTOOL_V_MSGFMT = $(INTLTOOL__v_MSGFMT_$(V)) INTLTOOL__v_MSGFMT_= $(INTLTOOL__v_MSGFMT_$(AM_DEFAULT_VERBOSITY)) INTLTOOL__v_MSGFMT_0 = @echo " MSGFMT" $@; .po.pox: $(MAKE) $(GETTEXT_PACKAGE).pot $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox .po.mo: $(INTLTOOL_V_MSGFMT)$(MSGFMT) -o $@ $< .po.gmo: $(INTLTOOL_V_MSGFMT)file=`echo $* | sed 's,.*/,,'`.gmo \ && rm -f $$file && $(GMSGFMT) -o $$file $< .po.cat: sed -f ../intl/po2msg.sed < $< > $*.msg \ && rm -f $@ && gencat $@ $*.msg all: all-@USE_NLS@ all-yes: $(CATALOGS) all-no: $(GETTEXT_PACKAGE).pot: $(POTFILES) $(GENPOT) install: install-data install-data: install-data-@USE_NLS@ install-data-no: all install-data-yes: all linguas="$(USE_LINGUAS)"; \ for lang in $$linguas; do \ dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \ $(mkdir_p) $$dir; \ if test -r $$lang.gmo; then \ $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ else \ $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ echo "installing $(srcdir)/$$lang.gmo as" \ "$$dir/$(GETTEXT_PACKAGE).mo"; \ fi; \ if test -r $$lang.gmo.m; then \ $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ else \ if test -r $(srcdir)/$$lang.gmo.m ; then \ $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ $$dir/$(GETTEXT_PACKAGE).mo.m; \ echo "installing $(srcdir)/$$lang.gmo.m as" \ "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ else \ true; \ fi; \ fi; \ done # Empty stubs to satisfy archaic automake needs dvi info ctags tags CTAGS TAGS ID: # Define this as empty until I found a useful application. install-exec installcheck: uninstall: linguas="$(USE_LINGUAS)"; \ for lang in $$linguas; do \ rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ done check: all $(GETTEXT_PACKAGE).pot rm -f missing notexist srcdir=$(srcdir) $(INTLTOOL_UPDATE) -m if [ -r missing -o -r notexist ]; then \ exit 1; \ fi mostlyclean: rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp rm -f .intltool-merge-cache clean: mostlyclean distclean: clean rm -f Makefile Makefile.in POTFILES stamp-it rm -f *.mo *.msg *.cat *.cat.m *.gmo maintainer-clean: distclean @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." rm -f Makefile.in.in distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) dist distdir: $(DISTFILES) dists="$(DISTFILES)"; \ extra_dists="$(EXTRA_DISTFILES)"; \ for file in $$extra_dists; do \ test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ done; \ for file in $$dists; do \ test -f $$file || file="$(srcdir)/$$file"; \ ln $$file $(distdir) 2> /dev/null \ || cp -p $$file $(distdir); \ done update-po: Makefile $(MAKE) $(GETTEXT_PACKAGE).pot tmpdir=`pwd`; \ linguas="$(USE_LINGUAS)"; \ for lang in $$linguas; do \ echo "$$lang:"; \ result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ if $$result; then \ if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ rm -f $$tmpdir/$$lang.new.po; \ else \ if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ :; \ else \ echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ rm -f $$tmpdir/$$lang.new.po; \ exit 1; \ fi; \ fi; \ else \ echo "msgmerge for $$lang.gmo failed!"; \ rm -f $$tmpdir/$$lang.new.po; \ fi; \ done Makefile POTFILES: stamp-it @if test ! -f $@; then \ rm -f stamp-it; \ $(MAKE) stamp-it; \ fi stamp-it: Makefile.in.in $(top_builddir)/config.status POTFILES.in cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ $(SHELL) ./config.status # Tell versions [3.59,3.63) of GNU make not to export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: cinnamon-session-3.6.1/po/POTFILES.in0000644000175000017500000000102213205266677015726 0ustar maxymaxy# List of source files containing translatable strings. # Please keep this file sorted alphabetically. [type: gettext/glade]data/csm-inhibit-dialog.glade egg/eggdesktopfile.c egg/eggsmclient.c cinnamon-session/csm-inhibit-dialog.c cinnamon-session/csm-logout-dialog.c cinnamon-session/csm-fail-whale-dialog.c cinnamon-session/csm-process-helper.c cinnamon-session/csm-manager.c cinnamon-session/csm-xsmp-client.c cinnamon-session/csm-xsmp-server.c cinnamon-session/csm-util.c cinnamon-session/main.c tools/cinnamon-session-quit.c cinnamon-session-3.6.1/po/POTFILES.skip0000644000175000017500000000030113205266677016265 0ustar maxymaxy# List of source files containing translatable strings that should not be # translated. # Please keep this file sorted alphabetically. data/cinnamon-session.schemas.in data/gnome-wm.desktop.in cinnamon-session-3.6.1/tools/0000755000175000017500000000000013205266677014700 5ustar maxymaxycinnamon-session-3.6.1/tools/Makefile.am0000644000175000017500000000231213205266677016732 0ustar maxymaxybin_PROGRAMS = cinnamon-session-quit libexec_PROGRAMS = cinnamon-session-check-accelerated cinnamon-session-check-accelerated-helper AM_CPPFLAGS = AM_CFLAGS = $(WARN_CFLAGS) cinnamon_session_quit_SOURCES = \ cinnamon-session-quit.c cinnamon_session_quit_CPPFLAGS = \ $(AM_CPPFLAGS) \ $(CINNAMON_SESSION_CFLAGS) \ $(DBUS_GLIB_CFLAGS) \ $(GCONF_FLAGS) \ -DLOCALE_DIR=\""$(datadir)/locale"\" \ $(DISABLE_DEPRECATED_CFLAGS) cinnamon_session_quit_LDADD = \ $(SM_LIBS) \ $(ICE_LIBS) \ $(CINNAMON_SESSION_LIBS) \ $(DBUS_GLIB_LIBS) \ $(GCONF_LIBS) cinnamon_session_check_accelerated_helper_SOURCES = \ cinnamon-session-check-accelerated-helper.c cinnamon_session_check_accelerated_helper_CPPFLAGS = \ -DPKGDATADIR=\""$(pkgdatadir)"\" \ $(GL_TEST_CFLAGS) cinnamon_session_check_accelerated_helper_LDADD = \ $(GL_TEST_LIBS) \ $(X_LIBS) cinnamon_session_check_accelerated_SOURCES = \ cinnamon-session-check-accelerated.c cinnamon_session_check_accelerated_CPPFLAGS = \ -DLIBEXECDIR=\""$(libexecdir)"\" \ $(AM_CPPFLAGS) \ $(GTK3_CFLAGS) cinnamon_session_check_accelerated_LDADD = \ $(GTK3_LIBS) \ $(X_LIBS) -include $(top_srcdir)/git.mk cinnamon-session-3.6.1/tools/cinnamon-session-check-accelerated-helper.c0000644000175000017500000003216313205266677025116 0ustar maxymaxy/* gcc -o cinnamon-session-accelerated `pkg-config --cflags --libs xcomposite gl` -Wall cinnamon-session-is-accelerated.c */ /* * Copyright (C) 2010 Novell, Inc. * Copyright (C) 2006-2009 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA * * Author: * Vincent Untz * * Most of the code comes from desktop-effects [1], released under GPLv2+. * desktop-effects was written by: * Soren Sandmann * * [1] http://git.fedorahosted.org/git/?p=desktop-effects.git;a=blob_plain;f=desktop-effects.c;hb=HEAD */ /* * Here's the rationale behind this helper, quoting Owen, in his mail to the * release team: * (http://mail.gnome.org/archives/release-team/2010-June/msg00079.html) * * """ * There are some limits to what we can do here automatically without * knowing anything about the driver situation on the system. The basic * problem is that there are all sorts of suck: * * * No GL at all. This typically only happens if a system is * misconfigured. * * * Only software GL. This one is easy to detect. We have code in * the Fedora desktop-effects tool, etc. * * * GL that isn't featureful enough. (Tiny texture size limits, no * texture-from-pixmap, etc.) Possible to detect with more work, but * largely a fringe case. * * * Buggy GL. This isn't possible to detect. Except for the case where * all GL programs crash. For that reason, we probably don't want * cinnamon-session to directly try and do any GL detection; better to * use a helper binary. * * * Horribly slow hardware GL. We could theoretically develop some sort * of benchmark, but it's a tricky area. And how slow is too slow? * """ * * Some other tools are doing similar checks: * - desktop-effects (Fedora Config Tool) [1] * - drak3d (Mandriva Config Tool) [2] * - compiz-manager (Compiz wrapper) [3] * * [1] http://git.fedorahosted.org/git/?p=desktop-effects.git;a=blob_plain;f=desktop-effects.c;hb=HEAD * [2] http://svn.mandriva.com/cgi-bin/viewvc.cgi/soft/drak3d/trunk/lib/Xconfig/glx.pm?view=markup * [3] http://git.compiz.org/fusion/misc/compiz-manager/tree/compiz-manager */ /* for strcasestr */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include static int max_texture_size = 0; static inline void _print_error (const char *str) { fprintf (stderr, "cinnamon-session-is-accelerated: %s\n", str); } static int _parse_kcmdline (void) { FILE *kcmdline; char *line = NULL; size_t line_len = 0; int ret = -1; kcmdline = fopen("/proc/cmdline", "r"); if (kcmdline == NULL) return ret; while (getline (&line, &line_len, kcmdline) != -1) { const char *arg; const char *str; int key_len = strlen ("gnome.fallback="); if (line == NULL) break; /* don't break if we found the argument once: last mention wins */ str = line; do { arg = strstr (str, "gnome.fallback="); str = arg + key_len; if (arg && (arg == line || isspace (arg[-1])) && /* gnome.fallback= is really the beginning of an argument */ (isdigit (arg[key_len]))) { /* the first character of the value of this argument is an integer */ if ((arg[key_len+1] == '\0' || isspace (arg[key_len+1]))) /* the value of this argument is only one character long */ ret = arg[key_len] - '0'; else /* invalid value */ ret = 0xDEAD; } } while (arg != NULL); free (line); line = NULL; line_len = 0; } fclose (kcmdline); return ret; } static int _has_composite (Display *display) { int dummy1, dummy2; if (XCompositeQueryExtension (display, &dummy1, &dummy2)) return 0; return 1; } static int _is_comment (const char *line) { while (*line && isspace(*line)) line++; if (*line == '#' || *line == '\0') return 0; else return 1; } static int _is_gl_renderer_blacklisted (const char *renderer) { FILE *blacklist; char *line = NULL; size_t line_len = 0; int ret = 1; blacklist = fopen(PKGDATADIR "/hardware-compatibility", "r"); if (blacklist == NULL) goto out; while (getline (&line, &line_len, blacklist) != -1) { int whitelist = 0; const char *re_str; regex_t re; int status; if (line == NULL) break; /* Drop trailing \n */ line[strlen(line) - 1] = '\0'; if (_is_comment (line) == 0) { free (line); line = NULL; continue; } if (line[0] == '+') whitelist = 1; else if (line[0] == '-') whitelist = 0; else { _print_error ("Invalid syntax in this line for hardware compatibility:"); _print_error (line); free (line); line = NULL; continue; } re_str = line + 1; if (regcomp (&re, re_str, REG_EXTENDED|REG_ICASE|REG_NOSUB) != 0) { _print_error ("Cannot use this regular expression for hardware compatibility:"); _print_error (re_str); } else { status = regexec (&re, renderer, 0, NULL, 0); regfree(&re); if (status == 0) { if (whitelist) ret = 0; goto out; } } free (line); line = NULL; } ret = 0; out: if (line != NULL) free (line); if (blacklist != NULL) fclose (blacklist); return ret; } static int _has_hardware_gl (Display *display) { int screen; Window root; XVisualInfo *visual = NULL; GLXContext context = NULL; XSetWindowAttributes cwa = { 0 }; Window window = None; const char *renderer; int ret = 1; int attrlist[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, None }; screen = DefaultScreen (display); root = RootWindow (display, screen); visual = glXChooseVisual (display, screen, attrlist); if (!visual) goto out; context = glXCreateContext (display, visual, NULL, True); if (!context) goto out; cwa.colormap = XCreateColormap (display, root, visual->visual, AllocNone); cwa.background_pixel = 0; cwa.border_pixel = 0; window = XCreateWindow (display, root, 0, 0, 1, 1, 0, visual->depth, InputOutput, visual->visual, CWColormap | CWBackPixel | CWBorderPixel, &cwa); if (!glXMakeCurrent (display, window, context)) goto out; renderer = (const char *) glGetString (GL_RENDERER); if (_is_gl_renderer_blacklisted (renderer) != 0) goto out; /* we need to get the max texture size while we have a context, * but we'll check its value later */ glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_texture_size); if (glGetError() != GL_NO_ERROR) max_texture_size = -1; ret = 0; out: glXMakeCurrent (display, None, None); if (context) glXDestroyContext (display, context); if (window) XDestroyWindow (display, window); if (cwa.colormap) XFreeColormap (display, cwa.colormap); return ret; } static int _has_extension (const char *extension_list, const char *extension) { int s = 0, e = 0; int ext_len; /* Extension_list is one big string, containing extensions * separated by spaces. We could use strstr, except that we * can't know for sure that there's no extension that starts * with the same string... */ if (!extension_list || extension_list[0] == 0) return 1; if (!extension || extension[0] == 0) return 0; ext_len = strlen (extension); while (1) { if (extension_list[e] != ' ' && extension_list[e] != 0) { e++; continue; } /* End of a word. Was is the extension we're looking for? */ if ((e - s) == ext_len && strncmp (&extension_list[s], extension, ext_len) == 0) { return 0; } /* was it the end of the string? */ if (extension_list[e] == 0) break; /* skip the space and start looking at the next word */ e++; s = e; } return 1; } static int _has_texture_from_pixmap (Display *display) { int screen; const char *server_extensions; const char *client_extensions; int ret = 1; screen = DefaultScreen (display); server_extensions = glXQueryServerString (display, screen, GLX_EXTENSIONS); if (_has_extension (server_extensions, "GLX_EXT_texture_from_pixmap") != 0) goto out; client_extensions = glXGetClientString (display, GLX_EXTENSIONS); if (_has_extension (client_extensions, "GLX_EXT_texture_from_pixmap") != 0) goto out; ret = 0; out: return ret; } static int _is_max_texture_size_big_enough (Display *display) { int screen; screen = DefaultScreen (display); if (max_texture_size < DisplayWidth (display, screen) || max_texture_size < DisplayHeight (display, screen)) return 1; return 0; } int main (int argc, char **argv) { int kcmdline_parsed; Display *display = NULL; int ret = 1; kcmdline_parsed = _parse_kcmdline (); if (kcmdline_parsed >= 0) { if (kcmdline_parsed == 0) { _print_error ("Non-fallback mode forced by kernel command line."); ret = 0; goto out; } else if (kcmdline_parsed == 1) { _print_error ("Fallback mode forced by kernel command line."); goto out; } else _print_error ("Invalid value for gnome.fallback passed in kernel command line."); } display = XOpenDisplay (NULL); if (!display) { _print_error ("No X display."); goto out; } if (_has_composite (display) != 0) { _print_error ("No composite extension."); goto out; } if (_has_hardware_gl (display) != 0) { _print_error ("No hardware 3D support."); goto out; } if (_has_texture_from_pixmap (display) != 0) { _print_error ("No GLX_EXT_texture_from_pixmap support."); goto out; } if (_is_max_texture_size_big_enough (display) != 0) { _print_error ("GL_MAX_TEXTURE_SIZE is too small."); goto out; } ret = 0; out: if (display) XCloseDisplay (display); return ret; } cinnamon-session-3.6.1/tools/cinnamon-session-check-accelerated.c0000644000175000017500000001332413205266677023637 0ustar maxymaxy/* -*- mode:c; c-basic-offset: 8; indent-tabs-mode: nil; -*- */ /* Tool to set the property _CINNAMON_SESSION_ACCELERATED on the root window */ /* * Copyright (C) 2011 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA * * Author: * Colin Walters */ #include #include #include #include #include #include /* Wait up to this long for a running check to finish */ #define PROPERTY_CHANGE_TIMEOUT 5000 /* Values used for the _CINNAMON_SESSION_ACCELERATED root window property */ #define NO_ACCEL 0 #define HAVE_ACCEL 1 #define ACCEL_CHECK_RUNNING 2 static Atom is_accelerated_atom; static gboolean property_changed; static void exit_1_message (const char *msg) G_GNUC_NORETURN; static void exit_1_message (const char *msg) { g_printerr ("%s", msg); exit (1); } static gboolean on_property_notify_timeout (gpointer data) { gtk_main_quit (); return FALSE; } static GdkFilterReturn property_notify_filter (GdkXEvent *xevent, GdkEvent *event, gpointer data) { XPropertyEvent *ev = xevent; if (ev->type == PropertyNotify && ev->atom == is_accelerated_atom) { property_changed = TRUE; gtk_main_quit (); } return GDK_FILTER_CONTINUE; } static gboolean wait_for_property_notify (void) { GdkDisplay *display = NULL; GdkScreen *screen; GdkWindow *root; Window rootwin; property_changed = FALSE; display = gdk_display_get_default (); screen = gdk_display_get_default_screen (display); root = gdk_screen_get_root_window (screen); rootwin = gdk_x11_window_get_xid (root); XSelectInput (GDK_DISPLAY_XDISPLAY (display), rootwin, PropertyChangeMask); gdk_window_add_filter (root, property_notify_filter, NULL); g_timeout_add (PROPERTY_CHANGE_TIMEOUT, on_property_notify_timeout, NULL); gtk_main (); return property_changed; } int main (int argc, char **argv) { GdkDisplay *display = NULL; int estatus; char *child_argv[] = { LIBEXECDIR "/cinnamon-session-check-accelerated-helper", NULL }; Window rootwin; glong is_accelerated; GError *error = NULL; gtk_init (NULL, NULL); display = gdk_display_get_default (); rootwin = gdk_x11_get_default_root_xwindow (); is_accelerated_atom = gdk_x11_get_xatom_by_name_for_display (display, "_CINNAMON_SESSION_ACCELERATED"); { Atom type; gint format; gulong nitems; gulong bytes_after; guchar *data; read: gdk_x11_display_error_trap_push (display); XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), rootwin, is_accelerated_atom, 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &data); gdk_x11_display_error_trap_pop_ignored (display); if (type == XA_CARDINAL) { glong *is_accelerated_ptr = (glong*) data; if (*is_accelerated_ptr == ACCEL_CHECK_RUNNING) { /* Test in progress, wait */ if (wait_for_property_notify ()) goto read; /* else fall through and do the check ourselves */ } else { return (*is_accelerated_ptr == 0 ? 1 : 0); } } } /* We don't have the property or it's the wrong type. * Try to compute it now. */ /* First indicate that a test is in progress */ is_accelerated = ACCEL_CHECK_RUNNING; XChangeProperty (GDK_DISPLAY_XDISPLAY (display), rootwin, is_accelerated_atom, XA_CARDINAL, 32, PropModeReplace, (guchar *) &is_accelerated, 1); gdk_display_sync (display); estatus = 1; if (!g_spawn_sync (NULL, (char**)child_argv, NULL, 0, NULL, NULL, NULL, NULL, &estatus, &error)) { is_accelerated = FALSE; g_printerr ("cinnamon-session-check-accelerated: Failed to run helper: %s\n", error->message); g_clear_error (&error); } else { is_accelerated = (estatus == 0); if (!is_accelerated) g_printerr ("cinnamon-session-check-accelerated: Helper exited with code %d\n", estatus); } XChangeProperty (GDK_DISPLAY_XDISPLAY (display), rootwin, is_accelerated_atom, XA_CARDINAL, 32, PropModeReplace, (guchar *) &is_accelerated, 1); gdk_display_sync (display); return is_accelerated ? 0 : 1; } cinnamon-session-3.6.1/tools/cinnamon-session-quit.c0000644000175000017500000001463613205266677021321 0ustar maxymaxy/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * save-session.c - Small program to talk to session manager. Copyright (C) 1998 Tom Tromey Copyright (C) 2008 Red Hat, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA 02110-1335, USA. */ #include #include #include #include #include #include #include #include #include #define CSM_SERVICE_DBUS "org.gnome.SessionManager" #define CSM_PATH_DBUS "/org/gnome/SessionManager" #define CSM_INTERFACE_DBUS "org.gnome.SessionManager" enum { CSM_LOGOUT_MODE_NORMAL = 0, CSM_LOGOUT_MODE_NO_CONFIRMATION, CSM_LOGOUT_MODE_FORCE }; static gboolean opt_logout = FALSE; static gboolean opt_power_off = FALSE; static gboolean opt_reboot = FALSE; static gboolean opt_no_prompt = FALSE; static gboolean opt_force = FALSE; static GOptionEntry options[] = { {"logout", '\0', 0, G_OPTION_ARG_NONE, &opt_logout, N_("Log out"), NULL}, {"power-off", '\0', 0, G_OPTION_ARG_NONE, &opt_power_off, N_("Power off"), NULL}, {"reboot", '\0', 0, G_OPTION_ARG_NONE, &opt_reboot, N_("Reboot"), NULL}, {"force", '\0', 0, G_OPTION_ARG_NONE, &opt_force, N_("Ignoring any existing inhibitors"), NULL}, {"no-prompt", '\0', 0, G_OPTION_ARG_NONE, &opt_no_prompt, N_("Don't prompt for user confirmation"), NULL}, {NULL} }; static void display_error (const char *message) { g_printerr ("%s\n", message); } static DBusGConnection * get_session_bus (void) { DBusGConnection *bus; GError *error = NULL; bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (bus == NULL) { g_warning ("Couldn't connect to session bus: %s", error->message); g_error_free (error); } return bus; } static DBusGProxy * get_sm_proxy (void) { DBusGConnection *connection; DBusGProxy *sm_proxy; connection = get_session_bus (); if (connection == NULL) { display_error (_("Could not connect to the session manager")); return NULL; } sm_proxy = dbus_g_proxy_new_for_name (connection, CSM_SERVICE_DBUS, CSM_PATH_DBUS, CSM_INTERFACE_DBUS); if (sm_proxy == NULL) { display_error (_("Could not connect to the session manager")); return NULL; } return sm_proxy; } static void do_logout (unsigned int mode) { DBusGProxy *sm_proxy; GError *error; gboolean res; sm_proxy = get_sm_proxy (); if (sm_proxy == NULL) { return; } error = NULL; res = dbus_g_proxy_call (sm_proxy, "Logout", &error, G_TYPE_UINT, mode, G_TYPE_INVALID, G_TYPE_INVALID); if (!res) { if (error != NULL) { g_warning ("Failed to call logout: %s", error->message); g_error_free (error); } else { g_warning ("Failed to call logout"); } } if (sm_proxy != NULL) { g_object_unref (sm_proxy); } } static void do_power_off (const char *action) { DBusGProxy *sm_proxy; GError *error; gboolean res; sm_proxy = get_sm_proxy (); if (sm_proxy == NULL) { return; } error = NULL; res = dbus_g_proxy_call (sm_proxy, action, &error, G_TYPE_INVALID, G_TYPE_INVALID); if (!res) { if (error != NULL) { g_warning ("Failed to call %s: %s", action, error->message); g_error_free (error); } else { g_warning ("Failed to call %s", action); } } if (sm_proxy != NULL) { g_object_unref (sm_proxy); } } int main (int argc, char *argv[]) { GError *error; int conflicting_options; /* Initialize the i18n stuff */ bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); error = NULL; if (! gtk_init_with_args (&argc, &argv, NULL, options, NULL, &error)) { g_warning ("Unable to start: %s", error->message); g_error_free (error); exit (1); } conflicting_options = 0; if (opt_logout) conflicting_options++; if (opt_power_off) conflicting_options++; if (opt_reboot) conflicting_options++; if (conflicting_options > 1) display_error (_("Program called with conflicting options")); if (opt_power_off) { do_power_off ("Shutdown"); } else if (opt_reboot) { do_power_off ("Reboot"); } else { /* default to logout */ if (opt_force) do_logout (CSM_LOGOUT_MODE_FORCE); else if (opt_no_prompt) do_logout (CSM_LOGOUT_MODE_NO_CONFIRMATION); else do_logout (CSM_LOGOUT_MODE_NORMAL); } return 0; }