[
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR)\n\nset(PROJECT_NAME slim)\nproject(${PROJECT_NAME})\n\n#Pretty colors\nset(CMAKE_COLOR_MAKEFILE ON)\n#Dont force verbose\nset(CMAKE_VERBOSE_MAKEFILE ON)\n#Include current dir\nset(CMAKE_INCLUDE_CURRENT_DIR TRUE)\n\nINCLUDE(CheckIncludeFile)\nINCLUDE(CheckCCompilerFlag)\nINCLUDE(CheckCXXCompilerFlag)\nINCLUDE(CheckTypeSize)\n\n# Version\nset(SLIM_VERSION_MAJOR \"1\")\nset(SLIM_VERSION_MINOR \"3\")\nset(SLIM_VERSION_PATCH \"6\")\nset(SLIM_VERSION \"${SLIM_VERSION_MAJOR}.${SLIM_VERSION_MINOR}.${SLIM_VERSION_PATCH}\")\n\nset(CMAKE_INSTALL_PREFIX \"/usr/local\" CACHE PATH \"Installation Directory\")\nset(PKGDATADIR \"${CMAKE_INSTALL_PREFIX}/share/slim\")\nset(SYSCONFDIR \"/etc\")\nset(LIBDIR \"/lib\")\nset(MANDIR \"${CMAKE_INSTALL_PREFIX}/share/man\")\n\nset(SLIM_DEFINITIONS)\nif(${CMAKE_SYSTEM_NAME} MATCHES \"FreeBSD\" OR\n\t\t${CMAKE_SYSTEM_NAME} MATCHES \"NetBSD\" OR\n\t\t${CMAKE_SYSTEM_NAME} MATCHES \"OpenBSD\"\n\t\t)\n\tset(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} \"-DNEEDS_BASENAME\")\nelse()\n\tset(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} \"-DHAVE_SHADOW\")\nendif()\n\nset(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} \"-DPACKAGE=\\\"slim\\\"\")\nset(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} \"-DVERSION=\\\"${SLIM_VERSION}\\\"\")\nset(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} \"-DPKGDATADIR=\\\"${PKGDATADIR}\\\"\")\nset(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} \"-DSYSCONFDIR=\\\"${SYSCONFDIR}\\\"\")\n\n# Flags\nset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Wall -g -O2\")\nset(CMAKE_CPP_FLAGS \"${CMAKE_CPP_FLAGS} -Wall -g -O2\")\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Wall -g -O2\")\n\n# source \nset(slim_srcs\n\tmain.cpp\n\tapp.cpp\n\tnumlock.cpp\n\tswitchuser.cpp\n\tpng.c\n\tjpeg.c\n)\n\nset(slimlock_srcs\n\tslimlock.cpp\n)\n\nset(common_srcs\n    cfg.cpp\n    image.cpp\n    log.cpp\n    panel.cpp\n    util.cpp\n)\nif(USE_PAM)\n\tset(common_srcs ${common_srcs} PAM.cpp)\n    # for now, only build slimlock if we are using PAM.\n    set(BUILD_SLIMLOCK 1)\nendif(USE_PAM)\n\n# Build common library\nset(BUILD_SHARED_LIBS ON CACHE BOOL \"Build shared libraries\")\n\nif (BUILD_SHARED_LIBS)\n\tmessage(STATUS \"Enable shared library building\")\n\tadd_library(libslim ${common_srcs})\nelse(BUILD_SHARED_LIBS)\n\tmessage(STATUS \"Disable shared library building\")\n\tadd_library(libslim STATIC ${common_srcs})\nendif(BUILD_SHARED_LIBS)\n\nif(USE_CONSOLEKIT)\n\tset(slim_srcs ${slim_srcs} Ck.cpp)\nendif(USE_CONSOLEKIT)\n\nadd_executable(${PROJECT_NAME} ${slim_srcs})\nif(BUILD_SLIMLOCK)\n    add_executable(slimlock ${slimlock_srcs})\nendif(BUILD_SLIMLOCK)\n\n#Set the custom CMake module directory where our include/lib finders are\nset(CMAKE_MODULE_PATH \"${CMAKE_SOURCE_DIR}/cmake/modules\")\n\nfind_package(X11 REQUIRED)\nfind_package(Freetype REQUIRED)\nfind_package(JPEG REQUIRED)\nfind_package(PNG REQUIRED)\nfind_package(ZLIB REQUIRED)\n\n# Fontconfig\nset(FONTCONFIG_DIR ${CMAKE_MODULE_PATH})\nfind_package(FONTCONFIG REQUIRED)\nif(FONTCONFIG_FOUND)\n\tmessage(\"\\tFontConfig Found\")\n\ttarget_link_libraries(${PROJECT_NAME} ${FONTCONFIG_LIBRARY})\n\tinclude_directories(${FONTCONFIG_INCLUDE_DIR})\nendif(FONTCONFIG_FOUND)\n\n# PAM\nif(USE_PAM)\n\tmessage(\"\\tPAM Enabled\")\n\tfind_package(PAM)\n\tif(PAM_FOUND)\n\t\tmessage(\"\\tPAM Found\")\n\t\tset(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} \"-DUSE_PAM\")\n\t\ttarget_link_libraries(${PROJECT_NAME} ${PAM_LIBRARY})\n\t\ttarget_link_libraries(slimlock ${PAM_LIBRARY})\n\t\tinclude_directories(${PAM_INCLUDE_DIR})\n\telse(PAM_FOUND)\n\t\tmessage(\"\\tPAM Not Found\")\n\tendif(PAM_FOUND)\nelse(USE_PAM)\n\tmessage(\"\\tPAM disabled\")\nendif(USE_PAM)\n\n# ConsoleKit\nif(USE_CONSOLEKIT)\n\tfind_package(CkConnector)\n\tmessage(\"\\tConsoleKit Enabled\")\n\tif(CKCONNECTOR_FOUND)\n\t\tmessage(\"\\tConsoleKit Found\")\n\t\t# DBus check\n\t\tfind_package(DBus REQUIRED)\n\t\tif(DBUS_FOUND)\n\t\t\tmessage(\"\\tDBus Found\")\n\t\t\ttarget_link_libraries(${PROJECT_NAME} ${DBUS_LIBRARIES})\n\t\t\tinclude_directories(${DBUS_ARCH_INCLUDE_DIR})\n\t\t\tinclude_directories(${DBUS_INCLUDE_DIR})\n\t\t\tset(SLIM_DEFINITIONS ${SLIM_DEFINITIONS} \"-DUSE_CONSOLEKIT\")\n\t\t\ttarget_link_libraries(${PROJECT_NAME} ${CKCONNECTOR_LIBRARIES})\n\t\t\tinclude_directories(${CKCONNECTOR_INCLUDE_DIR})\n\t\telse(DBUS_FOUND)\n\t\t\tmessage(\"\\tDBus Not Found\")\n\t\tendif(DBUS_FOUND)\n\telse(CKCONNECTOR_FOUND)\n\t\tmessage(\"\\tConsoleKit Not Found\")\n\t\tmessage(\"\\tConsoleKit disabled\")\n\tendif(CKCONNECTOR_FOUND)\nelse(USE_CONSOLEKIT)\n\tmessage(\"\\tConsoleKit disabled\")\nendif(USE_CONSOLEKIT)\n\n# system librarys\nfind_library(M_LIB m)\nfind_library(RT_LIB rt)\nfind_library(CRYPTO_LIB crypt)\nfind_package(Threads)\n\nadd_definitions(${SLIM_DEFINITIONS})\n\n#Set up include dirs with all found packages\ninclude_directories(\n\t${X11_INCLUDE_DIR}\n\t${X11_Xft_INCLUDE_PATH}\n\t${X11_Xrender_INCLUDE_PATH}\n\t${X11_Xrandr_INCLUDE_PATH}\n\t${FREETYPE_INCLUDE_DIR_freetype2}\n\t${X11_Xmu_INCLUDE_PATH}\n\t${ZLIB_INCLUDE_DIR}\n\t${JPEG_INCLUDE_DIR}\n\t${PNG_INCLUDE_DIR}\n)\n\ntarget_link_libraries(libslim\n    ${JPEG_LIBRARIES}\n\t${PNG_LIBRARIES}\n)\n\n#Set up library with all found packages for slim\ntarget_link_libraries(${PROJECT_NAME}\n\t${M_LIB}\n\t${RT_LIB}\n\t${CRYPTO_LIB}\n\t${X11_X11_LIB}\n\t${X11_Xft_LIB}\n\t${X11_Xrender_LIB}\n\t${X11_Xrandr_LIB}\n\t${X11_Xmu_LIB}\n\t${FREETYPE_LIBRARY}\n\t${JPEG_LIBRARIES}\n\t${PNG_LIBRARIES}\n    libslim\n)\n\nif(BUILD_SLIMLOCK)\n    #Set up library with all found packages for slimlock\n    target_link_libraries(slimlock\n        ${M_LIB}\n        ${RT_LIB}\n        ${CRYPTO_LIB}\n        ${X11_X11_LIB}\n        ${X11_Xft_LIB}\n        ${X11_Xrender_LIB}\n        ${X11_Xrandr_LIB}\n        ${X11_Xmu_LIB}\n        ${X11_Xext_LIB}\n        ${FREETYPE_LIBRARY}\n        ${JPEG_LIBRARIES}\n        ${PNG_LIBRARIES}\n        ${CMAKE_THREAD_LIBS_INIT}\n        libslim\n    )\nendif(BUILD_SLIMLOCK)\n\n####### install\n# slim\ninstall(TARGETS slim RUNTIME DESTINATION bin)\ninstall(TARGETS slimlock RUNTIME DESTINATION bin)\n\nif (BUILD_SHARED_LIBS)\n\tset_target_properties(libslim PROPERTIES\n\t\tOUTPUT_NAME slim\n\t\tSOVERSION ${SLIM_VERSION})\n\n\tinstall(TARGETS libslim\n\t\tLIBRARY DESTINATION lib\n\t\tARCHIVE DESTINATION lib\n\t)\nendif (BUILD_SHARED_LIBS)\n\n# man file\ninstall(FILES slim.1 DESTINATION ${MANDIR}/man1/)\ninstall(FILES slimlock.1 DESTINATION ${MANDIR}/man1/)\n# configure\ninstall(FILES slim.conf DESTINATION ${SYSCONFDIR})\n# systemd service file\nif (${CMAKE_SYSTEM_NAME} MATCHES \"Linux\")\n\tinstall(FILES slim.service DESTINATION ${LIBDIR}/systemd/system)\nendif (${CMAKE_SYSTEM_NAME} MATCHES \"Linux\")\n# themes directory\nsubdirs(themes)\n"
  },
  {
    "path": "COPYING",
    "content": "\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n                          675 Mass Ave, Cambridge, MA 02139, USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Library General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\f\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\f\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\f\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\f\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n\tAppendix: How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) 19yy  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program; if not, write to the Free Software\n    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) 19yy name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General\nPublic License instead of this License.\n"
  },
  {
    "path": "ChangeLog",
    "content": "1.3.6 - 2013.10.01\n\t* Merge slimlock.\n\t* Add support ^H (like backspace).\n\t* And fix some bugs.\n\n1.3.5 - 2012.12.31\n\t* Support UTF8 string.\n\t* Add systemd service.\n\t* And fix some bugs.\n\n1.3.4 - 2012.06.26\n\t* Replaced stderr writes function.\n\t* Fix numlock control.\n\t* Fix build with GLUT.\n\t* Fix PAM authentication.\n\n1.3.3 - 2012.02.22\n\t* Change build system to CMake.\n\t* Add support ConsoleKit.\n\t* Fix some bugs....\n\n1.3.2 - 2010.07.08\n    * Add support xauth secret.\n    * Add xnest_debug mode.\n\n1.3.1 - 2008.09.26\n    * Added focus_password config option for focusing password\n      automatically when default_user is enabled\n    * Added auto_login option\n    * Fixed uninitialized daemonmode, see\n      http://www.freebsd.org/cgi/query-pr.cgi?pr=114366\n    * Fixed maximum length for password\n    * Introduced customization options for session text:\n      font, colors, position, shadows.\n\n1.3.0 - 2006.07.14\n    * Added PAM support by Martin Parm\n    * Fixed segfault on exit when testing themes. Thanks\n      to Darren Salt & Mike Massonnet\n    * Fixed vt argument detection, thanks to Henrik Brix Andersen\n    * Corrected reference to input_color in the default theme\n    * Fixed default shell setting\n    * Fix segfault when calling XCloseDisplay(NULL); thanks Uli Schlachter\n\n1.2.6 - 2006.09.15\n    * Bug #008167: Update pid when in daemon mode\n    * Fixed warnings when compiling with -Wall. Thanks to\n      KIMURA Masaru\n    * Fixed major memory leaks with repeated login (bug #007535)\n\n1.2.5 - 2006.07.24\n    * hiding of the cursor is now an option (disabled\n      by default) since some WMs does not re-initialize\n      the root window cursor.\n    * The X server is restarted when the user logs out.\n      This fixes potential security issues with user-launched\n      apps staying attached to the root window after logout.\n    * Bug #7432 : Added proper Xauth authentication: the X server\n      is started with the -auth option and the user who logs\n      in has his .Xauthority file initializated.\n\n1.2.4 - 2006.01.18\n    * Added commands for session start and stop\n      (i.e. for session registering)\n    * Added automatic numlock on/off option\n    * Support for numpad Enter key\n    * Restored support for daemon option in the config\n      file.\n    * Lock file now uses process id, no more false\n      locking (thanks to Tobias Roth)\n\n1.2.3 - 2005.09.11\n    * Added FreeBSD, NetBSD, OpenBSD support\n    * Replaced autotools with plain makefile(s)\n    * Added 'suspend' command (untested, we don't use it)\n    * Added support for %theme variable in login command\n\t\n1.2.2 - 2005.05.21\n    * fix panel drawing on screens <= 1024x768\n    * Don't start X server unless valid theme found\n    * revert to 'default' of invalid theme specified\n    * try all themes from a set if one doesn't work\n    \n1.2.1 - 2005.05.17\n    * draw input directly on panel\n\n1.2.0 - 2005.05.16\n    * added theme preview (slim -p /path/to/theme)\n    * added JPEG support for panel image\n    * added 'center' background type and 'background_color' option\n    * added text shadow\n    * added warning when execution of login command fails\n    * Fix login failure when no shell specified in /etc/passwd\n    * Print error when login command execution fails\n    * add XNEST_DEBUG ifdef's to allow for easy debugging\n    * Add support for Ctrl-u and Ctrl-w\n    * Add 'vt07' to server arguments if not already specified\n    * Removes daemon option from the config file. Use slim -d\n    * Allow 'current_theme' to be a set of themes, choose randomly\n    * Change default theme\n\n1.1.0 - 2004.12.09\n    * error messages for X11 apps are no longer redirected\n      to the log file\n    * fixed text position for default theme\n    * added configurable shutdown and reboot messages\n    * separated 'Enter username' and 'Enter password' messages\n      position.\n    * due to the previous two points, the theme format has \n      slightly changed\n    \n1.0.0 - 2004.12.07\n    * First public SLiM release\n"
  },
  {
    "path": "Ck.cpp",
    "content": "/* SLiM - Simple Login Manager\n * Copyright (C) 2011 David Hauweele\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n */\n\n#include <cstdio>\n#include <iostream>\n\n#include <ck-connector.h>\n#include <X11/Xlib.h>\n#include <X11/Xatom.h>\n#include <stdarg.h>\n\n#include \"Ck.h\"\n\nnamespace Ck {\n\tException::Exception(const std::string &func,\n\t\t\t\tconst std::string &errstr):\n\t\t\t\tfunc(func),\n\t\t\t\terrstr(errstr)\n\t{}\n\n\tdbus_bool_t\n\tSession::ck_connector_open_graphic_session(\n\t\t\t\t\tconst std::string &display,\n\t\t\t\t\tuid_t uid)\n\t{\n\t\tdbus_bool_t local = true;\n\t\tconst char *session_type = \"x11\";\n\t\tconst char *x11_display\t= display.c_str();\n\t\tconst char *x11_device = get_x11_device(display);\n\t\tconst char *remote_host\t= \"\";\n\t\tconst char *display_dev\t= \"\";\n\n\t\treturn ck_connector_open_session_with_parameters(ckc, &error,\n\t\t\t\"unix-user\", &uid,\n\t\t\t\"session-type\", &session_type,\n\t\t\t\"x11-display\", &x11_display,\n\t\t\t\"x11-display-device\", &x11_device,\n\t\t\t\"display-device\", &display_dev,\n\t\t\t\"remote-host-name\", &remote_host,\n\t\t\t\"is-local\", &local,\n\t\t\tNULL);\n\t}\n\n\tconst char * Session::get_x11_device(const std::string &display)\n\t{\n\t\tstatic char device[32];\n\n\t\tDisplay *xdisplay = XOpenDisplay(display.c_str());\n\n\t\tif(!xdisplay)\n\t\t\tthrow Exception(__func__, \"cannot open display\");\n\n\t\tWindow root;\n\t\tAtom xfree86_vt_atom;\n\t\tAtom return_type_atom;\n\t\tint return_format;\n\t\tunsigned long return_count;\n\t\tunsigned long bytes_left;\n\t\tunsigned char *return_value;\n\t\tlong vt;\n\n\t\txfree86_vt_atom = XInternAtom(xdisplay, \"XFree86_VT\", true);\n\n\t\tif(xfree86_vt_atom == None)\n\t\t\tthrow Exception(__func__, \"cannot get XFree86_VT\");\n\n\t\troot = DefaultRootWindow(xdisplay);\n\n\t\tif(XGetWindowProperty(xdisplay, root, xfree86_vt_atom,\n\t\t\t\t\t\t\t0L, 1L, false, XA_INTEGER,\n\t\t\t\t\t\t\t&return_type_atom, &return_format,\n\t\t\t\t\t\t\t&return_count, &bytes_left,\n\t\t\t\t\t\t\t&return_value) != Success)\n\t\t\tthrow Exception(__func__, \"cannot get root window property\");\n\n\t\tif(return_type_atom != XA_INTEGER)\n\t\t\tthrow Exception(__func__, \"bad atom type\");\n\n\t\tif(return_format != 32)\n\t\t\tthrow Exception(__func__, \"invalid return format\");\n\n\t\tif(return_count != 1)\n\t\t\tthrow Exception(__func__, \"invalid count\");\n\n\t\tif(bytes_left != 0)\n\t\t\tthrow Exception(__func__, \"invalid bytes left\");\n\n\t\tvt = *((long *)return_value);\n\n\t\tstd::snprintf(device, 32, \"/dev/tty%ld\", vt);\n\n\t\tif(return_value)\n\t\t\tXFree(return_value);\n\n\t\treturn device;\n\t}\n\n\tvoid Session::open_session(const std::string &display, uid_t uid)\n\t{\n\t\tckc = ck_connector_new();\n\n\t\tif(!ckc)\n\t\t\tthrow Exception(__func__, \"error setting up connection to ConsoleKit\");\n\n\t\tif (!ck_connector_open_graphic_session(display, uid)) {\n\t\t\tif(dbus_error_is_set(&error))\n\t\t\t\tthrow Exception(__func__, error.message);\n\t\t\telse\n\t\t\t\tthrow Exception(__func__, \"cannot open ConsoleKit session: OOM,\"\n\t\t\t\t\t\t\" DBus system bus not available or insufficient\"\n\t\t\t\t\t\t\" privileges\");\n\t\t}\n\t}\n\n\tconst char * Session::get_xdg_session_cookie()\n\t{\n\t\treturn ck_connector_get_cookie(ckc);\n\t}\n\n\tvoid Session::close_session()\n\t{\n\t\tif(!ck_connector_close_session(ckc, &error)) {\n\t\t\tif(dbus_error_is_set(&error))\n\t\t\t\tthrow Exception(__func__, error.message);\n\t\t\telse\n\t\t\t\tthrow Exception(__func__, \"cannot close ConsoleKit session: OOM,\"\n\t\t\t\t\t\t\" DBus system bus not available or insufficient\"\n\t\t\t\t\t\t\" privileges\");\n\t\t}\n\t}\n\n\tSession::Session()\n\t{\n\t\tdbus_error_init(&error);\n\t}\n\n\tSession::~Session()\n\t{\n\t\tdbus_error_free(&error);\n\t}\n}\n\nstd::ostream& operator<<( std::ostream& os, const Ck::Exception& e)\n{\n\tos << e.func << \": \" << e.errstr;\n\treturn os;\n}\n"
  },
  {
    "path": "Ck.h",
    "content": "/* SLiM - Simple Login Manager\n * Copyright (C) 2007 Martin Parm\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n *(at your option) any later version.\n */\n\n#ifndef _CK_H_\n#define _CK_H_\n\n#include <string>\n\n#include <ck-connector.h>\n#include <dbus/dbus.h>\n\nnamespace Ck {\n\tclass Exception {\n\tpublic:\n\t\tstd::string func;\n\t\tstd::string errstr;\n\t\tException(const std::string &func, const std::string &errstr);\n\t};\n\n\tclass Session {\n\tprivate:\n\t\tCkConnector *ckc;\n\t\tDBusError error;\n\n\t\tconst char *get_x11_device(const std::string &display);\n\t\tdbus_bool_t ck_connector_open_graphic_session(const std::string &display,\n\t\t\tuid_t uid);\n\tpublic:\n\t\tconst char *get_xdg_session_cookie();\n\t\tvoid open_session(const std::string &display, uid_t uid);\n\t\tvoid close_session();\n\n\tSession();\n\t~Session();\n\t};\n}\n\nstd::ostream &operator<<(std::ostream &os, const Ck::Exception &e);\n\n#endif /* _CK_H_ */\n"
  },
  {
    "path": "INSTALL",
    "content": "INSTALL file for SLiM\n\n0. Prerequisites:\n - cmake\n - X.org or XFree86\n - libxmu\n - libpng\n - libjpeg\n\n1. to build and install the program:\n - edit the Makefile to adjust libraries and paths to your OS (if needed)\n - mkdir build ; cd build ; cmake ..\n     or\n - mkdir build ; cd build ; cmake .. -DUSE_PAM=yes to enable PAM support\n     or\n - mkdir build ; cd build ; cmake .. -DUSE_CONSOLEKIT=yes\n   to enable CONSOLEKIT support\n - make && make install\n \n2. automatic startup\nEdit the init scripts according to your OS/Distribution.\n"
  },
  {
    "path": "PAM.cpp",
    "content": "/* SLiM - Simple Login Manager\n * Copyright (C) 2007 Martin Parm\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n */\n\n#include <string>\n#include <iostream>\n#include \"PAM.h\"\n\nnamespace PAM {\n\tException::Exception(pam_handle_t* _pam_handle,\n\t\t\t\t\tconst std::string& _func_name,\n\t\t\t\t\tint _errnum):\n\t\terrnum(_errnum),\n\t\terrstr(pam_strerror(_pam_handle, _errnum)),\n\t\tfunc_name(_func_name)\n\t\t{}\n\n\tException::~Exception(void) {}\n\n\tAuth_Exception::Auth_Exception(pam_handle_t* _pam_handle,\n\t\t\t\t\tconst std::string& _func_name,\n\t\t\t\t\tint _errnum):\n\t\tException(_pam_handle, _func_name, _errnum) {}\n\n\tCred_Exception::Cred_Exception(pam_handle_t* _pam_handle,\n\t\t\t\t\tconst std::string& _func_name,\n\t\t\t\t\tint _errnum):\n\t\tException(_pam_handle, _func_name, _errnum) {}\n\n\tint Authenticator::_end (void)\n\t{\n\t\tint result=pam_end(pam_handle, last_result);\n\t\tpam_handle=0;\n\t\treturn result;\n\t}\n\n\tAuthenticator::Authenticator(conversation* conv, void* data):\n\t\tpam_handle(0),\n\t\tlast_result(PAM_SUCCESS)\n\t{\n\t\tpam_conversation.conv=conv;\n\t\tpam_conversation.appdata_ptr=data;\n\t}\n\n\tAuthenticator::~Authenticator(void)\n\t{\n\t\tif (pam_handle)\n\t\t\t_end();\n\t}\n\n\tvoid Authenticator::start(const std::string& service)\n\t{\n\t\tswitch ((last_result=pam_start(service.c_str(), NULL, &pam_conversation, &pam_handle))) {\n\t\t\tdefault:\n\t\t\t\tthrow Exception(pam_handle, \"pam_start()\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t}\n\n\tvoid Authenticator::end(void)\n\t{\n\t\tswitch ((last_result=_end())) {\n\t\t\tdefault:\n\t\t\t\tthrow Exception(pam_handle, \"pam_end()\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t}\n\n\tvoid Authenticator::set_item(const Authenticator::ItemType item, const void* value)\n\t{\n\t\tswitch ((last_result=pam_set_item(pam_handle, item, value))) {\n\t\t\tdefault:\n\t\t\t_end();\n\t\t\t\tthrow Exception(pam_handle, \"pam_set_item()\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t}\n\n\tconst void* Authenticator::get_item(const Authenticator::ItemType item)\n\t{\n\t\tconst void* data;\n\t\tswitch ((last_result=pam_get_item(pam_handle, item, &data))) {\n\t\t\tdefault:\n\t\t\tcase PAM_SYSTEM_ERR:\n#ifdef __LIBPAM_VERSION\n\t\t\tcase PAM_BAD_ITEM:\n#endif\n\t\t\t\t_end();\n\t\t\t\tthrow Exception(pam_handle, \"pam_get_item()\", last_result);\n\n\t\t\tcase PAM_PERM_DENIED: /* The value of item was NULL */\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn data;\n\t}\n\n#ifdef __LIBPAM_VERSION\n\tvoid Authenticator::fail_delay(const unsigned int micro_sec)\n\t{\n\t\tswitch ((last_result=pam_fail_delay(pam_handle, micro_sec))) {\n\t\t\tdefault:\n\t\t\t\t_end();\n\t\t\t\tthrow Exception(pam_handle, \"fail_delay()\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t}\n#endif\n\n\tvoid Authenticator::authenticate(void)\n\t{\n\t\tswitch ((last_result=pam_authenticate(pam_handle, 0))) {\n\t\t\tdefault:\n\t\t\tcase PAM_ABORT:\n\t\t\tcase PAM_AUTHINFO_UNAVAIL:\n\t\t\t\t_end();\n\t\t\t\tthrow Exception(pam_handle, \"pam_authenticate()\", last_result);\n\n\t\t\tcase PAM_USER_UNKNOWN:\n\t\t\tcase PAM_MAXTRIES:\n\t\t\tcase PAM_CRED_INSUFFICIENT:\n\t\t\tcase PAM_AUTH_ERR:\n\t\t\t\tthrow Auth_Exception(pam_handle, \"pam_authentication()\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\n\t\tswitch ((last_result=pam_acct_mgmt(pam_handle, PAM_SILENT))) {\n\t\t\t/* The documentation and implementation of Linux PAM differs:\n\t\t\t   PAM_NEW_AUTHTOKEN_REQD is described in the documentation but\n\t\t\t   don't exists in the actual implementation. This issue needs\n\t\t\t   to be fixes at some point. */\n\n\t\t\tdefault:\n\t\t\t/* case PAM_NEW_AUTHTOKEN_REQD: */\n\t\t\tcase PAM_ACCT_EXPIRED:\n\t\t\tcase PAM_USER_UNKNOWN:\n\t\t\t\t_end();\n\t\t\t\tthrow Exception(pam_handle, \"pam_acct_mgmt()\", last_result);\n\n\t\t\tcase PAM_AUTH_ERR:\n\t\t\tcase PAM_PERM_DENIED:\n\t\t\t\tthrow Auth_Exception(pam_handle, \"pam_acct_mgmt()\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t}\n\n\tvoid Authenticator::open_session(void)\n\t{\n\t\tswitch ((last_result=pam_setcred(pam_handle, PAM_ESTABLISH_CRED))) {\n\t\t\tdefault:\n\t\t\tcase PAM_CRED_ERR:\n\t\t\tcase PAM_CRED_UNAVAIL:\n\t\t\t\t_end();\n\t\t\t\tthrow Exception(pam_handle, \"pam_setcred()\", last_result);\n\n\t\t\tcase PAM_CRED_EXPIRED:\n\t\t\tcase PAM_USER_UNKNOWN:\n\t\t\t\tthrow Cred_Exception(pam_handle, \"pam_setcred()\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\n\t\tswitch ((last_result=pam_open_session(pam_handle, 0))) {\n\t\t\t/* The documentation and implementation of Linux PAM differs:\n\t\t\t   PAM_SESSION_ERROR is described in the documentation but\n\t\t\t   don't exists in the actual implementation. This issue needs\n\t\t\t   to be fixes at some point. */\n\n\t\t\tdefault:\n\t\t\t/* case PAM_SESSION_ERROR: */\n\t\t\t\tpam_setcred(pam_handle, PAM_DELETE_CRED);\n\t\t\t\t_end();\n\t\t\t\tthrow Exception(pam_handle, \"pam_open_session()\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t}\n\n\tvoid Authenticator::close_session(void)\n\t{\n\t\tswitch ((last_result=pam_close_session(pam_handle, 0))) {\n\t\t\t/* The documentation and implementation of Linux PAM differs:\n\t\t\t   PAM_SESSION_ERROR is described in the documentation but\n\t\t\t   don't exists in the actual implementation. This issue needs\n\t\t\t   to be fixes at some point. */\n\n\t\t\tdefault:\n\t\t\t/* case PAM_SESSION_ERROR: */\n\t\t\t\tpam_setcred(pam_handle, PAM_DELETE_CRED);\n\t\t\t\t_end();\n\t\t\t\tthrow Exception(pam_handle, \"pam_close_session\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\t\tswitch ((last_result=pam_setcred(pam_handle, PAM_DELETE_CRED))) {\n\t\t\tdefault:\n\t\t\tcase PAM_CRED_ERR:\n\t\t\tcase PAM_CRED_UNAVAIL:\n\t\t\tcase PAM_CRED_EXPIRED:\n\t\t\tcase PAM_USER_UNKNOWN:\n\t\t\t\t_end();\n\t\t\t\tthrow Exception(pam_handle, \"pam_setcred()\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t}\n\n\tvoid Authenticator::setenv(const std::string& key, const std::string& value)\n\t{\n\t\tstd::string name_value = key+\"=\"+value;\n\t\tswitch ((last_result = pam_putenv(pam_handle, name_value.c_str()))) {\n\t\t\tdefault:\n\t\t\tcase PAM_PERM_DENIED:\n\t\t\tcase PAM_ABORT:\n\t\t\tcase PAM_BUF_ERR:\n#ifdef __LIBPAM_VERSION\n\t\t\tcase PAM_BAD_ITEM:\n#endif\n\t\t\t\t_end();\n\t\t\t\tthrow Exception(pam_handle, \"pam_putenv()\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t}\n\n\tvoid Authenticator::delenv(const std::string& key)\n\t{\n\t\tswitch ((last_result = pam_putenv(pam_handle, key.c_str()))) {\n\t\t\tdefault: \n\t\t\tcase PAM_PERM_DENIED:\n\t\t\tcase PAM_ABORT:\n\t\t\tcase PAM_BUF_ERR:\n#ifdef __LIBPAM_VERSION\n\t\t\tcase PAM_BAD_ITEM:\n#endif\n\t\t\t\t_end();\n\t\t\t\tthrow Exception(pam_handle, \"pam_putenv()\", last_result);\n\n\t\t\tcase PAM_SUCCESS:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t}\n\n\tconst char* Authenticator::getenv(const std::string& key)\n\t{\n\t\treturn pam_getenv(pam_handle, key.c_str());\n\t}\n\n\tchar** Authenticator::getenvlist(void)\n\t{\n\t\treturn pam_getenvlist(pam_handle);\n\t}\n}\n\nstd::ostream& operator<<( std::ostream& os, const PAM::Exception& e)\n{\n\tos << e.func_name << \": \" << e.errstr;\n\treturn os;\n}\n"
  },
  {
    "path": "PAM.h",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 2007 Martin Parm\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n*/\n\n#ifndef _PAM_H_\n#define _PAM_H_\n#include <string>\n#include <security/pam_appl.h>\n\n#ifdef __LIBPAM_VERSION\n#include <security/pam_misc.h>\n#endif\n\nnamespace PAM {\n\tclass Exception {\n\tpublic:\n\t\tint errnum;\n\t\tstd::string errstr;\n\t\tstd::string func_name;\n\t\tException(pam_handle_t* _pam_handle,\n\t\t\t\t  const std::string& _func_name,\n\t\t\t\t  int _errnum);\n\t\tvirtual ~Exception(void);\n\t};\n\n\tclass Auth_Exception: public Exception {\n\tpublic:\n\t\tAuth_Exception(pam_handle_t* _pam_handle,\n\t\t\t\t\t   const std::string& _func_name,\n\t\t\t\t\t   int _errnum);\n\t};\n\n\tclass Cred_Exception: public Exception {\n\tpublic:\n\t\tCred_Exception(pam_handle_t* _pam_handle,\n\t\t\t\t\t   const std::string& _func_name,\n\t\t\t\t\t   int _errnum);\n\t};\n\n\n\tclass Authenticator {\n\tprivate:\n\t\tstruct pam_conv pam_conversation;\n\t\tpam_handle_t* pam_handle;\n\t\tint last_result;\n\n\t\tint _end(void);\n\tpublic:\n\t\ttypedef int (conversation)(int num_msg,\n\t\t\t\t\t\t   const struct pam_message **msg,\n\t\t\t\t\t\t   struct pam_response **resp,\n\t\t\t\t\t\t   void *appdata_ptr);\n\n\t\tenum ItemType {\n\t\t\tService\t\t= PAM_SERVICE,\n\t\t\tUser\t\t= PAM_USER,\n\t\t\tUser_Prompt\t= PAM_USER_PROMPT,\n\t\t\tTTY\t\t\t= PAM_TTY,\n\t\t\tRequestor\t= PAM_RUSER,\n\t\t\tHost\t\t= PAM_RHOST,\n\t\t\tConv\t\t= PAM_CONV,\n#ifdef __LIBPAM_VERSION\n\t\t\t/* Fail_Delay  = PAM_FAIL_DELAY */\n#endif\n\t\t};\n\n\tpublic:\n\t\tAuthenticator(conversation* conv, void* data=0);\n\t\t~Authenticator(void);\n\t\t\n\t\tvoid start(const std::string& service);\n\t\tvoid end(void);\n\t\tvoid set_item(const ItemType item, const void* value);\n\t\tconst void* get_item(const ItemType item);\n#ifdef __LIBPAM_VERSION\n\t\tvoid fail_delay(const unsigned int micro_sec);\n#endif\n\t\tvoid authenticate(void);\n\t\tvoid open_session(void);\n\t\tvoid close_session(void);\n\t\tvoid setenv(const std::string& key, const std::string& value);\n\t\tvoid delenv(const std::string& key);\n\t\tconst char* getenv(const std::string& key);\n\t\tchar** getenvlist(void);\n\n\tprivate:\n\t\t/* Explicitly disable copy constructor and copy assignment */\n\t\tAuthenticator(const PAM::Authenticator&);\n\t\tAuthenticator& operator=(const PAM::Authenticator&);\n\t};\n}\n\nstd::ostream& operator<<( std::ostream& os, const PAM::Exception& e);\n#endif /* _PAM_H_ */\n"
  },
  {
    "path": "README",
    "content": "README file for SLiM\n\nNobuhiro Iwamatsu <iwamatsu@nigauri.org>\n\nINTRODUCTION\n    SLiM (Simple Login Manager) is a graphical login manager for X11.\n    It aims to be simple, fast and independent from the various\n    desktop environments.\n    SLiM is based on latest stable release of Login.app by Per Lidn.\n\n    New features:\n    - External themes and configuration\n    - PNG support with alpha transparency for panel\n    - PNG / JPEG support for backgrounds\n    - XFT / freetype support\n    - Double or single (GDM-style) inputbox support\n    - CMake build procedure\n\nINSTALLATION\n    see the INSTALL file\n    \nUSAGE\n\n    To launch slim, execute run the slim binary,\n    followed by the -d option if you want it to\n    run as a daemon in the background (reccommended)\n    \n    enter username and password to login. The ~/.xinitrc\n    file is executed by default, so be sure to have a working\n    .xinitrc file in your home.\n    \n    Special usernames (commands configurable in the config file):\n    - console: start console login\n    - exit: exit SLiM\n    - halt: halt the system\n    - reboot: reboot the system\n    \n    pressing the F11 key executes a user-specified\n    command (see the configuration file), the default\n    is to take a screenshot if the 'import' program is available.\n    \nCONFIGURATION\n    /usr/etc/slim.conf is the main configuration file.\n    Options are explained in the file itself\n    \nTHEMES\n    See THEMES\n\nCOPYRIGHT\n    SLiM is copyright (c) 2004-06 by Simone Rota, Johannes Winkelmann,\n    Nobuhiro Iwamatsu and is available under the GNU General Public\n    License.\n    See the COPYING file for the complete license.\n\n    Image handling code adapted and extended from xplanet 1.0.1,\n    copyright (c) 2002-04 by Hari Nair\n\n    Login.app is copyright (c) 1997, 1998 by Per Liden and is \n    licensed through the GNU General Public License. \n"
  },
  {
    "path": "THEMES",
    "content": "Quick THEME howto for SLiM\n\nSome basic information regarding the slim theme format.\nRead this file if you plan to make some theme for\nthe program, and of course have a look at the included themes\n\nGENERAL CONCEPT\n    A SLiM theme essentially consists of:\n    - a background image (background.png or background.jpg)\n    - a panel image (panel.png or panel.jpg)\n    - input box(es) and messages and their placement\n      and properties (slim.theme)\n    \n    The panel and background images can be a PNG or JPEG file.\n    The panel is blended into the background image,\n    taking care of alpha transparency.\n\nSUPPORTED FORMATS\n    - fonts: use the xft font specs, ie: Verdana:size=16:bold\n    - colors: use html hex format, ie #0066CC\n    - positions: can be either absolute in pixels, ie 350\n      or relative to the container, ie 50% is in the middle\n      of the screen.\n    \nOPTIONS\n    The following is an example slim.theme file    \n    ----------------------------------------------------------------------\n    # Color, font, position for the messages (ie: shutting down)\n    msg_color               #FFFFFF\n    msg_font                Verdana:size=16:bold\n    msg_x                   50%\n    msg_y                   30\n\n    # Color, font, position for the session list\n    session_color           #FFFFFF\n    session_font            Verdana:size=16:bold\n    session_x               50%\n    session_y               90%\n\n    # style of background: 'stretch', 'tile', 'center', 'color'\n    background_style        stretch\n    background_color\t\t#FF0033\n\n    # Horizonatal and vertical position for the panel.\n    input_panel_x           50%\n    input_panel_y           40%\n    \n    # input controls horizontal and vertical positions.\n    # IMPORTANT! set input_pass_x and input_pass_y to -1\n    # to use a single input box for username/password (GDM Style).\n    # Note that this fields only accept absolute values.\n    input_name_x            40\n    input_name_y            100\n    input_pass_x            40\n    input_pass_y            120\n    \n    # Input controls font and color\n    input_font          \tVerdana:size=12\n    input_color             #000000\n\n    # Welcome message position. (relative to the panel)\n    # use -1 for both values or comment the options to disable\n    # the welcome message\n    welcome_x              \t50%\n    welcome_y              \t38\n    \n    # Font and color for the welcome message\n    welcome_font          \tVerdana:size=16:bold:slant=italic\n    welcome_color          \t#d7dde8\n\n    # 'Enter username' font and foreground/background color\n    username_font          \tVerdana:size=12\n    username_color          \t#d7dde8\n\n    # 'Enter username' and 'Enter password' position (relative to the panel)\n    #  use -1 for both values to disable the message\n    # note that in case of single inputbox the password values are ignored.\n    username_x                 50%\n    username_y                 146\n    password_x                 50%\n    password_y                 146\n\n    # The message to be displayed. Leave blank if no message\n    # is needed (ie, when already present in the panel image)\n    username_msg            Please enter your username\n    password_msg            Please enter your password\n    ----------------------------------------------------------------------\n\nSHADOWS\n\n    The 'msg', 'input', 'welcome', 'session' and 'username' sections\n    support shadows; three values can be configured:\n    - color: the shadow color\n    - x offset: the offset in x direction, relative to the normal text \n    - y offset: the offset in y direction, relative to the normal text\n\n    So to add a text shadow to the welcome message, add the following\n    to slim.conf:\n    ----------------------------------------------------------------------\n    welcome_shadow_xoffset      -2\n    welcome_shadow_yoffset      2\n    welcome_shadow_color        #ff0000\n    ----------------------------------------------------------------------\n     \n    The other keys are analogue:\n    ----------------------------------------------------------------------\n    # for username and password label\n    username_shadow_xoffset \t2\n    username_shadow_yoffset \t-2\n    username_shadow_color   \t#ff0000\n\n    # for the input fields\n    input_shadow_xoffset \t1\n    input_shadow_yoffset \t1\n    input_shadow_color   \t#0000ff\n\n    # for the messages:\n    msg_shadow_xoffset \t\t1    \n    msg_shadow_yoffset \t\t1    \n    msg_shadow_color   \t\t#ff00ff\n\n    # For the session:\n    session_shadow_xoffset \t\t1    \n    session_shadow_yoffset \t\t1    \n    session_shadow_color   \t\t#ff00ff\n    ----------------------------------------------------------------------\n\n    \n"
  },
  {
    "path": "TODO",
    "content": "1.2.2\n-----\n- drawing problem on screens <= 1024x768 (implemented)\n- Don't start X server if theme's not found\n\n1.2.x\n-----\n- i18n\n- don't choose a non-existing theme in random selection\n- think about multi-line configuration:\n    current_theme = t1, t2, t3\n    current_theme = t4, t5\n  or\n    current_theme = t1, t2, t3 \\\n\t\t    t4, t5\n- FreeBSD fixes\n\n2.0.x\n-----\n- restart X server on ctrl-alt-backspace\n- allow switching theme on the fly if a set is specified in slim.conf\n- text alignment, to allow to center texts of unknown length (e.g. %host)\n"
  },
  {
    "path": "app.cpp",
    "content": "/* SLiM - Simple Login Manager\n *  Copyright (C) 1997, 1998 Per Liden\n *  Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n *  Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n *\n *  This program is free software; you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation; either version 2 of the License, or\n *  (at your option) any later version.\n */\n\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <stdint.h>\n#include <cstring>\n#include <cstdio>\n#include <iostream>\n#include <fstream>\n#include <sstream>\n#include <vector>\n#include <algorithm>\n\n#include \"app.h\"\n#include \"numlock.h\"\n#include \"util.h\"\n\n#ifdef HAVE_SHADOW\n#include <shadow.h>\n#endif\n\nusing namespace std;\n\n#ifdef USE_PAM\n#include <string>\n\nint conv(int num_msg, const struct pam_message **msg,\n\t\t struct pam_response **resp, void *appdata_ptr)\n{\n\t*resp = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response));\n\tPanel* panel = *static_cast<Panel**>(appdata_ptr);\n\tint result = PAM_SUCCESS;\n\tint i;\n\n\tfor (i = 0; i < num_msg; i++) {\n\t\t(*resp)[i].resp = 0;\n\t\t(*resp)[i].resp_retcodei = 0;\n\t\tswitch (msg[i]->msg_style) {\n\t\t\tcase PAM_PROMPT_ECHO_ON:\n\t\t\t\t/* We assume PAM is asking for the username */\n\t\t\t\tpanel->EventHandler(Panel::Get_Name);\n\t\t\t\tswitch (panel->getAction()) {\n\t\t\t\t\tcase Panel::Suspend:\n\t\t\t\t\tcase Panel::Halt:\n\t\t\t\t\tcase Panel::Reboot:\n\t\t\t\t\t\t(*resp)[i].resp=strdup(\"root\");\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase Panel::Console:\n\t\t\t\t\tcase Panel::Exit:\n\t\t\t\t\tcase Panel::Login:\n\t\t\t\t\t\t(*resp)[i].resp=strdup(panel->GetName().c_str());\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase PAM_PROMPT_ECHO_OFF:\n\t\t\t\t/* We assume PAM is asking for the password */\n\t\t\t\tswitch (panel->getAction()) {\n\t\t\t\t\tcase Panel::Console:\n\t\t\t\t\tcase Panel::Exit:\n\t\t\t\t\t\t/* We should leave now! */\n\t\t\t\t\t\tresult = PAM_CONV_ERR;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tpanel->EventHandler(Panel::Get_Passwd);\n\t\t\t\t\t\t(*resp)[i].resp=strdup(panel->GetPasswd().c_str());\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase PAM_ERROR_MSG:\n\t\t\tcase PAM_TEXT_INFO:\n\t\t\t\t/* We simply write these to the log\n\t\t\t\t   TODO: Maybe we should simply ignore them */\n\t\t\t\tlogStream << APPNAME << \": \" << msg[i]->msg << endl;\n\t\t\t\tbreak;\n\t\t}\n\t\tif (result!=PAM_SUCCESS) break;\n\t}\n\n\tif (result != PAM_SUCCESS) {\n\t\tfor (i = 0; i < num_msg; i++) {\n\t\t\tif ((*resp)[i].resp == 0)\n\t\t\t\tcontinue;\n\t\t\tfree((*resp)[i].resp);\n\t\t\t(*resp)[i].resp = 0;\n\t\t}\n\t\tfree(*resp);\n\t\t*resp = 0;\n\t}\n\n\treturn result;\n}\n#endif\n\nextern App* LoginApp;\n\nint xioerror(Display *disp)\n{\n\tLoginApp->RestartServer();\n\treturn 0;\n}\n\nvoid CatchSignal(int sig)\n{\n\tlogStream << APPNAME << \": unexpected signal \" << sig << endl;\n\n\tif (LoginApp->isServerStarted())\n\t\tLoginApp->StopServer();\n\n\tLoginApp->RemoveLock();\n\texit(ERR_EXIT);\n}\n\nvoid User1Signal(int sig)\n{\n\tsignal(sig, User1Signal);\n}\n\n#ifdef USE_PAM\nApp::App(int argc, char** argv)\n  : pam(conv, static_cast<void*>(&LoginPanel)),\n#else\nApp::App(int argc, char** argv)\n  :\n#endif\n\tmcookiesize(32)\t\t/* Must be divisible by 4 */\n{\n\tint tmp;\n\tServerPID = -1;\n\ttesting = false;\n\tserverStarted = false;\n\tmcookie = string(App::mcookiesize, 'a');\n\tdaemonmode = false;\n\tforce_nodaemon = false;\n\tfirstlogin = true;\n\tDpy = NULL;\n\n\t/* Parse command line\n\t   Note: we force a option for nodaemon switch to handle \"-nodaemon\" */\n\twhile ((tmp = getopt(argc, argv, \"vhp:n:d?\")) != EOF) {\n\t\tswitch (tmp) {\n\t\tcase 'p':\t/* Test theme */\n\t\t\ttesttheme = optarg;\n\t\t\ttesting = true;\n\t\t\tif (testtheme == NULL) {\n\t\t\t\tlogStream << \"The -p option requires an argument\" << endl;\n\t\t\t\texit(ERR_EXIT);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 'd':\t/* Daemon mode */\n\t\t\tdaemonmode = true;\n\t\t\tbreak;\n\t\tcase 'n':\t/* Daemon mode */\n\t\t\tdaemonmode = false;\n\t\t\tforce_nodaemon = true;\n\t\t\tbreak;\n\t\tcase 'v':\t/* Version */\n\t\t\tstd::cout << APPNAME << \" version \" << VERSION << endl;\n\t\t\texit(OK_EXIT);\n\t\t\tbreak;\n\t\tcase '?':\t/* Illegal */\n\t\t\tlogStream << endl;\n\t\tcase 'h':   /* Help */\n\t\t\tlogStream << \"usage:  \" << APPNAME << \" [option ...]\" << endl\n\t\t\t<< \"options:\" << endl\n\t\t\t<< \"\t-d: daemon mode\" << endl\n\t\t\t<< \"\t-nodaemon: no-daemon mode\" << endl\n\t\t\t<< \"\t-v: show version\" << endl\n\t\t\t<< \"\t-p /path/to/theme/dir: preview theme\" << endl;\n\t\t\texit(OK_EXIT);\n\t\t\tbreak;\n\t\t}\n\t}\n#ifndef XNEST_DEBUG\n\tif (getuid() != 0 && !testing) {\n\t\tlogStream << APPNAME << \": only root can run this program\" << endl;\n\t\texit(ERR_EXIT);\n\t}\n#endif /* XNEST_DEBUG */\n\n}\n\nvoid App::Run()\n{\n\tDisplayName = DISPLAY;\n\n#ifdef XNEST_DEBUG\n\tchar* p = getenv(\"DISPLAY\");\n\tif (p && p[0]) {\n\t\tDisplayName = p;\n\t\tcout << \"Using display name \" << DisplayName << endl;\n\t}\n#endif\n\n\t/* Read configuration and theme */\n\tcfg = new Cfg;\n\tcfg->readConf(CFGFILE);\n\tstring themebase = \"\";\n\tstring themefile = \"\";\n\tstring themedir = \"\";\n\tthemeName = \"\";\n\tif (testing) {\n\t\tthemeName = testtheme;\n\t} else {\n\t\tthemebase = string(THEMESDIR) + \"/\";\n\t\tthemeName = cfg->getOption(\"current_theme\");\n\t\tstring::size_type pos;\n\t\tif ((pos = themeName.find(\",\")) != string::npos) {\n\t\t\t/* input is a set */\n\t\t\tthemeName = findValidRandomTheme(themeName);\n\t\t\tif (themeName == \"\") {\n\t\t\t\tthemeName = \"default\";\n\t\t\t}\n\t\t}\n\t}\n\n#ifdef USE_PAM\n\ttry {\n\t\tpam.start(\"slim\");\n\t\tpam.set_item(PAM::Authenticator::TTY, DisplayName);\n\t\tpam.set_item(PAM::Authenticator::Requestor, \"root\");\n\t} catch(PAM::Exception& e) {\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t\texit(ERR_EXIT);\n\t}\n#endif\n\n\tbool loaded = false;\n\twhile (!loaded) {\n\t\tthemedir = themebase + themeName;\n\t\tthemefile = themedir + THEMESFILE;\n\t\tif (!cfg->readConf(themefile)) {\n\t\t\tif (themeName == \"default\") {\n\t\t\t\tlogStream << APPNAME << \": Failed to open default theme file \"\n\t\t\t\t\t << themefile << endl;\n\t\t\t\texit(ERR_EXIT);\n\t\t\t} else {\n\t\t\t\tlogStream << APPNAME << \": Invalid theme in config: \"\n\t\t\t\t\t << themeName << endl;\n\t\t\t\tthemeName = \"default\";\n\t\t\t}\n\t\t} else {\n\t\t\tloaded = true;\n\t\t}\n\t}\n\n\tif (!testing) {\n\t\t/* Create lock file */\n\t\tLoginApp->GetLock();\n\n\t\t/* Start x-server */\n\t\tsetenv(\"DISPLAY\", DisplayName, 1);\n\t\tsignal(SIGQUIT, CatchSignal);\n\t\tsignal(SIGTERM, CatchSignal);\n\t\tsignal(SIGKILL, CatchSignal);\n\t\tsignal(SIGINT, CatchSignal);\n\t\tsignal(SIGHUP, CatchSignal);\n\t\tsignal(SIGPIPE, CatchSignal);\n\t\tsignal(SIGUSR1, User1Signal);\n\n#ifndef XNEST_DEBUG\n\t\tif (!force_nodaemon && cfg->getOption(\"daemon\") == \"yes\") {\n\t\t\tdaemonmode = true;\n\t\t}\n\n\t\t/* Daemonize */\n\t\tif (daemonmode) {\n\t\t\tif (daemon(0, 0) == -1) {\n\t\t\t\tlogStream << APPNAME << \": \" << strerror(errno) << endl;\n\t\t\t\texit(ERR_EXIT);\n\t\t\t}\n\t\t}\n\n\t\tOpenLog();\n\n\t\tif (daemonmode)\n\t\t\tUpdatePid();\n\n\t\tCreateServerAuth();\n\t\tStartServer();\n#endif\n\n\t}\n\n\t/* Open display */\n\tif ((Dpy = XOpenDisplay(DisplayName)) == 0) {\n\t\tlogStream << APPNAME << \": could not open display '\"\n\t\t\t << DisplayName << \"'\" << endl;\n\t\tif (!testing) StopServer();\n\t\texit(ERR_EXIT);\n\t}\n\n\t/* Get screen and root window */\n\tScr = DefaultScreen(Dpy);\n\tRoot = RootWindow(Dpy, Scr);\n\n\t// Intern _XROOTPMAP_ID property\n\tBackgroundPixmapId = XInternAtom(Dpy, \"_XROOTPMAP_ID\", False);\n\n\t/* for tests we use a standard window */\n\tif (testing) {\n\t\tWindow RealRoot = RootWindow(Dpy, Scr);\n\t\tRoot = XCreateSimpleWindow(Dpy, RealRoot, 0, 0, 1280, 1024, 0, 0, 0);\n\t\tXMapWindow(Dpy, Root);\n\t\tXFlush(Dpy);\n\t} else {\n\t\tblankScreen();\n\t}\n\n\tHideCursor();\n\n\t/* Create panel */\n\tLoginPanel = new Panel(Dpy, Scr, Root, cfg, themedir, Panel::Mode_DM);\n\tbool firstloop = true; /* 1st time panel is shown (for automatic username) */\n\tbool focuspass = cfg->getOption(\"focus_password\")==\"yes\";\n\tbool autologin = cfg->getOption(\"auto_login\")==\"yes\";\n\n\tif (firstlogin && cfg->getOption(\"default_user\") != \"\") {\n\t\tLoginPanel->SetName(cfg->getOption(\"default_user\"));\n#ifdef USE_PAM\n\t\tpam.set_item(PAM::Authenticator::User, cfg->getOption(\"default_user\").c_str());\n#endif\n\t\tfirstlogin = false;\n\t\tif (autologin) {\n\t\t\tLogin();\n\t\t}\n\t}\n\n\t/* Set NumLock */\n\tstring numlock = cfg->getOption(\"numlock\");\n\tif (numlock == \"on\") {\n\t\tNumLock::setOn(Dpy);\n\t} else if (numlock == \"off\") {\n\t\tNumLock::setOff(Dpy);\n\t}\n\n\t/* Start looping */\n\tint panelclosed = 1;\n\tPanel::ActionType Action;\n\n\twhile (1) {\n\t\tif (panelclosed) {\n\t\t\t/* Init root */\n\t\t\tsetBackground(themedir);\n\n\t\t\t/* Close all clients */\n\t\t\tif (!testing) {\n\t\t\t\tKillAllClients(False);\n\t\t\t\tKillAllClients(True);\n\t\t\t}\n\n\t\t\t/* Show panel */\n\t\t\tLoginPanel->OpenPanel();\n\t\t}\n\n\t\tLoginPanel->Reset();\n\n\t\tif (firstloop && cfg->getOption(\"default_user\") != \"\")\n\t\t\tLoginPanel->SetName(cfg->getOption(\"default_user\"));\n\n        if (firstloop)\n            LoginPanel->SwitchSession();\n\n\t\tif (!AuthenticateUser(focuspass && firstloop)) {\n\t\t\tpanelclosed = 0;\n\t\t\tfirstloop = false;\n\t\t\tLoginPanel->ClearPanel();\n\t\t\tXBell(Dpy, 100);\n\t\t\tcontinue;\n\t\t}\n\n\t\tfirstloop = false;\n\n\t\tAction = LoginPanel->getAction();\n\t\t/* for themes test we just quit */\n\t\tif (testing)\n\t\t\tAction = Panel::Exit;\n\n\t\tpanelclosed = 1;\n\t\tLoginPanel->ClosePanel();\n\n\t\tswitch (Action) {\n\t\t\tcase Panel::Login:\n\t\t\t\tLogin();\n\t\t\t\tbreak;\n\t\t\tcase Panel::Console:\n\t\t\t\tConsole();\n\t\t\t\tbreak;\n\t\t\tcase Panel::Reboot:\n\t\t\t\tReboot();\n\t\t\t\tbreak;\n\t\t\tcase Panel::Halt:\n\t\t\t\tHalt();\n\t\t\t\tbreak;\n\t\t\tcase Panel::Suspend:\n\t\t\t\tSuspend();\n\t\t\t\tbreak;\n\t\t\tcase Panel::Exit:\n\t\t\t\tExit();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n\n#ifdef USE_PAM\nbool App::AuthenticateUser(bool focuspass)\n{\n\t/* Reset the username */\n\ttry{\n\t\tif (!focuspass)\n\t\t\tpam.set_item(PAM::Authenticator::User, 0);\n\t\tpam.authenticate();\n\t} catch(PAM::Auth_Exception& e) {\n\t\tswitch (LoginPanel->getAction()) {\n\t\t\tcase Panel::Exit:\n\t\t\tcase Panel::Console:\n\t\t\t\treturn true; /* <--- This is simply fake! */\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t\treturn false;\n\t} catch(PAM::Exception& e) {\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t\texit(ERR_EXIT);\n\t}\n\treturn true;\n}\n#else\nbool App::AuthenticateUser(bool focuspass)\n{\n\tif (!focuspass) {\n\t\tLoginPanel->EventHandler(Panel::Get_Name);\n\t\tswitch (LoginPanel->getAction()) {\n\t\t\tcase Panel::Exit:\n\t\t\tcase Panel::Console:\n\t\t\t\tlogStream << APPNAME << \": Got a special command (\"\n\t\t\t\t\t\t<< LoginPanel->GetName() << \")\" << endl;\n\t\t\t\treturn true; /* <--- This is simply fake! */\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tLoginPanel->EventHandler(Panel::Get_Passwd);\n\n\tchar *encrypted, *correct;\n\tstruct passwd *pw;\n\n\tswitch (LoginPanel->getAction()) {\n\t\tcase Panel::Suspend:\n\t\tcase Panel::Halt:\n\t\tcase Panel::Reboot:\n\t\t\tpw = getpwnam(\"root\");\n\t\t\tbreak;\n\t\tcase Panel::Console:\n\t\tcase Panel::Exit:\n\t\tcase Panel::Login:\n\t\t\tpw = getpwnam(LoginPanel->GetName().c_str());\n\t\t\tbreak;\n\t}\n\tendpwent();\n\tif (pw == 0)\n\t\treturn false;\n\n#ifdef HAVE_SHADOW\n\tstruct spwd *sp = getspnam(pw->pw_name);\n\tendspent();\n\tif (sp)\n\t\tcorrect = sp->sp_pwdp;\n\telse\n#endif\t\t/* HAVE_SHADOW */\n\t\tcorrect = pw->pw_passwd;\n\n\tif (correct == 0 || correct[0] == '\\0')\n\t\treturn true;\n\n\tencrypted = crypt(LoginPanel->GetPasswd().c_str(), correct);\n\treturn ((encrypted && strcmp(encrypted, correct) == 0) ? true : false);\n}\n#endif\n\nint App::GetServerPID()\n{\n\treturn ServerPID;\n}\n\n/* Hide the cursor */\nvoid App::HideCursor()\n{\n\tif (cfg->getOption(\"hidecursor\") == \"true\") {\n\t\tXColor\t\t\tblack;\n\t\tchar\t\t\tcursordata[1];\n\t\tPixmap\t\t\tcursorpixmap;\n\t\tCursor\t\t\tcursor;\n\t\tcursordata[0]=0;\n\t\tcursorpixmap=XCreateBitmapFromData(Dpy,Root,cursordata,1,1);\n\t\tblack.red=0;\n\t\tblack.green=0;\n\t\tblack.blue=0;\n\t\tcursor=XCreatePixmapCursor(Dpy,cursorpixmap,cursorpixmap,&black,&black,0,0);\n\t\tXDefineCursor(Dpy,Root,cursor);\n\t}\n}\n\nvoid App::Login()\n{\n\tstruct passwd *pw;\n\tpid_t pid;\n\n#ifdef USE_PAM\n\ttry{\n\t\tpam.open_session();\n\t\tpw = getpwnam(static_cast<const char*>(pam.get_item(PAM::Authenticator::User)));\n\t} catch(PAM::Cred_Exception& e) {\n\t\t/* Credentials couldn't be established */\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t\treturn;\n\t} catch(PAM::Exception& e) {\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t\texit(ERR_EXIT);\n\t}\n#else\n\tpw = getpwnam(LoginPanel->GetName().c_str());\n#endif\n\tendpwent();\n\tif (pw == 0)\n\t\treturn;\n\tif (pw->pw_shell[0] == '\\0') {\n\t\tsetusershell();\n\t\tstrcpy(pw->pw_shell, getusershell());\n\t\tendusershell();\n\t}\n\n\t/* Setup the environment */\n\tchar* term = getenv(\"TERM\");\n\tstring maildir = _PATH_MAILDIR;\n\tmaildir.append(\"/\");\n\tmaildir.append(pw->pw_name);\n\tstring xauthority = pw->pw_dir;\n\txauthority.append(\"/.Xauthority\");\n\n#ifdef USE_PAM\n\t/* Setup the PAM environment */\n\ttry{\n\t\tif (term) pam.setenv(\"TERM\", term);\n\t\tpam.setenv(\"HOME\", pw->pw_dir);\n\t\tpam.setenv(\"PWD\", pw->pw_dir);\n\t\tpam.setenv(\"SHELL\", pw->pw_shell);\n\t\tpam.setenv(\"USER\", pw->pw_name);\n\t\tpam.setenv(\"LOGNAME\", pw->pw_name);\n\t\tpam.setenv(\"PATH\", cfg->getOption(\"default_path\").c_str());\n\t\tpam.setenv(\"DISPLAY\", DisplayName);\n\t\tpam.setenv(\"MAIL\", maildir.c_str());\n\t\tpam.setenv(\"XAUTHORITY\", xauthority.c_str());\n\t} catch(PAM::Exception& e) {\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t\texit(ERR_EXIT);\n\t}\n#endif\n\n#ifdef USE_CONSOLEKIT\n\t/* Setup the ConsoleKit session */\n\ttry {\n\t\tck.open_session(DisplayName, pw->pw_uid);\n\t}\n\tcatch(Ck::Exception &e) {\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t\texit(ERR_EXIT);\n\t}\n#endif\n\n\t/* Create new process */\n\tpid = fork();\n\tif (pid == 0) {\n#ifdef USE_PAM\n\t\t/* Get a copy of the environment and close the child's copy */\n\t\t/* of the PAM-handle. */\n\t\tchar** child_env = pam.getenvlist();\n\n# ifdef USE_CONSOLEKIT\n\t\tchar** old_env = child_env;\n\n\t\t/* Grow the copy of the environment for the session cookie */\n\t\tint n;\n\t\tfor (n = 0; child_env[n] != NULL ; n++);\n\n\t\tn++;\n\n\t\tchild_env = static_cast<char**>(malloc(sizeof(char*)*n));\n\t\tmemcpy(child_env, old_env, sizeof(char*)*n+1);\n\t\tchild_env[n - 1] = StrConcat(\"XDG_SESSION_COOKIE=\", ck.get_xdg_session_cookie());\n\t\tchild_env[n] = NULL;\n# endif /* USE_CONSOLEKIT */\n#else\n\n# ifdef USE_CONSOLEKIT\n\t\tconst int Num_Of_Variables = 12; /* Number of env. variables + 1 */\n# else\n\t\tconst int Num_Of_Variables = 11; /* Number of env. variables + 1 */\n# endif /* USE_CONSOLEKIT */\n\t\tchar** child_env = static_cast<char**>(malloc(sizeof(char*)*Num_Of_Variables));\n\t\tint n = 0;\n\t\tif (term) child_env[n++]=StrConcat(\"TERM=\", term);\n\t\tchild_env[n++]=StrConcat(\"HOME=\", pw->pw_dir);\n\t\tchild_env[n++]=StrConcat(\"PWD=\", pw->pw_dir);\n\t\tchild_env[n++]=StrConcat(\"SHELL=\", pw->pw_shell);\n\t\tchild_env[n++]=StrConcat(\"USER=\", pw->pw_name);\n\t\tchild_env[n++]=StrConcat(\"LOGNAME=\", pw->pw_name);\n\t\tchild_env[n++]=StrConcat(\"PATH=\", cfg->getOption(\"default_path\").c_str());\n\t\tchild_env[n++]=StrConcat(\"DISPLAY=\", DisplayName);\n\t\tchild_env[n++]=StrConcat(\"MAIL=\", maildir.c_str());\n\t\tchild_env[n++]=StrConcat(\"XAUTHORITY=\", xauthority.c_str());\n# ifdef USE_CONSOLEKIT\n\t\tchild_env[n++]=StrConcat(\"XDG_SESSION_COOKIE=\", ck.get_xdg_session_cookie());\n# endif /* USE_CONSOLEKIT */\n\t\tchild_env[n++]=0;\n\n#endif\n\n\t\t/* Login process starts here */\n\t\tSwitchUser Su(pw, cfg, DisplayName, child_env);\n\t\tstring session = LoginPanel->getSession();\n\t\tstring loginCommand = cfg->getOption(\"login_cmd\");\n\t\treplaceVariables(loginCommand, SESSION_VAR, session);\n\t\treplaceVariables(loginCommand, THEME_VAR, themeName);\n\t\tstring sessStart = cfg->getOption(\"sessionstart_cmd\");\n\t\tif (sessStart != \"\") {\n\t\t\treplaceVariables(sessStart, USER_VAR, pw->pw_name);\n\t\t\tsystem(sessStart.c_str());\n\t\t}\n\t\tSu.Login(loginCommand.c_str(), mcookie.c_str());\n\t\t_exit(OK_EXIT);\n\t}\n\n#ifndef XNEST_DEBUG\n\tCloseLog();\n#endif\n\n\t/* Wait until user is logging out (login process terminates) */\n\tpid_t wpid = -1;\n\tint status;\n\twhile (wpid != pid) {\n\t\twpid = wait(&status);\n\t\tif (wpid == ServerPID)\n\t\t\txioerror(Dpy);\t/* Server died, simulate IO error */\n\t}\n\tif (WIFEXITED(status) && WEXITSTATUS(status)) {\n\t\tLoginPanel->Message(\"Failed to execute login command\");\n\t\tsleep(3);\n\t} else {\n\t\t string sessStop = cfg->getOption(\"sessionstop_cmd\");\n\t\t if (sessStop != \"\") {\n\t\t\treplaceVariables(sessStop, USER_VAR, pw->pw_name);\n\t\t\tsystem(sessStop.c_str());\n\t\t}\n\t}\n\n#ifdef USE_CONSOLEKIT\n\ttry {\n\t\tck.close_session();\n\t} catch(Ck::Exception &e) {\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t}\n#endif\n\n#ifdef USE_PAM\n\ttry {\n\t\tpam.close_session();\n\t} catch(PAM::Exception& e) {\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t}\n#endif\n\n/* Close all clients */\n\tKillAllClients(False);\n\tKillAllClients(True);\n\n\t/* Send HUP signal to clientgroup */\n\tkillpg(pid, SIGHUP);\n\n\t/* Send TERM signal to clientgroup, if error send KILL */\n\tif (killpg(pid, SIGTERM))\n\tkillpg(pid, SIGKILL);\n\n\tHideCursor();\n\n#ifndef XNEST_DEBUG\n\t/* Re-activate log file */\n\tOpenLog();\n\tRestartServer();\n#endif\n\n}\n\nvoid App::Reboot()\n{\n#ifdef USE_PAM\n\ttry {\n\t\tpam.end();\n\t} catch(PAM::Exception& e) {\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t}\n#endif\n\n\t/* Write message */\n\tLoginPanel->Message((char*)cfg->getOption(\"reboot_msg\").c_str());\n\tsleep(3);\n\n\t/* Stop server and reboot */\n\tStopServer();\n\tRemoveLock();\n\tsystem(cfg->getOption(\"reboot_cmd\").c_str());\n\texit(OK_EXIT);\n}\n\n\nvoid App::Halt()\n{\n#ifdef USE_PAM\n\ttry {\n\t\tpam.end();\n\t} catch (PAM::Exception& e) {\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t}\n#endif\n\n\t/* Write message */\n\tLoginPanel->Message((char*)cfg->getOption(\"shutdown_msg\").c_str());\n\tsleep(3);\n\n\t/* Stop server and halt */\n\tStopServer();\n\tRemoveLock();\n\tsystem(cfg->getOption(\"halt_cmd\").c_str());\n\texit(OK_EXIT);\n}\n\nvoid App::Suspend()\n{\n\tsleep(1);\n\tsystem(cfg->getOption(\"suspend_cmd\").c_str());\n}\n\n\nvoid App::Console()\n{\n\tint posx = 40;\n\tint posy = 40;\n\tint fontx = 9;\n\tint fonty = 15;\n\tint width = (XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)) - (posx * 2)) / fontx;\n\tint height = (XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)) - (posy * 2)) / fonty;\n\n\t/* Execute console */\n\tconst char* cmd = cfg->getOption(\"console_cmd\").c_str();\n\tchar *tmp = new char[strlen(cmd) + 60];\n\tsprintf(tmp, cmd, width, height, posx, posy, fontx, fonty);\n\tsystem(tmp);\n\tdelete [] tmp;\n}\n\nvoid App::Exit()\n{\n#ifdef USE_PAM\n\ttry {\n\t\tpam.end();\n\t} catch(PAM::Exception& e) {\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t}\n#endif\n\n\tif (testing) {\n\t\tconst char* testmsg = \"This is a test message :-)\";\n\t\tLoginPanel->Message(testmsg);\n\t\tsleep(3);\n\t\tdelete LoginPanel;\n\t\tXCloseDisplay(Dpy);\n\t} else {\n\t\tdelete LoginPanel;\n\t\tStopServer();\n\t\tRemoveLock();\n\t}\n\tdelete cfg;\n\texit(OK_EXIT);\n}\n\nint CatchErrors(Display *dpy, XErrorEvent *ev)\n{\n\treturn 0;\n}\n\nvoid App::RestartServer()\n{\n#ifdef USE_PAM\n\ttry {\n\t\tpam.end();\n\t} catch(PAM::Exception& e) {\n\t\tlogStream << APPNAME << \": \" << e << endl;\n\t}\n#endif\n\n\tStopServer();\n\tRemoveLock();\n\twhile (waitpid(-1, NULL, WNOHANG) > 0); /* Collects all dead childrens */\n\tRun();\n}\n\nvoid App::KillAllClients(Bool top)\n{\n\tWindow dummywindow;\n\tWindow *children;\n\tunsigned int nchildren;\n\tunsigned int i;\n\tXWindowAttributes attr;\n\n\tXSync(Dpy, 0);\n\tXSetErrorHandler(CatchErrors);\n\n\tnchildren = 0;\n\tXQueryTree(Dpy, Root, &dummywindow, &dummywindow, &children, &nchildren);\n\tif (!top) {\n\t\tfor (i=0; i<nchildren; i++) {\n\t\t\tif (XGetWindowAttributes(Dpy, children[i], &attr) && (attr.map_state == IsViewable))\n\t\t\t\tchildren[i] = XmuClientWindow(Dpy, children[i]);\n\t\t\telse\n\t\t\t\tchildren[i] = 0;\n\t\t}\n\t}\n\n\tfor (i=0; i<nchildren; i++) {\n\t\tif (children[i])\n\t\t\tXKillClient(Dpy, children[i]);\n\t}\n\tXFree((char *)children);\n\n\tXSync(Dpy, 0);\n\tXSetErrorHandler(NULL);\n}\n\nint App::ServerTimeout(int timeout, char* text)\n{\n\tint\ti = 0;\n\tint pidfound = -1;\n\tstatic char\t*lasttext;\n\n\twhile (1) {\n\t\tpidfound = waitpid(ServerPID, NULL, WNOHANG);\n\t\tif (pidfound == ServerPID)\n\t\t\tbreak;\n\t\tif (timeout) {\n\t\t\tif (i == 0 && text != lasttext)\n\t\t\t\tlogStream << endl << APPNAME << \": waiting for \" << text;\n\t\t\telse\n\t\t\t\tlogStream << \".\";\n\t\t}\n\t\tif (timeout)\n\t\t\tsleep(1);\n\t\tif (++i > timeout)\n\t\t\tbreak;\n\t}\n\n\tif (i > 0)\n\t\tlogStream << endl;\n\tlasttext = text;\n\n\treturn (ServerPID != pidfound);\n}\n\n\nint App::WaitForServer()\n{\n\tint\tncycles\t = 120;\n\tint\tcycles;\n\n\tfor (cycles = 0; cycles < ncycles; cycles++) {\n\t\tif ((Dpy = XOpenDisplay(DisplayName))) {\n\t\t\tXSetIOErrorHandler(xioerror);\n\t\t\treturn 1;\n\t\t} else {\n\t\t\tif (!ServerTimeout(1, (char *) \"X server to begin accepting connections\"))\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tlogStream << \"Giving up.\" << endl;\n\n\treturn 0;\n}\n\nint App::StartServer()\n{\n\tServerPID = fork();\n\n\tint argc = 1, pos = 0, i;\n\tstatic const int MAX_XSERVER_ARGS = 256;\n\tstatic char* server[MAX_XSERVER_ARGS+2] = { NULL };\n\tserver[0] = (char *)cfg->getOption(\"default_xserver\").c_str();\n\tstring argOption = cfg->getOption(\"xserver_arguments\");\n\t/* Add mandatory -xauth option */\n\targOption = argOption + \" -auth \" + cfg->getOption(\"authfile\");\n\tchar* args = new char[argOption.length()+2]; /* NULL plus vt */\n\tstrcpy(args, argOption.c_str());\n\n\tserverStarted = false;\n\n\tbool hasVtSet = false;\n\twhile (args[pos] != '\\0') {\n\t\tif (args[pos] == ' ' || args[pos] == '\\t') {\n\t\t\t*(args+pos) = '\\0';\n\t\t\tserver[argc++] = args+pos+1;\n\t\t} else if (pos == 0) {\n\t\t\tserver[argc++] = args+pos;\n\t\t}\n\t\t++pos;\n\n\t\tif (argc+1 >= MAX_XSERVER_ARGS) {\n\t\t\t/* ignore _all_ arguments to make sure the server starts at */\n\t\t\t/* all */\n\t\t\targc = 1;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tfor (i = 0; i < argc; i++) {\n\t\tif (server[i][0] == 'v' && server[i][1] == 't') {\n\t\t\tbool ok = false;\n\t\t\tCfg::string2int(server[i]+2, &ok);\n\t\t\tif (ok) {\n\t\t\t\thasVtSet = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!hasVtSet && daemonmode) {\n\t\tserver[argc++] = (char*)\"vt07\";\n\t}\n\tserver[argc] = NULL;\n\n\tswitch (ServerPID) {\n\tcase 0:\n\t\tsignal(SIGTTIN, SIG_IGN);\n\t\tsignal(SIGTTOU, SIG_IGN);\n\t\tsignal(SIGUSR1, SIG_IGN);\n\t\tsetpgid(0,getpid());\n\n\t\texecvp(server[0], server);\n\t\tlogStream << APPNAME << \": X server could not be started\" << endl;\n\t\texit(ERR_EXIT);\n\t\tbreak;\n\n\tcase -1:\n\t\tbreak;\n\n\tdefault:\n\t\terrno = 0;\n\t\tif (!ServerTimeout(0, (char *)\"\")) {\n\t\t\tServerPID = -1;\n\t\t\tbreak;\n\t\t}\n\n\t\t/* Wait for server to start up */\n\t\tif (WaitForServer() == 0) {\n\t\t\tlogStream << APPNAME << \": unable to connect to X server\" << endl;\n\t\t\tStopServer();\n\t\t\tServerPID = -1;\n\t\t\texit(ERR_EXIT);\n\t\t}\n\t\tbreak;\n\t}\n\n\tdelete [] args;\n\n\tserverStarted = true;\n\n\treturn ServerPID;\n}\n\njmp_buf CloseEnv;\nint IgnoreXIO(Display *d)\n{\n\tlogStream << APPNAME << \": connection to X server lost.\" << endl;\n\tlongjmp(CloseEnv, 1);\n}\n\nvoid App::StopServer()\n{\n\tsignal(SIGQUIT, SIG_IGN);\n\tsignal(SIGINT, SIG_IGN);\n\tsignal(SIGHUP, SIG_IGN);\n\tsignal(SIGPIPE, SIG_IGN);\n\tsignal(SIGTERM, SIG_DFL);\n\tsignal(SIGKILL, SIG_DFL);\n\n\t/* Catch X error */\n\tXSetIOErrorHandler(IgnoreXIO);\n\tif (!setjmp(CloseEnv) && Dpy)\n\t\tXCloseDisplay(Dpy);\n\n\t/* Send HUP to process group */\n\terrno = 0;\n\tif ((killpg(getpid(), SIGHUP) != 0) && (errno != ESRCH))\n\t\tlogStream << APPNAME << \": can't send HUP to process group \" << getpid() << endl;\n\n\t/* Send TERM to server */\n\tif (ServerPID < 0)\n\t\treturn;\n\n\terrno = 0;\n\n\tif (killpg(ServerPID, SIGTERM) < 0) {\n\t\tif (errno == EPERM) {\n\t\t\tlogStream << APPNAME << \": can't kill X server\" << endl;\n\t\t\texit(ERR_EXIT);\n\t\t}\n\t\tif (errno == ESRCH)\n\t\t\treturn;\n\t}\n\n\t/* Wait for server to shut down */\n\tif (!ServerTimeout(10, (char *)\"X server to shut down\")) {\n\t\tlogStream << endl;\n\t\treturn;\n\t}\n\n\tlogStream << endl << APPNAME <<\n\t\t\":  X server slow to shut down, sending KILL signal.\" << endl;\n\n\t/* Send KILL to server */\n\terrno = 0;\n\tif (killpg(ServerPID, SIGKILL) < 0) {\n\t\tif (errno == ESRCH)\n\t\t\treturn;\n\t}\n\n\t/* Wait for server to die */\n\tif (ServerTimeout(3, (char*)\"server to die\")) {\n\t\tlogStream << endl << APPNAME << \": can't kill server\" << endl;\n\t\texit(ERR_EXIT);\n\t}\n\tlogStream << endl;\n}\n\nvoid App::blankScreen()\n{\n\tGC gc = XCreateGC(Dpy, Root, 0, 0);\n\tXSetForeground(Dpy, gc, BlackPixel(Dpy, Scr));\n\tXFillRectangle(Dpy, Root, gc, 0, 0,\n\t\t\t\t   XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t   XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)));\n\tXFlush(Dpy);\n\tXFreeGC(Dpy, gc);\n\n}\n\nvoid App::setBackground(const string& themedir)\n{\n\tstring filename;\n\tfilename = themedir + \"/background.png\";\n\timage = new Image;\n\tbool loaded = image->Read(filename.c_str());\n\tif (!loaded) { /* try jpeg if png failed */\n\t\tfilename = themedir + \"/background.jpg\";\n\t\tloaded = image->Read(filename.c_str());\n\t}\n\n\tif (loaded) {\n\t\tstring bgstyle = cfg->getOption(\"background_style\");\n\t\tif (bgstyle == \"stretch\") {\n\t\t\timage->Resize(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t\t\tXHeightOfScreen(ScreenOfDisplay(Dpy, Scr)));\n\t\t} else if (bgstyle == \"tile\") {\n\t\t\timage->Tile(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t\t\tXHeightOfScreen(ScreenOfDisplay(Dpy, Scr)));\n\t\t} else if (bgstyle == \"center\") {\n\t\t\tstring hexvalue = cfg->getOption(\"background_color\");\n\t\t\thexvalue = hexvalue.substr(1,6);\n\t\t\timage->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t\t\tXHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t\t\thexvalue.c_str());\n\t\t} else { /* plain color or error */\n\t\t\tstring hexvalue = cfg->getOption(\"background_color\");\n\t\t\thexvalue = hexvalue.substr(1,6);\n\t\t\timage->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t\t\tXHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t\t\thexvalue.c_str());\n\t\t}\n\t\tPixmap p = image->createPixmap(Dpy, Scr, Root);\n\t\tXSetWindowBackgroundPixmap(Dpy, Root, p);\n\t\tXChangeProperty(Dpy, Root, BackgroundPixmapId, XA_PIXMAP, 32,\n\t\t\tPropModeReplace, (unsigned char *)&p, 1);\n\t}\n\tXClearWindow(Dpy, Root);\n\n\tXFlush(Dpy);\n\tdelete image;\n}\n\n/* Check if there is a lockfile and a corresponding process */\nvoid App::GetLock()\n{\n\tstd::ifstream lockfile(cfg->getOption(\"lockfile\").c_str());\n\tif (!lockfile) {\n\t\t/* no lockfile present, create one */\n\t\tstd::ofstream lockfile(cfg->getOption(\"lockfile\").c_str(), ios_base::out);\n\t\tif (!lockfile) {\n\t\t\tlogStream << APPNAME << \": Could not create lock file: \" <<\n\t\t\t\t\tcfg->getOption(\"lockfile\").c_str() << std::endl;\n\t\t\texit(ERR_EXIT);\n\t\t}\n\t\tlockfile << getpid() << std::endl;\n\t\tlockfile.close();\n\t} else {\n\t\t/* lockfile present, read pid from it */\n\t\tint pid = 0;\n\t\tlockfile >> pid;\n\t\tlockfile.close();\n\t\tif (pid > 0) {\n\t\t\t/* see if process with this pid exists */\n\t\t\tint ret = kill(pid, 0);\n\t\t\tif (ret == 0 || (ret == -1 && errno == EPERM) ) {\n\t\t\t\tlogStream << APPNAME <<\n\t\t\t\t\t\": Another instance of the program is already running with PID \"\n\t\t\t\t\t<< pid << std::endl;\n\t\t\t\texit(0);\n\t\t\t} else {\n\t\t\t\tlogStream << APPNAME << \": Stale lockfile found, removing it\" << std::endl;\n\t\t\t\tstd::ofstream lockfile(cfg->getOption(\"lockfile\").c_str(), ios_base::out);\n\t\t\t\tif (!lockfile) {\n\t\t\t\t\tlogStream << APPNAME <<\n\t\t\t\t\t\t\": Could not create new lock file: \" << cfg->getOption(\"lockfile\")\n\t\t\t\t\t\t<< std::endl;\n\t\t\t\t\texit(ERR_EXIT);\n\t\t\t\t}\n\t\t\t\tlockfile << getpid() << std::endl;\n\t\t\t\tlockfile.close();\n\t\t\t}\n\t\t}\n\t}\n}\n\n/* Remove lockfile and close logs */\nvoid App::RemoveLock()\n{\n\tremove(cfg->getOption(\"lockfile\").c_str());\n}\n\n/* Get server start check flag. */\nbool App::isServerStarted()\n{\n\treturn serverStarted;\n}\n\n/* Redirect stdout and stderr to log file */\nvoid App::OpenLog()\n{\n\tif ( !logStream.openLog( cfg->getOption(\"logfile\").c_str() ) ) {\n\t\tlogStream <<  APPNAME << \": Could not accesss log file: \" << cfg->getOption(\"logfile\") << endl;\n\t\tRemoveLock();\n\t\texit(ERR_EXIT);\n\t}\n\t/* I should set the buffers to imediate write, but I just flush on every << operation. */\n}\n\n/* Relases stdout/err */\nvoid App::CloseLog()\n{\n\t/* Simply closing the log */\n\tlogStream.closeLog();\n}\n\nstring App::findValidRandomTheme(const string& set)\n{\n\t/* extract random theme from theme set; return empty string on error */\n\tstring name = set;\n\tstruct stat buf;\n\n\tif (name[name.length()-1] == ',') {\n\t\tname = name.substr(0, name.length() - 1);\n\t}\n\n\tUtil::srandom(Util::makeseed());\n\n\tvector<string> themes;\n\tstring themefile;\n\tCfg::split(themes, name, ',');\n\tdo {\n\t\tint sel = Util::random() % themes.size();\n\n\t\tname = Cfg::Trim(themes[sel]);\n\t\tthemefile = string(THEMESDIR) +\"/\" + name + THEMESFILE;\n\t\tif (stat(themefile.c_str(), &buf) != 0) {\n\t\t\tthemes.erase(find(themes.begin(), themes.end(), name));\n\t\t\tlogStream << APPNAME << \": Invalid theme in config: \"\n\t\t\t\t << name << endl;\n\t\t\tname = \"\";\n\t\t}\n\t} while (name == \"\" && themes.size());\n\treturn name;\n}\n\n\nvoid App::replaceVariables(string& input,\n\t\t\t   const string& var,\n\t\t\t   const string& value)\n{\n\tstring::size_type pos = 0;\n\tint len = var.size();\n\twhile ((pos = input.find(var, pos)) != string::npos) {\n\t\tinput = input.substr(0, pos) + value + input.substr(pos+len);\n\t}\n}\n\n/*\n * We rely on the fact that all bits generated by Util::random()\n * are usable, so we are taking full words from its output.\n */\nvoid App::CreateServerAuth()\n{\n\t/* create mit cookie */\n\tuint16_t word;\n\tuint8_t hi, lo;\n\tint i;\n\tstring authfile;\n\tconst char *digits = \"0123456789abcdef\";\n\tUtil::srandom(Util::makeseed());\n\tfor (i = 0; i < App::mcookiesize; i+=4) {\n\t\tword = Util::random() & 0xffff;\n\t\tlo = word & 0xff;\n\t\thi = word >> 8;\n\t\tmcookie[i] = digits[lo & 0x0f];\n\t\tmcookie[i+1] = digits[lo >> 4];\n\t\tmcookie[i+2] = digits[hi & 0x0f];\n\t\tmcookie[i+3] = digits[hi >> 4];\n\t}\n\t/* reinitialize auth file */\n\tauthfile = cfg->getOption(\"authfile\");\n\tremove(authfile.c_str());\n\tputenv(StrConcat(\"XAUTHORITY=\", authfile.c_str()));\n\tUtil::add_mcookie(mcookie, \":0\", cfg->getOption(\"xauth_path\"),\n\t  authfile);\n}\n\nchar* App::StrConcat(const char* str1, const char* str2)\n{\n\tchar* tmp = new char[strlen(str1) + strlen(str2) + 1];\n\tstrcpy(tmp, str1);\n\tstrcat(tmp, str2);\n\treturn tmp;\n}\n\nvoid App::UpdatePid()\n{\n\tstd::ofstream lockfile(cfg->getOption(\"lockfile\").c_str(), ios_base::out);\n\tif (!lockfile) {\n\t\tlogStream << APPNAME << \": Could not update lock file: \" <<\n\t\t\t\tcfg->getOption(\"lockfile\").c_str() << endl;\n\t\texit(ERR_EXIT);\n\t}\n\tlockfile << getpid() << endl;\n\tlockfile.close();\n}\n"
  },
  {
    "path": "app.h",
    "content": "/* SLiM - Simple Login Manager\n *  Copyright (C) 1997, 1998 Per Liden\n *  Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n *  Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n *\n *  This program is free software; you can redistribute it and/or modify\n *  it under the terms of the GNU General Public License as published by\n *  the Free Software Foundation; either version 2 of the License, or\n *  (at your option) any later version.\n */\n\n#ifndef _APP_H_\n#define _APP_H_\n\n#include <X11/Xlib.h>\n#include <X11/Xatom.h>\n#include <signal.h>\n#include <unistd.h>\n#include <sys/wait.h>\n#include <errno.h>\n#include <setjmp.h>\n#include <stdlib.h>\n#include <iostream>\n#include \"panel.h\"\n#include \"cfg.h\"\n#include \"image.h\"\n\n#ifdef USE_PAM\n#include \"PAM.h\"\n#endif\n#ifdef USE_CONSOLEKIT\n#include \"Ck.h\"\n#endif\n\nclass App {\npublic:\n\tApp(int argc, char **argv);\n\t~App();\n\tvoid Run();\n\tint GetServerPID();\n\tvoid RestartServer();\n\tvoid StopServer();\n\n\t/* Lock functions */\n\tvoid GetLock();\n\tvoid RemoveLock();\n\n\tbool isServerStarted();\n\nprivate:\n\tvoid Login();\n\tvoid Reboot();\n\tvoid Halt();\n\tvoid Suspend();\n\tvoid Console();\n\tvoid Exit();\n\tvoid KillAllClients(Bool top);\n\tvoid ReadConfig();\n\tvoid OpenLog();\n\tvoid CloseLog();\n\tvoid HideCursor();\n\tvoid CreateServerAuth();\n\tchar *StrConcat(const char *str1, const char *str2);\n\tvoid UpdatePid();\n\n\tbool AuthenticateUser(bool focuspass);\n\n\tstatic std::string findValidRandomTheme(const std::string &set);\n\tstatic void replaceVariables(std::string &input,\n\t\t\t\t\t\t\t\t const std::string &var,\n\t\t\t\t\t\t\t\t const std::string &value);\n\n\t/* Server functions */\n\tint StartServer();\n\tint ServerTimeout(int timeout, char *string);\n\tint WaitForServer();\n\n\t/* Private data */\n\tWindow Root;\n\tDisplay *Dpy;\n\tint Scr;\n\tPanel *LoginPanel;\n\tint ServerPID;\n\tconst char *DisplayName;\n\tbool serverStarted;\n\n#ifdef USE_PAM\n\tPAM::Authenticator pam;\n#endif\n#ifdef USE_CONSOLEKIT\n\tCk::Session ck;\n#endif\n\n\t/* Options */\n\tchar *DispName;\n\n\tCfg *cfg;\n\n\tPixmap BackgroundPixmap;\n\n\tvoid blankScreen();\n\tImage *image;\n\tAtom BackgroundPixmapId;\n\tvoid setBackground(const std::string &themedir);\n\n\tbool firstlogin;\n\tbool daemonmode;\n\tbool force_nodaemon;\n\t/* For testing themes */\n\tchar *testtheme;\n\tbool testing;\n\n\tstd::string themeName;\n\tstd::string mcookie;\n\n\tconst int mcookiesize;\n};\n\n#endif /* _APP_H_ */\n"
  },
  {
    "path": "cfg.cpp",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n   Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n   Copyright (C) 2012-13 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n*/\n\n#include <fstream>\n#include <string>\n#include <iostream>\n#include <unistd.h>\n#include <stdlib.h>\n\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <dirent.h>\n\n#include \"cfg.h\"\n\nusing namespace std;\n\ntypedef pair<string,string> option;\n\nCfg::Cfg()\n\t: currentSession(-1)\n{\n\t/* Configuration options */\n\toptions.insert(option(\"default_path\",\"/bin:/usr/bin:/usr/local/bin\"));\n\toptions.insert(option(\"default_xserver\",\"/usr/bin/X\"));\n\toptions.insert(option(\"xserver_arguments\",\"\"));\n\toptions.insert(option(\"numlock\",\"\"));\n\toptions.insert(option(\"daemon\",\"\"));\n\toptions.insert(option(\"xauth_path\",\"/usr/bin/xauth\"));\n\toptions.insert(option(\"login_cmd\",\"exec /bin/bash -login ~/.xinitrc %session\"));\n\toptions.insert(option(\"halt_cmd\",\"/sbin/shutdown -h now\"));\n\toptions.insert(option(\"reboot_cmd\",\"/sbin/shutdown -r now\"));\n\toptions.insert(option(\"suspend_cmd\",\"\"));\n\toptions.insert(option(\"sessionstart_cmd\",\"\"));\n\toptions.insert(option(\"sessionstop_cmd\",\"\"));\n\toptions.insert(option(\"console_cmd\",\"/usr/bin/xterm -C -fg white -bg black +sb -g %dx%d+%d+%d -fn %dx%d -T \"\"Console login\"\" -e /bin/sh -c \"\"/bin/cat /etc/issue; exec /bin/login\"\"\"));\n\toptions.insert(option(\"screenshot_cmd\",\"import -window root /slim.png\"));\n\toptions.insert(option(\"welcome_msg\",\"Welcome to %host\"));\n\toptions.insert(option(\"session_msg\",\"Session:\"));\n\toptions.insert(option(\"default_user\",\"\"));\n\toptions.insert(option(\"focus_password\",\"no\"));\n\toptions.insert(option(\"auto_login\",\"no\"));\n\toptions.insert(option(\"current_theme\",\"default\"));\n\toptions.insert(option(\"lockfile\",\"/var/run/slim.lock\"));\n\toptions.insert(option(\"logfile\",\"/var/log/slim.log\"));\n\toptions.insert(option(\"authfile\",\"/var/run/slim.auth\"));\n\toptions.insert(option(\"shutdown_msg\",\"The system is halting...\"));\n\toptions.insert(option(\"reboot_msg\",\"The system is rebooting...\"));\n\toptions.insert(option(\"sessiondir\",\"\"));\n\toptions.insert(option(\"hidecursor\",\"false\"));\n\n\t/* Theme stuff */\n\toptions.insert(option(\"input_panel_x\",\"50%\"));\n\toptions.insert(option(\"input_panel_y\",\"40%\"));\n\toptions.insert(option(\"input_name_x\",\"200\"));\n\toptions.insert(option(\"input_name_y\",\"154\"));\n\toptions.insert(option(\"input_pass_x\",\"-1\")); /* default is single inputbox */\n\toptions.insert(option(\"input_pass_y\",\"-1\"));\n\toptions.insert(option(\"input_font\",\"Verdana:size=11\"));\n\toptions.insert(option(\"input_color\", \"#000000\"));\n\toptions.insert(option(\"input_cursor_height\",\"20\"));\n\toptions.insert(option(\"input_maxlength_name\",\"20\"));\n\toptions.insert(option(\"input_maxlength_passwd\",\"20\"));\n\toptions.insert(option(\"input_shadow_xoffset\", \"0\"));\n\toptions.insert(option(\"input_shadow_yoffset\", \"0\"));\n\toptions.insert(option(\"input_shadow_color\",\"#FFFFFF\"));\n\n\toptions.insert(option(\"welcome_font\",\"Verdana:size=14\"));\n\toptions.insert(option(\"welcome_color\",\"#FFFFFF\"));\n\toptions.insert(option(\"welcome_x\",\"-1\"));\n\toptions.insert(option(\"welcome_y\",\"-1\"));\n\toptions.insert(option(\"welcome_shadow_xoffset\", \"0\"));\n\toptions.insert(option(\"welcome_shadow_yoffset\", \"0\"));\n\toptions.insert(option(\"welcome_shadow_color\",\"#FFFFFF\"));\n\n\toptions.insert(option(\"intro_msg\",\"\"));\n\toptions.insert(option(\"intro_font\",\"Verdana:size=14\"));\n\toptions.insert(option(\"intro_color\",\"#FFFFFF\"));\n\toptions.insert(option(\"intro_x\",\"-1\"));\n\toptions.insert(option(\"intro_y\",\"-1\"));\n\n\toptions.insert(option(\"background_style\",\"stretch\"));\n\toptions.insert(option(\"background_color\",\"#CCCCCC\"));\n\n\toptions.insert(option(\"username_font\",\"Verdana:size=12\"));\n\toptions.insert(option(\"username_color\",\"#FFFFFF\"));\n\toptions.insert(option(\"username_x\",\"-1\"));\n\toptions.insert(option(\"username_y\",\"-1\"));\n\toptions.insert(option(\"username_msg\",\"Please enter your username\"));\n\toptions.insert(option(\"username_shadow_xoffset\", \"0\"));\n\toptions.insert(option(\"username_shadow_yoffset\", \"0\"));\n\toptions.insert(option(\"username_shadow_color\",\"#FFFFFF\"));\n\n\toptions.insert(option(\"password_x\",\"-1\"));\n\toptions.insert(option(\"password_y\",\"-1\"));\n\toptions.insert(option(\"password_msg\",\"Please enter your password\"));\n\n\toptions.insert(option(\"msg_color\",\"#FFFFFF\"));\n\toptions.insert(option(\"msg_font\",\"Verdana:size=16:bold\"));\n\toptions.insert(option(\"msg_x\",\"40\"));\n\toptions.insert(option(\"msg_y\",\"40\"));\n\toptions.insert(option(\"msg_shadow_xoffset\", \"0\"));\n\toptions.insert(option(\"msg_shadow_yoffset\", \"0\"));\n\toptions.insert(option(\"msg_shadow_color\",\"#FFFFFF\"));\n\n\toptions.insert(option(\"session_color\",\"#FFFFFF\"));\n\toptions.insert(option(\"session_font\",\"Verdana:size=16:bold\"));\n\toptions.insert(option(\"session_x\",\"50%\"));\n\toptions.insert(option(\"session_y\",\"90%\"));\n\toptions.insert(option(\"session_shadow_xoffset\", \"0\"));\n\toptions.insert(option(\"session_shadow_yoffset\", \"0\"));\n\toptions.insert(option(\"session_shadow_color\",\"#FFFFFF\"));\n\n\t// slimlock-specific options\n\toptions.insert(option(\"dpms_standby_timeout\", \"60\"));\n\toptions.insert(option(\"dpms_off_timeout\", \"600\"));\n\toptions.insert(option(\"wrong_passwd_timeout\", \"2\"));\n\toptions.insert(option(\"passwd_feedback_x\", \"50%\"));\n\toptions.insert(option(\"passwd_feedback_y\", \"10%\"));\n\toptions.insert(option(\"passwd_feedback_msg\", \"Authentication failed\"));\n\toptions.insert(option(\"passwd_feedback_capslock\", \"Authentication failed (CapsLock is on)\"));\n\toptions.insert(option(\"show_username\", \"1\"));\n\toptions.insert(option(\"show_welcome_msg\", \"0\"));\n\toptions.insert(option(\"tty_lock\", \"1\"));\n\toptions.insert(option(\"bell\", \"1\"));\n\n\terror = \"\";\n}\n\nCfg::~Cfg() {\n\toptions.clear();\n}\n/*\n * Creates the Cfg object and parses\n * known options from the given configfile / themefile\n */\nbool Cfg::readConf(string configfile) {\n\tint n = -1;\n\tsize_t pos = 0;\n\tstring line, next, op, fn(configfile);\n\tmap<string,string>::iterator it;\n\tifstream cfgfile(fn.c_str());\n\n\tif (!cfgfile) {\n\t\terror = \"Cannot read configuration file: \" + configfile;\n\t\treturn false;\n\t}\n\twhile (getline(cfgfile, line)) {\n\t\tif ((pos = line.find('\\\\')) != string::npos) {\n\t\t\tif (line.length() == pos + 1) {\n\t\t\t\tline.replace(pos, 1, \" \");\n\t\t\t\tnext = next + line;\n\t\t\t\tcontinue;\n\t\t\t} else\n\t\t\t\tline.replace(pos, line.length() - pos, \" \");\n\t\t}\n\n\t\tif (!next.empty()) {\n\t\t\tline = next + line;\n\t\t\tnext = \"\";\n\t\t}\n\t\tit = options.begin();\n\t\twhile (it != options.end()) {\n\t\t\top = it->first;\n\t\t\tn = line.find(op);\n\t\t\tif (n == 0)\n\t\t\t\toptions[op] = parseOption(line, op);\n\t\t\t++it;\n\t\t}\n\t}\n\tcfgfile.close();\n\n\tfillSessionList();\n\n\treturn true;\n}\n\n/* Returns the option value, trimmed */\nstring Cfg::parseOption(string line, string option ) {\n\treturn Trim( line.substr(option.size(), line.size() - option.size()));\n}\n\nconst string& Cfg::getError() const {\n\treturn error;\n}\n\nstring& Cfg::getOption(string option) {\n\treturn options[option];\n}\n\n/* return a trimmed string */\nstring Cfg::Trim( const string& s ) {\n\tif ( s.empty() ) {\n\t\treturn s;\n\t}\n\tint pos = 0;\n\tstring line = s;\n\tint len = line.length();\n\twhile ( pos < len && isspace( line[pos] ) ) {\n\t\t++pos;\n\t}\n\tline.erase( 0, pos );\n\tpos = line.length()-1;\n\twhile ( pos > -1 && isspace( line[pos] ) ) {\n\t\t--pos;\n\t}\n\tif ( pos != -1 ) {\n\t\tline.erase( pos+1 );\n\t}\n\treturn line;\n}\n\n/* Return the welcome message with replaced vars */\nstring Cfg::getWelcomeMessage(){\n\tstring s = getOption(\"welcome_msg\");\n\tint n = s.find(\"%host\");\n\tif (n >= 0) {\n\t\tstring tmp = s.substr(0, n);\n\t\tchar host[40];\n\t\tgethostname(host,40);\n\t\ttmp = tmp + host;\n\t\ttmp = tmp + s.substr(n+5, s.size() - n);\n\t\ts = tmp;\n\t}\n\tn = s.find(\"%domain\");\n\tif (n >= 0) {\n\t\tstring tmp = s.substr(0, n);;\n\t\tchar domain[40];\n\t\tgetdomainname(domain,40);\n\t\ttmp = tmp + domain;\n\t\ttmp = tmp + s.substr(n+7, s.size() - n);\n\t\ts = tmp;\n\t}\n\treturn s;\n}\n\nint Cfg::string2int(const char* string, bool* ok) {\n\tchar* err = 0;\n\tint l = (int)strtol(string, &err, 10);\n\tif (ok) {\n\t\t*ok = (*err == 0);\n\t}\n\treturn (*err == 0) ? l : 0;\n}\n\nint Cfg::getIntOption(std::string option) {\n\treturn string2int(options[option].c_str());\n}\n\n/* Get absolute position */\nint Cfg::absolutepos(const string& position, int max, int width) {\n\tint n = position.find(\"%\");\n\tif (n>0) { /* X Position expressed in percentage */\n\t\tint result = (max*string2int(position.substr(0, n).c_str())/100) - (width / 2);\n\t\treturn result < 0 ? 0 : result ;\n\t} else { /* Absolute X position */\n\t\treturn string2int(position.c_str());\n\t}\n}\n\n/* split a comma separated string into a vector of strings */\nvoid Cfg::split(vector<string>& v, const string& str, char c, bool useEmpty) {\n\tv.clear();\n\tstring::const_iterator s = str.begin();\n\tstring tmp;\n\twhile (true) {\n\t\tstring::const_iterator begin = s;\n\t\twhile (*s != c && s != str.end()) { ++s; }\n\ttmp = string(begin, s);\n\tif (useEmpty || tmp.size() > 0)\n\t\t\tv.push_back(tmp);\n\t\tif (s == str.end()) {\n\t\t\tbreak;\n\t\t}\n\t\tif (++s == str.end()) {\n\t\tif (useEmpty)\n\t\t\t\tv.push_back(\"\");\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid Cfg::fillSessionList(){\n\tstring strSessionDir  = getOption(\"sessiondir\");\n\n\tsessions.clear();\n\n\tif( !strSessionDir.empty() ) {\n\t\tDIR *pDir = opendir(strSessionDir.c_str());\n\n\t\tif (pDir != NULL) {\n\t\t\tstruct dirent *pDirent = NULL;\n\n\t\t\twhile ((pDirent = readdir(pDir)) != NULL) {\n\t\t\t\tstring strFile(strSessionDir);\n\t\t\t\tstrFile += \"/\";\n\t\t\t\tstrFile += pDirent->d_name;\n\n\t\t\t\tstruct stat oFileStat;\n\n\t\t\t\tif (stat(strFile.c_str(), &oFileStat) == 0) {\n\t\t\t\t\tif (S_ISREG(oFileStat.st_mode) &&\n\t\t\t\t\t\t\taccess(strFile.c_str(), R_OK) == 0){\n\t\t\t\t\t\tifstream desktop_file(strFile.c_str());\n\t\t\t\t\t\tif (desktop_file){\n\t\t\t\t\t\t\t string line, session_name = \"\", session_exec = \"\";\n\t\t\t\t\t\t\t while (getline( desktop_file, line )) {\n\t\t\t\t\t\t\t\t if (line.substr(0, 5) == \"Name=\") {\n\t\t\t\t\t\t\t\t\t session_name = line.substr(5);\n\t\t\t\t\t\t\t\t\t if (!session_exec.empty())\n\t\t\t\t\t\t\t\t\t\t break;\n\t\t\t\t\t\t\t\t } else\n\t\t\t\t\t\t\t\t\t if (line.substr(0, 5) == \"Exec=\") {\n\t\t\t\t\t\t\t\t\t\t session_exec = line.substr(5);\n\t\t\t\t\t\t\t\t\t\t if (!session_name.empty())\n\t\t\t\t\t\t\t\t\t\t\t break;\n\t\t\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t desktop_file.close();\n\t\t\t\t\t\t\t pair<string,string> session(session_name,session_exec);\n\t\t\t\t\t\t\t sessions.push_back(session);\n\t\t\t\t\t\t\t cout << session_exec << \" - \" << session_name << endl;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tclosedir(pDir);\n\t\t}\n\t}\n\n\tif (sessions.empty()){\n\t\tpair<string,string> session(\"\",\"\");\n\t\tsessions.push_back(session);\n\t}\n}\n\npair<string,string> Cfg::nextSession() {\n\tcurrentSession = (currentSession + 1) % sessions.size();\n\treturn sessions[currentSession];\n}\n"
  },
  {
    "path": "cfg.h",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n   Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n*/\n\n#ifndef _CFG_H_\n#define _CFG_H_\n\n#include <string>\n#include <map>\n#include <vector>\n\n#define INPUT_MAXLENGTH_NAME\t30\n#define INPUT_MAXLENGTH_PASSWD  50\n\n#define CFGFILE SYSCONFDIR\"/slim.conf\"\n#define THEMESDIR PKGDATADIR\"/themes\"\n#define THEMESFILE \"/slim.theme\"\n\nclass Cfg {\n\npublic:\n\tCfg();\n\t~Cfg();\n\n\tbool readConf(std::string configfile);\n\tstd::string parseOption(std::string line, std::string option);\n\tconst std::string& getError() const;\n\tstd::string& getOption(std::string option);\n\tint getIntOption(std::string option);\n\tstd::string getWelcomeMessage();\n\n\tstatic int absolutepos(const std::string &position, int max, int width);\n\tstatic int string2int(const char *string, bool *ok = 0);\n\tstatic void split(std::vector<std::string> &v, const std::string &str, \n\t\t\t\t\t  char c, bool useEmpty=true);\n\tstatic std::string Trim(const std::string &s);\n\n    std::pair<std::string,std::string> nextSession();\n\nprivate:\n\tvoid fillSessionList();\n\nprivate:\n\tstd::map<std::string,std::string> options;\n    std::vector<std::pair<std::string,std::string> > sessions;\n\tint currentSession;\n\tstd::string error;\n};\n\n#endif /* _CFG_H_ */\n"
  },
  {
    "path": "cmake/modules/FONTCONFIGConfig.cmake",
    "content": "#\n# Find the native FONTCONFIG includes and library\n#\n\n# This module defines\n# FONTCONFIG_INCLUDE_DIR, where to find art*.h etc\n# FONTCONFIG_LIBRARY, the libraries to link against to use FONTCONFIG.\n# FONTCONFIG_FOUND, If false, do not try to use FONTCONFIG.\n# LIBFONTCONFIG_LIBS, link information\n# LIBFONTCONFIG_CFLAGS, cflags for include information\n\nIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.5)\n  INCLUDE(UsePkgConfig)\n  PKGCONFIG(fontconfig _fontconfigIncDir _fontconfigLinkDir _fontconfigLinkFlags _fontconfigCflags)\n  SET(FONTCONFIG_LIBS ${_fontconfigCflags})\nELSE (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.5)\n  INCLUDE(FindPkgConfig)\n  pkg_search_module(FONTCONFIG REQUIRED fontconfig)\nENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} LESS 2.5)\n\n#INCLUDE(UsePkgConfig)\n\n# use pkg-config to get the directories and then use these values\n# in the FIND_PATH() and FIND_LIBRARY() calls\n#PKGCONFIG(fontconfig _fontconfigIncDir _fontconfigLinkDir _fontconfigLinkFlags _fontconfigCflags)\n\n#SET(FONTCONFIG_LIBS ${_fontconfigCflags})\n\nIF(BUILD_OSX_BUNDLE)\n  FIND_PATH(FONTCONFIG_INCLUDE_DIR\n    NAMES fontconfig/fontconfig.h\n    PATHS ${FONTCONFIG_INCLUDE_DIRS} /opt/local/include\n    NO_DEFAULT_PATH\n  )\n  FIND_LIBRARY(FONTCONFIG_LIBRARY \n    NAMES fontconfig\n    PATHS ${FONTCONFIG_LIBRARY_DIRS} /opt/local/lib\n    NO_DEFAULT_PATH\n  )\nELSE(BUILD_OSX_BUNDLE)\n  FIND_PATH(FONTCONFIG_INCLUDE_DIR \n    NAMES fontconfig/fontconfig.h\n\tPATHS ${FONTCONFIG_INCLUDE_DIRS} \n    ${_fontconfigIncDir}\n    /usr/include\n    /usr/local/include\n    PATH_SUFFIXES fontconfig\n  )\n  # quick hack as the above finds it nicely but our source includes the libart_lgpl text at the moment\n  #STRING(REGEX REPLACE \"/libart_lgpl\" \"\" FONTCONFIG_INCLUDE_DIR ${FONTCONFIG_INCLUDE_DIR})\n  FIND_LIBRARY(FONTCONFIG_LIBRARY NAMES fontconfig\n    PATHS ${FONTCONFIG_LIBRARY_DIRS} /usr/lib /usr/local/lib\n  )\nENDIF(BUILD_OSX_BUNDLE)\n\n\n# MESSAGE(STATUS \"fclib ${FONTCONFIG_LIBRARY}\")\n# MESSAGE(STATUS \"fcinclude ${FONTCONFIG_INCLUDE_DIR}\")\n\n\nIF (FONTCONFIG_LIBRARY)\n  IF (FONTCONFIG_INCLUDE_DIR)\n    SET( FONTCONFIG_FOUND \"YES\" )\n    SET( FONTCONFIG_LIBRARIES ${FONTCONFIG_LIBRARY} )\n\tFIND_PROGRAM(FONTCONFIG_CONFIG NAMES fontconfig-config PATHS ${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin /usr/bin /usr/nekoware/bin /usr/X11/bin)\n# \tEXEC_PROGRAM(${FONTCONFIG_CONFIG} ARGS --libs OUTPUT_VARIABLE FONTCONFIG_LIBS)\n# \tEXEC_PROGRAM(${FONTCONFIG_CONFIG} ARGS --cflags OUTPUT_VARIABLE FONTCONFIG_CFLAGS)\n#  \tMESSAGE(STATUS ${FONTCONFIG_LIBS})\n#  \tMESSAGE(STATUS ${FONTCONFIG_CFLAGS})\n  ENDIF (FONTCONFIG_INCLUDE_DIR)\nENDIF (FONTCONFIG_LIBRARY)\n"
  },
  {
    "path": "cmake/modules/FindCkConnector.cmake",
    "content": "# - Try to find the ConsoleKit connector library (libck-connector)\n# Once done this will define\n#\n#  CKCONNECTOR_FOUND - system has the CK Connector\n#  CKCONNECTOR_INCLUDE_DIR - the CK Connector include directory\n#  CKCONNECTOR_LIBRARIES - the libraries needed to use CK Connector\n\n# Copyright (c) 2008, Kevin Kofler, <kevin.kofler@chello.at>\n# modeled after FindLibArt.cmake:\n# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>\n#\n# Redistribution and use is allowed according to the terms of the BSD license.\n# For details see the accompanying COPYING-CMAKE-SCRIPTS file.\n\n\nif (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES)\n\n  # in cache already\n  SET(CKCONNECTOR_FOUND TRUE)\n\nelse (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES)\n\n  IF (NOT WIN32)\n    FIND_PACKAGE(PkgConfig)\n    IF (PKG_CONFIG_FOUND)\n      # use pkg-config to get the directories and then use these values\n      # in the FIND_PATH() and FIND_LIBRARY() calls\n      pkg_check_modules(_CKCONNECTOR_PC QUIET ck-connector)\n    ENDIF (PKG_CONFIG_FOUND)\n  ENDIF (NOT WIN32)\n\n  FIND_PATH(CKCONNECTOR_INCLUDE_DIR ck-connector.h\n     ${_CKCONNECTOR_PC_INCLUDE_DIRS}\n  )\n\n  FIND_LIBRARY(CKCONNECTOR_LIBRARIES NAMES ck-connector\n     PATHS\n     ${_CKCONNECTOR_PC_LIBDIR}\n  )\n\n\n  if (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES)\n     set(CKCONNECTOR_FOUND TRUE)\n  endif (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES)\n\n\n  if (CKCONNECTOR_FOUND)\n     if (NOT CkConnector_FIND_QUIETLY)\n        message(STATUS \"Found ck-connector: ${CKCONNECTOR_LIBRARIES}\")\n     endif (NOT CkConnector_FIND_QUIETLY)\n  else (CKCONNECTOR_FOUND)\n     if (CkConnector_FIND_REQUIRED)\n        message(FATAL_ERROR \"Could NOT find ck-connector\")\n     endif (CkConnector_FIND_REQUIRED)\n  endif (CKCONNECTOR_FOUND)\n\n  MARK_AS_ADVANCED(CKCONNECTOR_INCLUDE_DIR CKCONNECTOR_LIBRARIES)\n\nendif (CKCONNECTOR_INCLUDE_DIR AND CKCONNECTOR_LIBRARIES)\n"
  },
  {
    "path": "cmake/modules/FindDBus.cmake",
    "content": "# - Try to find the low-level D-Bus library\n# Once done this will define\n#\n#  DBUS_FOUND - system has D-Bus\n#  DBUS_INCLUDE_DIR - the D-Bus include directory\n#  DBUS_ARCH_INCLUDE_DIR - the D-Bus architecture-specific include directory\n#  DBUS_LIBRARIES - the libraries needed to use D-Bus\n\n# Copyright (c) 2008, Kevin Kofler, <kevin.kofler@chello.at>\n# modeled after FindLibArt.cmake:\n# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>\n#\n# Redistribution and use is allowed according to the terms of the BSD license.\n# For details see the accompanying COPYING-CMAKE-SCRIPTS file.\n\nif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES)\n\n  # in cache already\n  SET(DBUS_FOUND TRUE)\n\nelse (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES)\n\n  IF (NOT WIN32)\n    FIND_PACKAGE(PkgConfig)\n    IF (PKG_CONFIG_FOUND)\n      # use pkg-config to get the directories and then use these values\n      # in the FIND_PATH() and FIND_LIBRARY() calls\n      pkg_check_modules(_DBUS_PC QUIET dbus-1)\n    ENDIF (PKG_CONFIG_FOUND)\n  ENDIF (NOT WIN32)\n\n  FIND_PATH(DBUS_INCLUDE_DIR dbus/dbus.h\n    ${_DBUS_PC_INCLUDE_DIRS}\n    /usr/include\n    /usr/include/dbus-1.0\n    /usr/local/include\n  )\n\n  FIND_PATH(DBUS_ARCH_INCLUDE_DIR dbus/dbus-arch-deps.h\n    ${_DBUS_PC_INCLUDE_DIRS}\n    /usr/lib${LIB_SUFFIX}/include\n    /usr/lib${LIB_SUFFIX}/dbus-1.0/include\n    /usr/lib64/include\n    /usr/lib64/dbus-1.0/include\n    /usr/lib/include\n    /usr/lib/dbus-1.0/include\n  )\n\n  FIND_LIBRARY(DBUS_LIBRARIES NAMES dbus-1 dbus\n    PATHS\n     ${_DBUS_PC_LIBDIR}\n  )\n\n\n  if (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES)\n     set(DBUS_FOUND TRUE)\n  endif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES)\n\n\n  if (DBUS_FOUND)\n     if (NOT DBus_FIND_QUIETLY)\n        message(STATUS \"Found D-Bus: ${DBUS_LIBRARIES}\")\n     endif (NOT DBus_FIND_QUIETLY)\n  else (DBUS_FOUND)\n     if (DBus_FIND_REQUIRED)\n        message(FATAL_ERROR \"Could NOT find D-Bus\")\n     endif (DBus_FIND_REQUIRED)\n  endif (DBUS_FOUND)\n\n  MARK_AS_ADVANCED(DBUS_INCLUDE_DIR DBUS_ARCH_INCLUDE_DIR DBUS_LIBRARIES)\n\nendif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES)\n"
  },
  {
    "path": "cmake/modules/FindPAM.cmake",
    "content": "# - Try to find the PAM libraries\n# Once done this will define\n#\n#  PAM_FOUND - system has pam\n#  PAM_INCLUDE_DIR - the pam include directory\n#  PAM_LIBRARIES - libpam library\n\nif (PAM_INCLUDE_DIR AND PAM_LIBRARY)\n\t# Already in cache, be silent\n\tset(PAM_FIND_QUIETLY TRUE)\nendif (PAM_INCLUDE_DIR AND PAM_LIBRARY)\n\nfind_path(PAM_INCLUDE_DIR NAMES security/pam_appl.h pam/pam_appl.h)\nfind_library(PAM_LIBRARY pam)\nfind_library(DL_LIBRARY dl)\n\nif (PAM_INCLUDE_DIR AND PAM_LIBRARY)\n\tset(PAM_FOUND TRUE)\n\tif (DL_LIBRARY)\n\t\tset(PAM_LIBRARIES ${PAM_LIBRARY} ${DL_LIBRARY})\n\telse (DL_LIBRARY)\n\t\tset(PAM_LIBRARIES ${PAM_LIBRARY})\n\tendif (DL_LIBRARY)\n\n\tif (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h)\n\t\t# darwin claims to be something special\n\t\tset(HAVE_PAM_PAM_APPL_H 1)\n\tendif (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h)\n\n\tif (NOT DEFINED PAM_MESSAGE_CONST)\n\t\tinclude(CheckCXXSourceCompiles)\n\t\t# XXX does this work with plain c?\n\t\tcheck_cxx_source_compiles(\"\n#if ${HAVE_PAM_PAM_APPL_H}+0\n# include <pam/pam_appl.h>\n#else\n# include <security/pam_appl.h>\n#endif\n\nstatic int PAM_conv(\n\tint num_msg,\n\tconst struct pam_message **msg, /* this is the culprit */\n\tstruct pam_response **resp,\n\tvoid *ctx)\n{\n\treturn 0;\n}\n\nint main(void)\n{\n\tstruct pam_conv PAM_conversation = {\n\t\t&PAM_conv, /* this bombs out if the above does not match */\n\t\t0\n\t};\n\n\treturn 0;\n}\n\" PAM_MESSAGE_CONST)\n\tendif (NOT DEFINED PAM_MESSAGE_CONST)\n\tset(PAM_MESSAGE_CONST ${PAM_MESSAGE_CONST} CACHE BOOL \"PAM expects a conversation function with const pam_message\")\n\nendif (PAM_INCLUDE_DIR AND PAM_LIBRARY)\n\nif (PAM_FOUND)\n\tif (NOT PAM_FIND_QUIETLY)\n\t\tmessage(STATUS \"Found PAM: ${PAM_LIBRARIES}\")\n\tendif (NOT PAM_FIND_QUIETLY)\nelse (PAM_FOUND)\n\tif (PAM_FIND_REQUIRED)\n\t\tmessage(FATAL_ERROR \"PAM was not found\")\n\tendif(PAM_FIND_REQUIRED)\nendif (PAM_FOUND)\n\nmark_as_advanced(PAM_INCLUDE_DIR PAM_LIBRARY DL_LIBRARY PAM_MESSAGE_CONST)"
  },
  {
    "path": "const.h",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 1997, 1998 Per Liden\n   Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n   Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n*/\n\n#ifndef _CONST_H_\n#define _CONST_H_\n\n#define APPNAME\t\"slim\"\n#define DISPLAY\t\":0.0\"\n\n#define CONSOLE_STR\t \"console\"\n#define HALT_STR\t\t\"halt\"\n#define REBOOT_STR\t  \"reboot\"\n#define EXIT_STR\t\t\"exit\"\n#define SUSPEND_STR\t \"suspend\"\n\n#define HIDE\t\t0\n#define SHOW\t\t1\n\n#define GET_NAME\t0\n#define GET_PASSWD  1\n\n#define OK_EXIT\t 0\n#define ERR_EXIT\t1\n\n/* duration for showing error messages,\n * as \"login command failed\", in seconds \n */\n#define ERROR_DURATION  5\n\n/* variables replaced in login_cmd */\n#define SESSION_VAR\t \"%session\"\n#define THEME_VAR\t   \"%theme\"\n\n/* variables replaced in pre-session_cmd and post-session_cmd */\n#define USER_VAR\t   \"%user\"\n\n/* max height/width for images */\n#define MAX_DIMENSION 10000\n\n#endif /* _CONST_H_ */\n"
  },
  {
    "path": "image.cpp",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n   Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n   Copyright (C) 2012\tNobuhiro Iwamatsu <iwamatsu@nigauri.org>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n\n   The following code has been adapted and extended from\n   xplanet 1.0.1, Copyright (C) 2002-04 Hari Nair <hari@alumni.caltech.edu>\n*/\n\n#include <cctype>\n#include <cmath>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <iostream>\n\nusing namespace std;\n\n#include \"image.h\"\n\nextern \"C\" {\n\t#include <jpeglib.h>\n\t#include <png.h>\n}\n\nImage::Image() : width(0), height(0), area(0),\nrgb_data(NULL), png_alpha(NULL), quality_(80) {}\n\nImage::Image(const int w, const int h, const unsigned char *rgb, const unsigned char *alpha) :\nwidth(w), height(h), area(w*h), quality_(80) {\n\twidth = w;\n\theight = h;\n\tarea = w * h;\n\n\trgb_data = (unsigned char *) malloc(3 * area);\n\tmemcpy(rgb_data, rgb, 3 * area);\n\n\tif (alpha == NULL) {\n\t\tpng_alpha = NULL;\n\t} else {\n\t\tpng_alpha = (unsigned char *) malloc(area);\n\t\tmemcpy(png_alpha, alpha, area);\n\t}\n}\n\nImage::~Image() {\n\tfree(rgb_data);\n\tfree(png_alpha);\n}\n\nbool\nImage::Read(const char *filename) {\n\tchar buf[4];\n\tunsigned char *ubuf = (unsigned char *) buf;\n\tint success = 0;\n\n\tFILE *file;\n\tfile = fopen(filename, \"rb\");\n\tif (file == NULL)\n\t\treturn(false);\n\n\t/* see what kind of file we have */\n\n\tfread(buf, 1, 4, file);\n\tfclose(file);\n\n\tif ((ubuf[0] == 0x89) && !strncmp(\"PNG\", buf+1, 3))\n\t\tsuccess = readPng(filename, &width, &height, &rgb_data, &png_alpha);\n\telse if ((ubuf[0] == 0xff) && (ubuf[1] == 0xd8))\n\t\tsuccess = readJpeg(filename, &width, &height, &rgb_data);\n\telse {\n\t\tfprintf(stderr, \"Unknown image format\\n\");\n\t\tsuccess = 0;\n\t}\n\treturn(success == 1);\n}\n\nvoid\nImage::Reduce(const int factor) {\n\tif (factor < 1)\n\t\treturn;\n\n\tint scale = 1;\n\tfor (int i = 0; i < factor; i++)\n\t\tscale *= 2;\n\n\tdouble scale2 = scale*scale;\n\n\tint w = width / scale;\n\tint h = height / scale;\n\tint new_area = w * h;\n\n\tunsigned char *new_rgb = (unsigned char *) malloc(3 * new_area);\n\tmemset(new_rgb, 0, 3 * new_area);\n\n\tunsigned char *new_alpha = NULL;\n\tif (png_alpha != NULL) {\n\t\tnew_alpha = (unsigned char *) malloc(new_area);\n\t\tmemset(new_alpha, 0, new_area);\n\t}\n\n\tint ipos = 0;\n\tfor (int j = 0; j < height; j++) {\n\t\tint js = j / scale;\n\t\tfor (int i = 0; i < width; i++) {\n\t\t\tint is = i/scale;\n\t\t\tfor (int k = 0; k < 3; k++)\n\t\t\t\tnew_rgb[3*(js * w + is) + k] += static_cast<unsigned char> ((rgb_data[3*ipos + k] + 0.5) / scale2);\n\n\t\t\tif (png_alpha != NULL)\n\t\t\t\tnew_alpha[js * w + is] += static_cast<unsigned char> (png_alpha[ipos]/scale2);\n\t\t\tipos++;\n\t\t}\n\t}\n\n\tfree(rgb_data);\n\tfree(png_alpha);\n\n\trgb_data = new_rgb;\n\tpng_alpha = new_alpha;\n\twidth = w;\n\theight = h;\n\n\tarea = w * h;\n}\n\nvoid\nImage::Resize(const int w, const int h) {\n\n\tif (width==w && height==h){\n\t\treturn;\n\t}\n\n\tint new_area = w * h;\n\n\tunsigned char *new_rgb = (unsigned char *) malloc(3 * new_area);\n\tunsigned char *new_alpha = NULL;\n\tif (png_alpha != NULL)\n\t\tnew_alpha = (unsigned char *) malloc(new_area);\n\n\tconst double scale_x = ((double) w) / width;\n\tconst double scale_y = ((double) h) / height;\n\n\tint ipos = 0;\n\tfor (int j = 0; j < h; j++) {\n\t\tconst double y = j / scale_y;\n\t\tfor (int i = 0; i < w; i++) {\n\t\t\tconst double x = i / scale_x;\n\t\t\tif (new_alpha == NULL)\n\t\t\t\tgetPixel(x, y, new_rgb + 3*ipos);\n\t\t\telse\n\t\t\t\tgetPixel(x, y, new_rgb + 3*ipos, new_alpha + ipos);\n\t\t\tipos++;\n\t\t}\n\t}\n\n\tfree(rgb_data);\n\tfree(png_alpha);\n\n\trgb_data = new_rgb;\n\tpng_alpha = new_alpha;\n\twidth = w;\n\theight = h;\n\n\tarea = w * h;\n}\n\n/* Find the color of the desired point using bilinear interpolation. */\n/* Assume the array indices refer to the denter of the pixel, so each */\n/* pixel has corners at (i - 0.5, j - 0.5) and (i + 0.5, j + 0.5) */\nvoid\nImage::getPixel(double x, double y, unsigned char *pixel) {\n\tgetPixel(x, y, pixel, NULL);\n}\n\nvoid\nImage::getPixel(double x, double y, unsigned char *pixel, unsigned char *alpha) {\n\tif (x < -0.5)\n\t\tx = -0.5;\n\tif (x >= width - 0.5)\n\t\tx = width - 0.5;\n\n\tif (y < -0.5)\n\t\ty = -0.5;\n\tif (y >= height - 0.5)\n\t\ty = height - 0.5;\n\n\tint ix0 = (int) (floor(x));\n\tint ix1 = ix0 + 1;\n\tif (ix0 < 0)\n\t\tix0 = width - 1;\n\tif (ix1 >= width)\n\t\tix1 = 0;\n\n\tint iy0 = (int) (floor(y));\n\tint iy1 = iy0 + 1;\n\tif (iy0 < 0)\n\t\tiy0 = 0;\n\tif (iy1 >= height)\n\t\tiy1 = height - 1;\n\n\tconst double t = x - floor(x);\n\tconst double u = 1 - (y - floor(y));\n\n\tdouble weight[4];\n\tweight[1] = t * u;\n\tweight[0] = u - weight[1];\n\tweight[2] = 1 - t - u + weight[1];\n\tweight[3] = t - weight[1];\n\n\tunsigned char *pixels[4];\n\tpixels[0] = rgb_data + 3 * (iy0 * width + ix0);\n\tpixels[1] = rgb_data + 3 * (iy0 * width + ix1);\n\tpixels[2] = rgb_data + 3 * (iy1 * width + ix0);\n\tpixels[3] = rgb_data + 3 * (iy1 * width + ix1);\n\n\tmemset(pixel, 0, 3);\n\tfor (int i = 0; i < 4; i++) {\n\t\tfor (int j = 0; j < 3; j++)\n\t\t\tpixel[j] += (unsigned char) (weight[i] * pixels[i][j]);\n\t}\n\n\tif (alpha != NULL) {\n\t\tunsigned char pixels[4];\n\t\tpixels[0] = png_alpha[iy0 * width + ix0];\n\t\tpixels[1] = png_alpha[iy0 * width + ix1];\n\t\tpixels[2] = png_alpha[iy0 * width + ix0];\n\t\tpixels[3] = png_alpha[iy1 * width + ix1];\n\n\t\tfor (int i = 0; i < 4; i++)\n\t\t\t*alpha = (unsigned char) (weight[i] * pixels[i]);\n\t}\n}\n\n/* Merge the image with a background, taking care of the\n * image Alpha transparency. (background alpha is ignored).\n * The images is merged on position (x, y) on the\n * background, the background must contain the image.\n */\nvoid Image::Merge(Image* background, const int x, const int y) {\n\n\tif (x + width > background->Width()|| y + height > background->Height())\n\t\treturn;\n\n\tif (background->Width()*background->Height() != width*height)\n\t\tbackground->Crop(x, y, width, height);\n\n\tdouble tmp;\n\tunsigned char *new_rgb = (unsigned char *) malloc(3 * width * height);\n\tmemset(new_rgb, 0, 3 * width * height);\n\tconst unsigned char *bg_rgb = background->getRGBData();\n\n\tint ipos = 0;\n\tif (png_alpha != NULL){\n\t\tfor (int j = 0; j < height; j++) {\n\t\t\tfor (int i = 0; i < width; i++) {\n\t\t\t\tfor (int k = 0; k < 3; k++) {\n\t\t\t\t\ttmp = rgb_data[3*ipos + k]*png_alpha[ipos]/255.0\n\t\t\t\t\t\t\t+ bg_rgb[3*ipos + k]*(1-png_alpha[ipos]/255.0);\n\t\t\t\t\tnew_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);\n\t\t\t\t}\n\t\t\t\tipos++;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor (int j = 0; j < height; j++) {\n\t\t\tfor (int i = 0; i < width; i++) {\n\t\t\t\tfor (int k = 0; k < 3; k++) {\n\t\t\t\t\ttmp = rgb_data[3*ipos + k];\n\t\t\t\t\tnew_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);\n\t\t\t\t}\n\t\t\t\tipos++;\n\t\t\t}\n\t\t}\n\t}\n\n\tfree(rgb_data);\n\tfree(png_alpha);\n\trgb_data = new_rgb;\n\tpng_alpha = NULL;\n\n}\n\n/* Merge the image with a background, taking care of the\n * image Alpha transparency. (background alpha is ignored).\n * The images is merged on position (x, y) on the\n * background, the background must contain the image.\n */\n#define IMG_POS_RGB(p, x) (3 * p + x)\nvoid Image::Merge_non_crop(Image* background, const int x, const int y)\n{\n\tint bg_w = background->Width();\n\tint bg_h = background->Height();\n\n\tif (x + width > bg_w || y + height > bg_h)\n\t\treturn;\n\n\tdouble tmp;\n\tunsigned char *new_rgb = (unsigned char *)malloc(3 * bg_w * bg_h);\n\tconst unsigned char *bg_rgb = background->getRGBData();\n\tint pnl_pos = 0;\n\tint bg_pos = 0;\n\tint pnl_w_end = x + width;\n\tint pnl_h_end = y + height;\n\n\tmemcpy(new_rgb, bg_rgb, 3 * bg_w * bg_h);\n\n\tfor (int j = 0; j < bg_h; j++) {\n\t\tfor (int i = 0; i < bg_w; i++) {\n\t\t\tif (j >= y && i >= x && j < pnl_h_end && i < pnl_w_end ) {\n\t\t\t\tfor (int k = 0; k < 3; k++) {\n\t\t\t\t\tif (png_alpha != NULL)\n\t\t\t\t\t\ttmp = rgb_data[IMG_POS_RGB(pnl_pos, k)]\n\t\t\t\t\t\t\t* png_alpha[pnl_pos]/255.0\n\t\t\t\t\t\t\t+ bg_rgb[IMG_POS_RGB(bg_pos, k)]\n\t\t\t\t\t\t\t* (1 - png_alpha[pnl_pos]/255.0);\n\t\t\t\t\telse\n\t\t\t\t\t\ttmp = rgb_data[IMG_POS_RGB(pnl_pos, k)];\n\n\t\t\t\t\tnew_rgb[IMG_POS_RGB(bg_pos, k)] = static_cast<unsigned char>(tmp);\n\t\t\t\t}\n\t\t\t\tpnl_pos++;\n\t\t\t}\n\t\t\tbg_pos++;\n\t\t}\n\t}\n\n\twidth = bg_w;\n\theight = bg_h;\n\n\tfree(rgb_data);\n\tfree(png_alpha);\n\trgb_data = new_rgb;\n\tpng_alpha = NULL;\n}\n\n/* Tile the image growing its size to the minimum entire\n * multiple of w * h.\n * The new dimensions should be > of the current ones.\n * Note that this flattens image (alpha removed)\n */\nvoid Image::Tile(const int w, const int h) {\n\n\tif (w < width || h < height)\n\t\treturn;\n\n\tint nx = w / width;\n\tif (w % width > 0)\n\t\tnx++;\n\tint ny = h / height;\n\tif (h % height > 0)\n\t\tny++;\n\n\tint newwidth = nx*width;\n\tint newheight=ny*height;\n\n\tunsigned char *new_rgb = (unsigned char *) malloc(3 * newwidth * newheight);\n\tmemset(new_rgb, 0, 3 * width * height * nx * ny);\n\n\tint ipos = 0;\n\tint opos = 0;\n\n\tfor (int r = 0; r < ny; r++) {\n\t\tfor (int c = 0; c < nx; c++) {\n\t\t\tfor (int j = 0; j < height; j++) {\n\t\t\t\tfor (int i = 0; i < width; i++) {\n\t\t\t\t\topos = j*width + i;\n\t\t\t\t\tipos = r*width*height*nx + j*newwidth + c*width +i;\n\t\t\t\t\tfor (int k = 0; k < 3; k++) {\n\t\t\t\t\t\tnew_rgb[3*ipos + k] = static_cast<unsigned char> (rgb_data[3*opos + k]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfree(rgb_data);\n\tfree(png_alpha);\n\trgb_data = new_rgb;\n\tpng_alpha = NULL;\n\twidth = newwidth;\n\theight = newheight;\n\tarea = width * height;\n\tCrop(0,0,w,h);\n\n}\n\n/* Crop the image\n */\nvoid Image::Crop(const int x, const int y, const int w, const int h) {\n\n\tif (x+w > width || y+h > height) {\n\t\treturn;\n\t}\n\n\tint x2 = x + w;\n\tint y2 = y + h;\n\tunsigned char *new_rgb = (unsigned char *) malloc(3 * w * h);\n\tmemset(new_rgb, 0, 3 * w * h);\n\tunsigned char *new_alpha = NULL;\n\tif (png_alpha != NULL) {\n\t\tnew_alpha = (unsigned char *) malloc(w * h);\n\t\tmemset(new_alpha, 0, w * h);\n\t}\n\n\tint ipos = 0;\n\tint opos = 0;\n\n\tfor (int j = 0; j < height; j++) {\n\t\tfor (int i = 0; i < width; i++) {\n\t\t\tif (j>=y && i>=x && j<y2 && i<x2) {\n\t\t\t\tfor (int k = 0; k < 3; k++) {\n\t\t\t\t\tnew_rgb[3*ipos + k] = static_cast<unsigned char> (rgb_data[3*opos + k]);\n\t\t\t\t}\n\t\t\t\tif (png_alpha != NULL)\n\t\t\t\t\tnew_alpha[ipos] = static_cast<unsigned char> (png_alpha[opos]);\n\t\t\t\tipos++;\n\t\t\t}\n\t\t\topos++;\n\t\t}\n\t}\n\n\tfree(rgb_data);\n\tfree(png_alpha);\n\trgb_data = new_rgb;\n\tif (png_alpha != NULL)\n\t\tpng_alpha = new_alpha;\n\twidth = w;\n\theight = h;\n\tarea = w * h;\n\n\n}\n\n/* Center the image in a rectangle of given width and height.\n * Fills the remaining space (if any) with the hex color\n */\nvoid Image::Center(const int w, const int h, const char *hex) {\n\n\tunsigned long packed_rgb;\n\tsscanf(hex, \"%lx\", &packed_rgb);\n\n\tunsigned long r = packed_rgb>>16;\n\tunsigned long g = packed_rgb>>8 & 0xff;\n\tunsigned long b = packed_rgb & 0xff;\n\n\tunsigned char *new_rgb = (unsigned char *) malloc(3 * w * h);\n\tmemset(new_rgb, 0, 3 * w * h);\n\n\tint x = (w - width) / 2;\n\tint y = (h - height) / 2;\n\n\tif (x<0) {\n\t\tCrop((width - w)/2,0,w,height);\n\t\tx = 0;\n\t}\n\tif (y<0) {\n\t\tCrop(0,(height - h)/2,width,h);\n\t\ty = 0;\n\t}\n\tint x2 = x + width;\n\tint y2 = y + height;\n\n\tint ipos = 0;\n\tint opos = 0;\n\tdouble tmp;\n\n\tarea = w * h;\n\tfor (int i = 0; i < area; i++) {\n\t\tnew_rgb[3*i] = r;\n\t\tnew_rgb[3*i+1] = g;\n\t\tnew_rgb[3*i+2] = b;\n\t}\n\n\tif (png_alpha != NULL) {\n\t\tfor (int j = 0; j < h; j++) {\n\t\t\tfor (int i = 0; i < w; i++) {\n\t\t\t\tif (j>=y && i>=x && j<y2 && i<x2) {\n\t\t\t\t\tipos = j*w + i;\n\t\t\t\t\tfor (int k = 0; k < 3; k++) {\n\t\t\t\t\t\ttmp = rgb_data[3*opos + k]*png_alpha[opos]/255.0\n\t\t\t\t\t\t\t  + new_rgb[k]*(1-png_alpha[opos]/255.0);\n\t\t\t\t\t\tnew_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);\n\t\t\t\t\t}\n\t\t\t\t\topos++;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor (int j = 0; j < h; j++) {\n\t\t\tfor (int i = 0; i < w; i++) {\n\t\t\t\tif (j>=y && i>=x && j<y2 && i<x2) {\n\t\t\t\t\tipos = j*w + i;\n\t\t\t\t\tfor (int k = 0; k < 3; k++) {\n\t\t\t\t\t\ttmp = rgb_data[3*opos + k];\n\t\t\t\t\t\tnew_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);\n\t\t\t\t\t}\n\t\t\t\t\topos++;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t}\n\n\tfree(rgb_data);\n\tfree(png_alpha);\n\trgb_data = new_rgb;\n\tpng_alpha = NULL;\n\twidth = w;\n\theight = h;\n\n}\n\n/* Fill the image with the given color and adjust its dimensions\n * to passed values.\n */\nvoid Image::Plain(const int w, const int h, const char *hex) {\n\n\tunsigned long packed_rgb;\n\tsscanf(hex, \"%lx\", &packed_rgb);\n\n\tunsigned long r = packed_rgb>>16;\n\tunsigned long g = packed_rgb>>8 & 0xff;\n\tunsigned long b = packed_rgb & 0xff;\n\n\tunsigned char *new_rgb = (unsigned char *) malloc(3 * w * h);\n\tmemset(new_rgb, 0, 3 * w * h);\n\n\tarea = w * h;\n\tfor (int i = 0; i < area; i++) {\n\t\tnew_rgb[3*i] = r;\n\t\tnew_rgb[3*i+1] = g;\n\t\tnew_rgb[3*i+2] = b;\n\t}\n\n\tfree(rgb_data);\n\tfree(png_alpha);\n\trgb_data = new_rgb;\n\tpng_alpha = NULL;\n\twidth = w;\n\theight = h;\n}\n\nvoid\nImage::computeShift(unsigned long mask,\n\t\t\t\t\tunsigned char &left_shift,\n\t\t\t\t\tunsigned char &right_shift) {\n\tleft_shift = 0;\n\tright_shift = 8;\n\tif (mask != 0) {\n\t\twhile ((mask & 0x01) == 0) {\n\t\t\tleft_shift++;\n\t\t\tmask >>= 1;\n\t\t}\n\t\twhile ((mask & 0x01) == 1) {\n\t\t\tright_shift--;\n\t\t\tmask >>= 1;\n\t\t}\n\t}\n}\n\nPixmap\nImage::createPixmap(Display* dpy, int scr, Window win) {\n\tint i, j;   /* loop variables */\n\n\tconst int depth = DefaultDepth(dpy, scr);\n\tVisual *visual = DefaultVisual(dpy, scr);\n\tColormap colormap = DefaultColormap(dpy, scr);\n\n\tPixmap tmp = XCreatePixmap(dpy, win, width, height,\n\t\t\t\t\t\t\t   depth);\n\n\tchar *pixmap_data = NULL;\n\tswitch (depth) {\n\tcase 32:\n\tcase 24:\n\t\tpixmap_data = new char[4 * width * height];\n\t\tbreak;\n\tcase 16:\n\tcase 15:\n\t\tpixmap_data = new char[2 * width * height];\n\t\tbreak;\n\tcase 8:\n\t\tpixmap_data = new char[width * height];\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tXImage *ximage = XCreateImage(dpy, visual, depth, ZPixmap, 0,\n\t\t\t\t\t\t\t\t  pixmap_data, width, height,\n\t\t\t\t\t\t\t\t  8, 0);\n\n\tint entries;\n\tXVisualInfo v_template;\n\tv_template.visualid = XVisualIDFromVisual(visual);\n\tXVisualInfo *visual_info = XGetVisualInfo(dpy, VisualIDMask,\n\t\t\t\t\t\t\t   &v_template, &entries);\n\n\tunsigned long ipos = 0;\n\tswitch (visual_info->c_class) {\n\tcase PseudoColor: {\n\t\t\tXColor xc;\n\t\t\txc.flags = DoRed | DoGreen | DoBlue;\n\n\t\t\tint num_colors = 256;\n\t\t\tXColor *colors = new XColor[num_colors];\n\t\t\tfor (i = 0; i < num_colors; i++)\n\t\t\t\tcolors[i].pixel = (unsigned long) i;\n\t\t\tXQueryColors(dpy, colormap, colors, num_colors);\n\n\t\t\tint *closest_color = new int[num_colors];\n\n\t\t\tfor (i = 0; i < num_colors; i++) {\n\t\t\t\txc.red = (i & 0xe0) << 8;\t\t   /* highest 3 bits */\n\t\t\t\txc.green = (i & 0x1c) << 11;\t\t/* middle 3 bits */\n\t\t\t\txc.blue = (i & 0x03) << 14;\t\t /* lowest 2 bits */\n\n\t\t\t\t/* find the closest color in the colormap */\n\t\t\t\tdouble distance, distance_squared, min_distance = 0;\n\t\t\t\tfor (int ii = 0; ii < num_colors; ii++) {\n\t\t\t\t\tdistance = colors[ii].red - xc.red;\n\t\t\t\t\tdistance_squared = distance * distance;\n\t\t\t\t\tdistance = colors[ii].green - xc.green;\n\t\t\t\t\tdistance_squared += distance * distance;\n\t\t\t\t\tdistance = colors[ii].blue - xc.blue;\n\t\t\t\t\tdistance_squared += distance * distance;\n\n\t\t\t\t\tif ((ii == 0) || (distance_squared <= min_distance)) {\n\t\t\t\t\t\tmin_distance = distance_squared;\n\t\t\t\t\t\tclosest_color[i] = ii;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (j = 0; j < height; j++) {\n\t\t\t\tfor (i = 0; i < width; i++) {\n\t\t\t\t\txc.red = (unsigned short) (rgb_data[ipos++] & 0xe0);\n\t\t\t\t\txc.green = (unsigned short) (rgb_data[ipos++] & 0xe0);\n\t\t\t\t\txc.blue = (unsigned short) (rgb_data[ipos++] & 0xc0);\n\n\t\t\t\t\txc.pixel = xc.red | (xc.green >> 3) | (xc.blue >> 6);\n\t\t\t\t\tXPutPixel(ximage, i, j,\n\t\t\t\t\t\t\t  colors[closest_color[xc.pixel]].pixel);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdelete [] colors;\n\t\t\tdelete [] closest_color;\n\t\t}\n\t\tbreak;\n\tcase TrueColor: {\n\t\t\tunsigned char red_left_shift;\n\t\t\tunsigned char red_right_shift;\n\t\t\tunsigned char green_left_shift;\n\t\t\tunsigned char green_right_shift;\n\t\t\tunsigned char blue_left_shift;\n\t\t\tunsigned char blue_right_shift;\n\n\t\t\tcomputeShift(visual_info->red_mask, red_left_shift,\n\t\t\t\t\t\t red_right_shift);\n\t\t\tcomputeShift(visual_info->green_mask, green_left_shift,\n\t\t\t\t\t\t green_right_shift);\n\t\t\tcomputeShift(visual_info->blue_mask, blue_left_shift,\n\t\t\t\t\t\t blue_right_shift);\n\n\t\t\tunsigned long pixel;\n\t\t\tunsigned long red, green, blue;\n\t\t\tfor (j = 0; j < height; j++) {\n\t\t\t\tfor (i = 0; i < width; i++) {\n\t\t\t\t\tred = (unsigned long)\n\t\t\t\t\t\t  rgb_data[ipos++] >> red_right_shift;\n\t\t\t\t\tgreen = (unsigned long)\n\t\t\t\t\t\t\trgb_data[ipos++] >> green_right_shift;\n\t\t\t\t\tblue = (unsigned long)\n\t\t\t\t\t\t   rgb_data[ipos++] >> blue_right_shift;\n\n\t\t\t\t\tpixel = (((red << red_left_shift) & visual_info->red_mask)\n\t\t\t\t\t\t\t | ((green << green_left_shift)\n\t\t\t\t\t\t\t\t& visual_info->green_mask)\n\t\t\t\t\t\t\t | ((blue << blue_left_shift)\n\t\t\t\t\t\t\t\t& visual_info->blue_mask));\n\n\t\t\t\t\tXPutPixel(ximage, i, j, pixel);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tdefault: {\n\t\t\tlogStream << \"Login.app: could not load image\" << endl;\n\t\t\treturn(tmp);\n\t\t}\n\t}\n\n\tGC gc = XCreateGC(dpy, win, 0, NULL);\n\tXPutImage(dpy, tmp, gc, ximage, 0, 0, 0, 0, width, height);\n\n\tXFreeGC(dpy, gc);\n\n\tXFree(visual_info);\n\n\tdelete [] pixmap_data;\n\n\t/* Set ximage data to NULL since pixmap data was deallocated above */\n\tximage->data = NULL;\n\tXDestroyImage(ximage);\n\n\treturn(tmp);\n}\n\nint\nImage::readJpeg(const char *filename, int *width, int *height,\n\t\t\t\tunsigned char **rgb)\n{\n\tint ret = 0;\n\tstruct jpeg_decompress_struct cinfo;\n\tstruct jpeg_error_mgr jerr;\n\tunsigned char *ptr = NULL;\n\n\tFILE *infile = fopen(filename, \"rb\");\n\tif (infile == NULL) {\n\t\tlogStream << APPNAME << \"Cannot fopen file: \" << filename << endl;\n\t\treturn ret;\n\t}\n\n\tcinfo.err = jpeg_std_error(&jerr);\n\tjpeg_create_decompress(&cinfo);\n\tjpeg_stdio_src(&cinfo, infile);\n\tjpeg_read_header(&cinfo, TRUE);\n\tjpeg_start_decompress(&cinfo);\n\n\t/* Prevent against integer overflow */\n\tif(cinfo.output_width >= MAX_DIMENSION\n\t   || cinfo.output_height >= MAX_DIMENSION)\n\t{\n\t\tlogStream << APPNAME << \"Unreasonable dimension found in file: \"\n\t\t\t\t  << filename << endl;\n\t\tgoto close_file;\n\t}\n\n\t*width = cinfo.output_width;\n\t*height = cinfo.output_height;\n\n\trgb[0] = (unsigned char*)\n\t\t\t\tmalloc(3 * cinfo.output_width * cinfo.output_height);\n\tif (rgb[0] == NULL) {\n\t\tlogStream << APPNAME << \": Can't allocate memory for JPEG file.\"\n\t\t\t\t  << endl;\n\t\tgoto close_file;\n\t}\n\n\tif (cinfo.output_components == 3) {\n\t\tptr = rgb[0];\n\t\twhile (cinfo.output_scanline < cinfo.output_height) {\n\t\t\tjpeg_read_scanlines(&cinfo, &ptr, 1);\n\t\t\tptr += 3 * cinfo.output_width;\n\t\t}\n\t} else if (cinfo.output_components == 1) {\n\t\tptr = (unsigned char*) malloc(cinfo.output_width);\n\t\tif (ptr == NULL) {\n\t\t\tlogStream << APPNAME << \": Can't allocate memory for JPEG file.\"\n\t\t\t\t\t  << endl;\n\t\t\tgoto rgb_free;\n\t\t}\n\n\t\tunsigned int ipos = 0;\n\t\twhile (cinfo.output_scanline < cinfo.output_height) {\n\t\t\tjpeg_read_scanlines(&cinfo, &ptr, 1);\n\n\t\t\tfor (unsigned int i = 0; i < cinfo.output_width; i++) {\n\t\t\t\tmemset(rgb[0] + ipos, ptr[i], 3);\n\t\t\t\tipos += 3;\n\t\t\t}\n\t\t}\n\n\t\tfree(ptr);\n\t}\n\n\tjpeg_finish_decompress(&cinfo);\n\n\tret = 1;\n\tgoto close_file;\n\nrgb_free:\n\tfree(rgb[0]);\n\nclose_file:\n\tjpeg_destroy_decompress(&cinfo);\n\tfclose(infile);\n\n\treturn(ret);\n}\n\nint\nImage::readPng(const char *filename, int *width, int *height,\n\t\t\t   unsigned char **rgb, unsigned char **alpha)\n{\n\tint ret = 0;\n\n\tpng_structp png_ptr;\n\tpng_infop info_ptr;\n\tpng_bytepp row_pointers;\n\n\tunsigned char *ptr = NULL;\n\tpng_uint_32 w, h;\n\tint bit_depth, color_type, interlace_type;\n\tint i;\n\n\tFILE *infile = fopen(filename, \"rb\");\n\tif (infile == NULL) {\n\t\tlogStream << APPNAME << \"Can not fopen file: \" << filename << endl;\n\t\treturn ret;\n\t}\n\n\tpng_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,\n\t\t\t\t\t\t\t\t\t (png_voidp) NULL,\n\t\t\t\t\t\t\t\t\t (png_error_ptr) NULL,\n\t\t\t\t\t\t\t\t\t (png_error_ptr) NULL);\n\tif (!png_ptr) {\n\t\tgoto file_close;\n\t}\n\n\tinfo_ptr = png_create_info_struct(png_ptr);\n\tif (!info_ptr) {\n\t\tpng_destroy_read_struct(&png_ptr, (png_infopp) NULL,\n\t\t\t\t\t\t\t\t(png_infopp) NULL);\n\t}\n\n#if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 4\n\t\tif (setjmp(png_jmpbuf((png_ptr)))) {\n#else\n\tif (setjmp(png_ptr->jmpbuf)) {\n#endif\n\t\tgoto png_destroy;\n\t}\n\n\tpng_init_io(png_ptr, infile);\n\tpng_read_info(png_ptr, info_ptr);\n\n\tpng_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type,\n\t\t\t\t &interlace_type, (int *) NULL, (int *) NULL);\n\n\t/* Prevent against integer overflow */\n\tif(w >= MAX_DIMENSION || h >= MAX_DIMENSION) {\n\t\tlogStream << APPNAME << \"Unreasonable dimension found in file: \"\n\t\t\t\t  << filename << endl;\n\t\tgoto png_destroy;\n\t}\n\n\t*width = (int) w;\n\t*height = (int) h;\n\n\tif (color_type == PNG_COLOR_TYPE_RGB_ALPHA\n\t\t|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n\t{\n\t\talpha[0] = (unsigned char *) malloc(*width * *height);\n\t\tif (alpha[0] == NULL) {\n\t\t\tlogStream << APPNAME\n\t\t\t\t\t<< \": Can't allocate memory for alpha channel in PNG file.\"\n\t\t\t\t\t<< endl;\n\t\t\tgoto png_destroy;\n\t\t}\n\t}\n\n\t/* Change a paletted/grayscale image to RGB */\n\tif (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)\n\t{\n\t\tpng_set_expand(png_ptr);\n\t}\n\n\t/* Change a grayscale image to RGB */\n\tif (color_type == PNG_COLOR_TYPE_GRAY\n\t\t|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n\t{\n\t\tpng_set_gray_to_rgb(png_ptr);\n\t}\n\n\t/* If the PNG file has 16 bits per channel, strip them down to 8 */\n\tif (bit_depth == 16) {\n\t  png_set_strip_16(png_ptr);\n\t}\n\n\t/* use 1 byte per pixel */\n\tpng_set_packing(png_ptr);\n\n\trow_pointers = (png_byte **) malloc(*height * sizeof(png_bytep));\n\tif (row_pointers == NULL) {\n\t\tlogStream << APPNAME << \": Can't allocate memory for PNG file.\" << endl;\n\t\tgoto png_destroy;\n\t}\n\n\tfor (i = 0; i < *height; i++) {\n\t\trow_pointers[i] = (png_byte*) malloc(4 * *width);\n\t\tif (row_pointers == NULL) {\n\t\t\tlogStream << APPNAME << \": Can't allocate memory for PNG file.\"\n\t\t\t\t\t  << endl;\n\t\t\tgoto rows_free;\n\t\t}\n\t}\n\n\tpng_read_image(png_ptr, row_pointers);\n\n\trgb[0] = (unsigned char *) malloc(3 * (*width) * (*height));\n\tif (rgb[0] == NULL) {\n\t\tlogStream << APPNAME << \": Can't allocate memory for PNG file.\" << endl;\n\t\tgoto rows_free;\n\t}\n\n\tif (alpha[0] == NULL) {\n\t\tptr = rgb[0];\n\t\tfor (i = 0; i < *height; i++) {\n\t\t\tmemcpy(ptr, row_pointers[i], 3 * (*width));\n\t\t\tptr += 3 * (*width);\n\t\t}\n\t} else {\n\t\tptr = rgb[0];\n\t\tfor (i = 0; i < *height; i++) {\n\t\t\tunsigned int ipos = 0;\n\t\t\tfor (int j = 0; j < *width; j++) {\n\t\t\t\t*ptr++ = row_pointers[i][ipos++];\n\t\t\t\t*ptr++ = row_pointers[i][ipos++];\n\t\t\t\t*ptr++ = row_pointers[i][ipos++];\n\t\t\t\talpha[0][i * (*width) + j] = row_pointers[i][ipos++];\n\t\t\t}\n\t\t}\n\t}\n\n\tret = 1; /* data reading is OK */\n\nrows_free:\n\tfor (i = 0; i < *height; i++) {\n\t\tif (row_pointers[i] != NULL ) {\n\t\t\tfree(row_pointers[i]);\n\t\t}\n\t}\n\n\tfree(row_pointers);\n\npng_destroy:\n\tpng_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);\n\nfile_close:\n\tfclose(infile);\n\treturn(ret);\n}\n\n"
  },
  {
    "path": "image.h",
    "content": "/* SLiM - Simple Login Manager\n\t Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n\t Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n\t Copyright (C) 2012\tNobuhiro Iwamatsu <iwamatsu@nigauri.org>\n\n\t This program is free software; you can redistribute it and/or modify\n\t it under the terms of the GNU General Public License as published by\n\t the Free Software Foundation; either version 2 of the License, or\n\t (at your option) any later version.\n\n\t The following code has been adapted and extended from\n\t xplanet 1.0.1, Copyright (C) 2002-04 Hari Nair <hari@alumni.caltech.edu>\n*/\n\n#ifndef _IMAGE_H_\n#define _IMAGE_H_\n\n#include <X11/Xlib.h>\n#include <X11/Xmu/WinUtil.h>\n#include \"log.h\"\n\nclass Image {\npublic:\n\tImage();\n\tImage(const int w, const int h, const unsigned char *rgb,\n\t\t\tconst unsigned char *alpha);\n\n\t~Image();\n\n\tconst unsigned char *getPNGAlpha() const {\n\t\treturn(png_alpha);\n\t};\n\tconst unsigned char *getRGBData() const {\n\t\treturn(rgb_data);\n\t};\n\n\tvoid getPixel(double px, double py, unsigned char *pixel);\n\tvoid getPixel(double px, double py, unsigned char *pixel,\n\t\t\t\t\tunsigned char *alpha);\n\n\tint Width() const {\n\t\treturn(width);\n\t};\n\tint Height() const {\n\t\treturn(height);\n\t};\n\tvoid Quality(const int q) {\n\t\tquality_ = q;\n\t};\n\n\tbool Read(const char *filename);\n\n\tvoid Reduce(const int factor);\n\tvoid Resize(const int w, const int h);\n\tvoid Merge(Image *background, const int x, const int y);\n\tvoid Merge_non_crop(Image* background, const int x, const int y);\n\tvoid Crop(const int x, const int y, const int w, const int h);\n\tvoid Tile(const int w, const int h);\n\tvoid Center(const int w, const int h, const char *hex);\n\tvoid Plain(const int w, const int h, const char *hex);\n\n\tvoid computeShift(unsigned long mask, unsigned char &left_shift,\n\t\t\t\tunsigned char &right_shift);\n\n\tPixmap createPixmap(Display *dpy, int scr, Window win);\n\nprivate:\n\tint width, height, area;\n\tunsigned char *rgb_data;\n\tunsigned char *png_alpha;\n\n\tint quality_;\n\n\tint readJpeg(const char *filename, int *width, int *height,\n\t\tunsigned char **rgb);\n\tint readPng(const char *filename, int *width, int *height,\n\t\tunsigned char **rgb, unsigned char **alpha);\n};\n\n#endif /* _IMAGE_H_ */\n"
  },
  {
    "path": "jpeg.c",
    "content": "/****************************************************************************\n\tjpeg.c - read and write jpeg images using libjpeg routines\n\tCopyright (C) 2002 Hari Nair <hari@alumni.caltech.edu>\n\n\tThis program is free software; you can redistribute it and/or modify\n\tit under the terms of the GNU General Public License as published by\n\tthe Free Software Foundation; either version 2 of the License, or\n\t(at your option) any later version.\n\n\tThis program is distributed in the hope that it will be useful,\n\tbut WITHOUT ANY WARRANTY; without even the implied warranty of\n\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\tGNU General Public License for more details.\n\n\tYou should have received a copy of the GNU General Public License\n\talong with this program; if not, write to the Free Software\n\tFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n****************************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <jpeglib.h>\n#include \"const.h\"\n\nint\nread_jpeg(const char *filename, int *width, int *height, unsigned char **rgb)\n{\n\tint ret = 0;\n\tstruct jpeg_decompress_struct cinfo;\n\tstruct jpeg_error_mgr jerr;\n\tunsigned char *ptr = NULL;\n\tunsigned int i, ipos;\n\n\tFILE *infile = fopen(filename, \"rb\");\n\tif (infile == NULL) {\n\t\tfprintf(stderr, \"Can not fopen file: %s\\n\",filename);\n\t\treturn ret;\n\t}\n\n\tcinfo.err = jpeg_std_error(&jerr);\n\tjpeg_create_decompress(&cinfo);\n\tjpeg_stdio_src(&cinfo, infile);\n\tjpeg_read_header(&cinfo, TRUE);\n\tjpeg_start_decompress(&cinfo);\n\n\t/* Prevent against integer overflow */\n\tif(cinfo.output_width >= MAX_DIMENSION || cinfo.output_height >= MAX_DIMENSION) {\n\t\tfprintf(stderr, \"Unreasonable dimension found in file: %s\\n\",filename);\n\t\tgoto close_file;\n\t}\n\n\t*width = cinfo.output_width;\n\t*height = cinfo.output_height;\n\n\trgb[0] = malloc(3 * cinfo.output_width * cinfo.output_height);\n\tif (rgb[0] == NULL) {\n\t\tfprintf(stderr, \"Can't allocate memory for JPEG file.\\n\");\n\t\tgoto close_file;\n\t}\n\n\tif (cinfo.output_components == 3) {\n\t\tptr = rgb[0];\n\t\twhile (cinfo.output_scanline < cinfo.output_height) {\n\t\t\tjpeg_read_scanlines(&cinfo, &ptr, 1);\n\t\t\tptr += 3 * cinfo.output_width;\n\t\t}\n\t} else if (cinfo.output_components == 1) {\n\t\tptr = malloc(cinfo.output_width);\n\t\tif (ptr == NULL) {\n\t\t\tfprintf(stderr, \"Can't allocate memory for JPEG file.\\n\");\n\t\t\tgoto rgb_free;\n\t\t}\n\n\t\tipos = 0;\n\t\twhile (cinfo.output_scanline < cinfo.output_height) {\n\t\t\tjpeg_read_scanlines(&cinfo, &ptr, 1);\n\n\t\t\tfor (i = 0; i < cinfo.output_width; i++) {\n\t\t\t\tmemset(rgb[0] + ipos, ptr[i], 3);\n\t\t\t\tipos += 3;\n\t\t\t}\n\t\t}\n\n\t\tfree(ptr);\n\t}\n\n\tjpeg_finish_decompress(&cinfo);\n\n\tret = 1;\n\tgoto close_file;\n\nrgb_free:\n\tfree(rgb[0]);\n\nclose_file:\n\tjpeg_destroy_decompress(&cinfo);\n\tfclose(infile);\n\n\treturn(ret);\n}\n"
  },
  {
    "path": "log.cpp",
    "content": "#include \"log.h\"\n#include <iostream>\n\nbool\nLogUnit::openLog(const char * filename)\n{\n\tif (logFile.is_open()) {\n\t\tcerr << APPNAME\n\t\t\t<< \": opening a new Log file, while another is already open\"\n\t\t\t<< endl;\n\t\tlogFile.close();\n\t}\n\tlogFile.open(filename, ios_base::app);\n\n\treturn !(logFile.fail());\n}\n\nvoid\nLogUnit::closeLog()\n{\n\tif (logFile.is_open())\n\t\tlogFile.close();\n}\n"
  },
  {
    "path": "log.h",
    "content": "#ifndef _LOG_H_\n#define _LOG_H_\n\n#ifdef USE_CONSOLEKIT\n#include \"Ck.h\" \n#endif\n#ifdef USE_PAM\n#include \"PAM.h\"\n#endif\n#include \"const.h\"\n#include <fstream>\n\nusing namespace std;\n\nstatic class LogUnit {\n\tofstream logFile;\npublic:\n\tbool openLog(const char * filename);\n\tvoid closeLog();\n\n\t~LogUnit() { closeLog(); }\n\n\ttemplate<typename Type>\n\tLogUnit & operator<<(const Type & text) {\n\t\tlogFile << text; logFile.flush();\n\t\treturn *this;\n\t}\n\n\tLogUnit & operator<<(ostream & (*fp)(ostream&)) {\n\t\tlogFile << fp; logFile.flush();\n\t\treturn *this;\n\t}\n\n\tLogUnit & operator<<(ios_base & (*fp)(ios_base&)) {\n\t\tlogFile << fp; logFile.flush();\n\t\treturn *this;\n\t}\n} logStream;\n\n#endif /* _LOG_H_ */\n"
  },
  {
    "path": "main.cpp",
    "content": "/* SLiM - Simple Login Manager\n\tCopyright (C) 1997, 1998 Per Liden\n\tCopyright (C) 2004-06 Simone Rota <sip@varlock.com>\n\tCopyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n\n\tThis program is free software; you can redistribute it and/or modify\n\tit under the terms of the GNU General Public License as published by\n\tthe Free Software Foundation; either version 2 of the License, or\n\t(at your option) any later version.\n*/\n\n#include \"app.h\"\n#include \"const.h\"\n\nApp* LoginApp = 0;\n\nint main(int argc, char** argv)\n{\n\tLoginApp = new App(argc, argv);\n\tLoginApp->Run();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "numlock.cpp",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n   Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n   Copyright (C) 2012\tNobuhiro Iwamatsu <iwamatsu@nigauri.org>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n\n   Code adapted from NumLockX, look at the end of this file for\n   the original Copyright information.\n\n*/\n\n#include \"numlock.h\"\n#include <string.h>\n\nNumLock::NumLock() {\n}\n\nint NumLock::xkb_init(Display* dpy) {\n\tint xkb_opcode, xkb_event, xkb_error;\n\tint xkb_lmaj = XkbMajorVersion;\n\tint xkb_lmin = XkbMinorVersion;\n\n\treturn XkbLibraryVersion( &xkb_lmaj, &xkb_lmin )\n\t\t&& XkbQueryExtension( dpy, &xkb_opcode, &xkb_event, &xkb_error,\n\t\t\t\t   &xkb_lmaj, &xkb_lmin );\n}\n\nunsigned int NumLock::xkb_mask_modifier( XkbDescPtr xkb, const char *name ) {\n\tint i;\n\tif( !xkb || !xkb->names )\n\t\treturn 0;\n\n\tfor( i = 0; i < XkbNumVirtualMods; i++ ) {\n\t\tchar* modStr = XGetAtomName( xkb->dpy, xkb->names->vmods[i] );\n\t\tif( modStr != NULL && strcmp(name, modStr) == 0 ) {\n\t\t\tunsigned int mask;\n\t\t\tXkbVirtualModsToReal( xkb, 1 << i, &mask );\n\t\t\treturn mask;\n\t\t}\n\t}\n\treturn 0;\n}\n\nunsigned int NumLock::xkb_numlock_mask(Display* dpy) {\n\tXkbDescPtr xkb;\n\n\txkb = XkbGetKeyboard( dpy, XkbAllComponentsMask, XkbUseCoreKbd );\n\tif( xkb != NULL ) {\n\t\tunsigned int mask = xkb_mask_modifier( xkb, \"NumLock\" );\n\t\tXkbFreeKeyboard( xkb, 0, True );\n\t\treturn mask;\n\t}\n\treturn 0;\n}\n\nvoid NumLock::control_numlock(Display *dpy, bool flag) {\n\tunsigned int mask;\n\n\tif( !xkb_init(dpy) )\n\t\treturn;\n\n\tmask = xkb_numlock_mask(dpy);\n\tif( mask == 0 )\n\t\treturn;\n\n\tif( flag == true )\n\t\tXkbLockModifiers ( dpy, XkbUseCoreKbd, mask, mask);\n\telse\n\t\tXkbLockModifiers ( dpy, XkbUseCoreKbd, mask, 0);\n}\n\nvoid NumLock::setOn(Display *dpy) {\n\tcontrol_numlock(dpy, true);\n}\n\nvoid NumLock::setOff(Display *dpy) {\n\tcontrol_numlock(dpy, false);\n}\n\n/*\n Copyright (C) 2000-2001 Lubos Lunak\t\t<l.lunak@kde.org>\n Copyright (C) 2001\t  Oswald Buddenhagen <ossi@kde.org>\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\nTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n\n*/\n"
  },
  {
    "path": "numlock.h",
    "content": "/* SLiM - Simple Login Manager\n\tCopyright (C) 2004-06 Simone Rota <sip@varlock.com>\n\tCopyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n\tCopyright (C) 2012\t\tNobuhiro Iwamatsu <iwamatsu@nigauri.org>\n\n\tThis program is free software; you can redistribute it and/or modify\n\tit under the terms of the GNU General Public License as published by\n\tthe Free Software Foundation; either version 2 of the License, or\n\t(at your option) any later version.\n*/\n\n#ifndef _NUMLOCK_H_\n#define _NUMLOCK_H_\n\n#include <X11/Xlib.h>\n#include <X11/XKBlib.h>\n#include <X11/keysym.h>\n\nclass NumLock {\n\npublic:\n\tNumLock();\n\tstatic void setOn(Display *dpy);\n\tstatic void setOff(Display *dpy);\n\nprivate:\n\tstatic int xkb_init(Display *dpy);\n\tstatic unsigned int xkb_mask_modifier(XkbDescPtr xkb, const char *name);\n\tstatic unsigned int xkb_numlock_mask(Display *dpy);\n\tstatic void control_numlock(Display *dpy, bool flag);\n};\n\n#endif /* _NUMLOCK_H_ */\n"
  },
  {
    "path": "pam.sample",
    "content": "#%PAM-1.0\nauth            requisite       pam_nologin.so\nauth            required        pam_env.so\nauth            required        pam_unix.so\naccount         required        pam_unix.so\npassword        required        pam_unix.so\nsession         required        pam_limits.so\nsession         required        pam_unix.so\nsession         optional        pam_loginuid.so\nsession         optional        pam_ck_connector.so\n"
  },
  {
    "path": "panel.cpp",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 1997, 1998 Per Liden\n   Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n   Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n*/\n\n#include <sstream>\n#include <poll.h>\n#include <X11/extensions/Xrandr.h>\n#include \"panel.h\"\n\nusing namespace std;\n\nPanel::Panel(Display* dpy, int scr, Window root, Cfg* config,\n\t\t\t const string& themedir, PanelType panel_mode) {\n\t/* Set display */\n\tDpy = dpy;\n\tScr = scr;\n\tRoot = root;\n\tcfg = config;\n\tmode = panel_mode;\n\n\tsession_name = \"\";\n    session_exec = \"\";\n\tif (mode == Mode_Lock) {\n\t\tWin = root;\n\t\tviewport = GetPrimaryViewport();\n\t}\n\n\t/* Init GC */\n\tXGCValues gcv;\n\tunsigned long gcm;\n\tgcm = GCForeground|GCBackground|GCGraphicsExposures;\n\tgcv.foreground = GetColor(\"black\");\n\tgcv.background = GetColor(\"white\");\n\tgcv.graphics_exposures = False;\n\tif (mode == Mode_Lock)\n\t\tTextGC = XCreateGC(Dpy, Win, gcm, &gcv);\n\telse\n\t\tTextGC = XCreateGC(Dpy, Root, gcm, &gcv);\n\n\tif (mode == Mode_Lock) {\n\t\tgcm = GCGraphicsExposures;\n\t\tgcv.graphics_exposures = False;\n\t\tWinGC = XCreateGC(Dpy, Win, gcm, &gcv);\n\t\tif (WinGC < 0) {\n\t\t\tcerr << APPNAME\n\t\t\t\t<< \": failed to create pixmap\\n.\";\n\t\t\texit(ERR_EXIT);\n\t\t}\n\t}\n\n\tfont = XftFontOpenName(Dpy, Scr, cfg->getOption(\"input_font\").c_str());\n\twelcomefont = XftFontOpenName(Dpy, Scr, cfg->getOption(\"welcome_font\").c_str());\n\tintrofont = XftFontOpenName(Dpy, Scr, cfg->getOption(\"intro_font\").c_str());\n\tenterfont = XftFontOpenName(Dpy, Scr, cfg->getOption(\"username_font\").c_str());\n\tmsgfont = XftFontOpenName(Dpy, Scr, cfg->getOption(\"msg_font\").c_str());\n\n\tVisual* visual = DefaultVisual(Dpy, Scr);\n\tColormap colormap = DefaultColormap(Dpy, Scr);\n\t/* NOTE: using XftColorAllocValue() would be a better solution. Lazy me. */\n\tXftColorAllocName(Dpy, visual, colormap, cfg->getOption(\"input_color\").c_str(), &inputcolor);\n\tXftColorAllocName(Dpy, visual, colormap, cfg->getOption(\"input_shadow_color\").c_str(), &inputshadowcolor);\n\tXftColorAllocName(Dpy, visual, colormap, cfg->getOption(\"welcome_color\").c_str(), &welcomecolor);\n\tXftColorAllocName(Dpy, visual, colormap, cfg->getOption(\"welcome_shadow_color\").c_str(), &welcomeshadowcolor);\n\tXftColorAllocName(Dpy, visual, colormap, cfg->getOption(\"username_color\").c_str(), &entercolor);\n\tXftColorAllocName(Dpy, visual, colormap, cfg->getOption(\"username_shadow_color\").c_str(), &entershadowcolor);\n\tXftColorAllocName(Dpy, visual, colormap, cfg->getOption(\"msg_color\").c_str(), &msgcolor);\n\tXftColorAllocName(Dpy, visual, colormap, cfg->getOption(\"msg_shadow_color\").c_str(), &msgshadowcolor);\n\tXftColorAllocName(Dpy, visual, colormap, cfg->getOption(\"intro_color\").c_str(), &introcolor);\n\tXftColorAllocName(Dpy, visual, colormap,\n\t\t\t\t\t  cfg->getOption(\"session_color\").c_str(), &sessioncolor);\n\tXftColorAllocName(Dpy, visual, colormap,\n\t\t\t\t\t  cfg->getOption(\"session_shadow_color\").c_str(), &sessionshadowcolor);\n\n\t/* Load properties from config / theme */\n\tinput_name_x = cfg->getIntOption(\"input_name_x\");\n\tinput_name_y = cfg->getIntOption(\"input_name_y\");\n\tinput_pass_x = cfg->getIntOption(\"input_pass_x\");\n\tinput_pass_y = cfg->getIntOption(\"input_pass_y\");\n\tinputShadowXOffset = cfg->getIntOption(\"input_shadow_xoffset\");\n\tinputShadowYOffset = cfg->getIntOption(\"input_shadow_yoffset\");\n\n\tif (input_pass_x < 0 || input_pass_y < 0){ /* single inputbox mode */\n\t\tinput_pass_x = input_name_x;\n\t\tinput_pass_y = input_name_y;\n\t}\n\n\t/* Load panel and background image */\n\tstring panelpng = \"\";\n\tpanelpng = panelpng + themedir +\"/panel.png\";\n\timage = new Image;\n\tbool loaded = image->Read(panelpng.c_str());\n\tif (!loaded) { /* try jpeg if png failed */\n\t\tpanelpng = themedir + \"/panel.jpg\";\n\t\tloaded = image->Read(panelpng.c_str());\n\t\tif (!loaded) {\n\t\t\tlogStream << APPNAME\n\t\t\t\t << \": could not load panel image for theme '\"\n\t\t\t\t << basename((char*)themedir.c_str()) << \"'\"\n\t\t\t\t << endl;\n\t\t\texit(ERR_EXIT);\n\t\t}\n\t}\n\n\tImage* bg = new Image();\n\tstring bgstyle = cfg->getOption(\"background_style\");\n\tif (bgstyle != \"color\") {\n\t\tpanelpng = themedir +\"/background.png\";\n\t\tloaded = bg->Read(panelpng.c_str());\n\t\tif (!loaded) { /* try jpeg if png failed */\n\t\t\tpanelpng = themedir + \"/background.jpg\";\n\t\t\tloaded = bg->Read(panelpng.c_str());\n\t\t\tif (!loaded){\n\t\t\t\tlogStream << APPNAME\n\t\t\t\t\t << \": could not load background image for theme '\"\n\t\t\t\t\t << basename((char*)themedir.c_str()) << \"'\"\n\t\t\t\t\t << endl;\n\t\t\t\texit(ERR_EXIT);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (mode == Mode_Lock) {\n\t\tif (bgstyle == \"stretch\")\n\t\t\tbg->Resize(viewport.width, viewport.height);\n\t\t\t//bg->Resize(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t//\t\t\tXHeightOfScreen(ScreenOfDisplay(Dpy, Scr)));\n\t\telse if (bgstyle == \"tile\")\n\t\t\tbg->Tile(viewport.width, viewport.height);\n\t\telse if (bgstyle == \"center\") {\n\t\t\tstring hexvalue = cfg->getOption(\"background_color\");\n\t\t\thexvalue = hexvalue.substr(1,6);\n\t\t\tbg->Center(viewport.width,\n\t\t\t\tviewport.height,\n\t\t\t\thexvalue.c_str());\n\t\t} else { // plain color or error\n\t\t\tstring hexvalue = cfg->getOption(\"background_color\");\n\t\t\thexvalue = hexvalue.substr(1,6);\n\t\t\tbg->Center(viewport.width,\n\t\t\t\tviewport.height,\n\t\t\t\thexvalue.c_str());\n\t\t}\n\t} else {\n\t\tif (bgstyle == \"stretch\") {\n\t\t\tbg->Resize(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t\t\tXHeightOfScreen(ScreenOfDisplay(Dpy, Scr)));\n\t\t} else if (bgstyle == \"tile\") {\n\t\t\tbg->Tile(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t\t\tXHeightOfScreen(ScreenOfDisplay(Dpy, Scr)));\n\t\t} else if (bgstyle == \"center\") {\n\t\t\tstring hexvalue = cfg->getOption(\"background_color\");\n\t\t\thexvalue = hexvalue.substr(1,6);\n\t\t\tbg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t\tXHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t\thexvalue.c_str());\n\t\t} else { /* plain color or error */\n\t\t\tstring hexvalue = cfg->getOption(\"background_color\");\n\t\t\thexvalue = hexvalue.substr(1,6);\n\t\t\tbg->Center(XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t   XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)),\n\t\t\t\t   hexvalue.c_str());\n\t\t}\n\t}\n\n\tstring cfgX = cfg->getOption(\"input_panel_x\");\n\tstring cfgY = cfg->getOption(\"input_panel_y\");\n\n\tif (mode == Mode_Lock) {\n\t\tX = Cfg::absolutepos(cfgX, viewport.width, image->Width());\n\t\tY = Cfg::absolutepos(cfgY, viewport.height, image->Height());\n\n\t\tinput_name_x += X;\n\t\tinput_name_y += Y;\n\t\tinput_pass_x += X;\n\t\tinput_pass_y += Y;\n\t} else {\n\t\tX = Cfg::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), image->Width());\n\t\tY = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), image->Height());\n\t}\n\n\tif (mode == Mode_Lock) {\n\t\t/* Merge image into background without crop */\n\t\timage->Merge_non_crop(bg, X, Y);\n\t\tPanelPixmap = image->createPixmap(Dpy, Scr, Win);\n\t} else {\n\t\t/* Merge image into background */\n\t\timage->Merge(bg, X, Y);\n\t\tPanelPixmap = image->createPixmap(Dpy, Scr, Root);\n\t}\n\tdelete bg;\n\n\t/* Read (and substitute vars in) the welcome message */\n\twelcome_message = cfg->getWelcomeMessage();\n\tintro_message = cfg->getOption(\"intro_msg\");\n\n\tif (mode == Mode_Lock) {\n\t\tSetName(getenv(\"USER\"));\n\t\tfield = Get_Passwd;\n\t\tOnExpose();\n\t}\n}\n\nPanel::~Panel() {\n\tVisual* visual = DefaultVisual(Dpy, Scr);\n\tColormap colormap = DefaultColormap(Dpy, Scr);\n\n\tXftColorFree(Dpy, visual, colormap, &inputcolor);\n\tXftColorFree(Dpy, visual, colormap, &inputshadowcolor);\n\tXftColorFree(Dpy, visual, colormap, &welcomecolor);\n\tXftColorFree(Dpy, visual, colormap, &welcomeshadowcolor);\n\tXftColorFree(Dpy, visual, colormap, &entercolor);\n\tXftColorFree(Dpy, visual, colormap, &entershadowcolor);\n\tXftColorFree(Dpy, visual, colormap, &msgcolor);\n\tXftColorFree(Dpy, visual, colormap, &msgshadowcolor);\n\tXftColorFree(Dpy, visual, colormap, &introcolor);\n\tXftColorFree(Dpy, visual, colormap, &sessioncolor);\n\tXftColorFree(Dpy, visual, colormap, &sessionshadowcolor);\n\n\tXFreeGC(Dpy, TextGC);\n\tXftFontClose(Dpy, font);\n\tXftFontClose(Dpy, msgfont);\n\tXftFontClose(Dpy, introfont);\n\tXftFontClose(Dpy, welcomefont);\n\tXftFontClose(Dpy, enterfont);\n\n\tif (mode == Mode_Lock)\n\t\tXFreeGC(Dpy, WinGC);\n\n\tdelete image;\n}\n\nvoid Panel::OpenPanel() {\n\t/* Create window */\n\tWin = XCreateSimpleWindow(Dpy, Root, X, Y,\n\t\t\t\t\t\t\t  image->Width(),\n\t\t\t\t\t\t\t  image->Height(),\n\t\t\t\t\t\t\t  0, GetColor(\"white\"), GetColor(\"white\"));\n\n\t/* Events */\n\tXSelectInput(Dpy, Win, ExposureMask | KeyPressMask);\n\n\t/* Set background */\n\tXSetWindowBackgroundPixmap(Dpy, Win, PanelPixmap);\n\n\t/* Show window */\n\tXMapWindow(Dpy, Win);\n\tXMoveWindow(Dpy, Win, X, Y); /* override wm positioning (for tests) */\n\n\t/* Grab keyboard */\n\tXGrabKeyboard(Dpy, Win, False, GrabModeAsync, GrabModeAsync, CurrentTime);\n\n\tXFlush(Dpy);\n}\n\nvoid Panel::ClosePanel() {\n\tXUngrabKeyboard(Dpy, CurrentTime);\n\tXUnmapWindow(Dpy, Win);\n\tXDestroyWindow(Dpy, Win);\n\tXFlush(Dpy);\n}\n\nvoid Panel::ClearPanel() {\n\tsession_name = \"\";\n    session_exec = \"\";\n\tReset();\n\tXClearWindow(Dpy, Root);\n\tXClearWindow(Dpy, Win);\n\tCursor(SHOW);\n\tShowText();\n\tXFlush(Dpy);\n}\n\nvoid Panel::WrongPassword(int timeout) {\n\tstring message;\n\tXGlyphInfo extents;\n\n#if 0\n\tif (CapsLockOn)\n\t\tmessage = cfg->getOption(\"passwd_feedback_capslock\");\n\telse\n#endif\n\tmessage = cfg->getOption(\"passwd_feedback_msg\");\n\n\tXftDraw *draw = XftDrawCreate(Dpy, Win,\n\t\tDefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));\n\t\tXftTextExtents8(Dpy, msgfont, reinterpret_cast<const XftChar8*>(message.c_str()),\n\t\tmessage.length(), &extents);\n\n\tstring cfgX = cfg->getOption(\"passwd_feedback_x\");\n\tstring cfgY = cfg->getOption(\"passwd_feedback_y\");\n\tint shadowXOffset = cfg->getIntOption(\"msg_shadow_xoffset\");\n\tint shadowYOffset = cfg->getIntOption(\"msg_shadow_yoffset\");\n\tint msg_x = Cfg::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width);\n\tint msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height);\n\n\tOnExpose();\n\tSlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message,\n\t\t&msgshadowcolor, shadowXOffset, shadowYOffset);\n\n\tif (cfg->getOption(\"bell\") == \"1\")\n\t\tXBell(Dpy, 100);\n\n\tXFlush(Dpy);\n\tsleep(timeout);\n\tResetPasswd();\n\tOnExpose();\n\t// The message should stay on the screen even after the password field is\n\t// cleared, methinks. I don't like this solution, but it works.\n\tSlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message,\n\t\t&msgshadowcolor, shadowXOffset, shadowYOffset);\n\tXSync(Dpy, True);\n\tXftDrawDestroy(draw);\n}\n\nvoid Panel::Message(const string& text) {\n\tstring cfgX, cfgY;\n\tXGlyphInfo extents;\n\tXftDraw *draw;\n\n\tif (mode == Mode_Lock)\n\t\tdraw = XftDrawCreate(Dpy, Win,\n\t\t\tDefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));\n\telse\n\t\tdraw = XftDrawCreate(Dpy, Root,\n\t\t\tDefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));\n\n\tXftTextExtents8(Dpy, msgfont,\n\t\treinterpret_cast<const XftChar8*>(text.c_str()),\n\t\t\t\t\ttext.length(), &extents);\n\tcfgX = cfg->getOption(\"msg_x\");\n\tcfgY = cfg->getOption(\"msg_y\");\n\tint shadowXOffset = cfg->getIntOption(\"msg_shadow_xoffset\");\n\tint shadowYOffset = cfg->getIntOption(\"msg_shadow_yoffset\");\n\tint msg_x, msg_y;\n\n\tif (mode == Mode_Lock) {\n\t\tmsg_x = Cfg::absolutepos(cfgX, viewport.width, extents.width);\n\t\tmsg_y = Cfg::absolutepos(cfgY, viewport.height, extents.height);\n\t} else {\n\t\tmsg_x = Cfg::absolutepos(cfgX, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width);\n\t\tmsg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height);\n\t}\n\n\tSlimDrawString8 (draw, &msgcolor, msgfont, msg_x, msg_y,\n\t\t\t\t\t text,\n\t\t\t\t\t &msgshadowcolor,\n\t\t\t\t\t shadowXOffset, shadowYOffset);\n\tXFlush(Dpy);\n\tXftDrawDestroy(draw);\n}\n\nvoid Panel::Error(const string& text) {\n\tClosePanel();\n\tMessage(text);\n\tsleep(ERROR_DURATION);\n\tOpenPanel();\n\tClearPanel();\n}\n\nunsigned long Panel::GetColor(const char* colorname) {\n\tXColor color;\n\tXWindowAttributes attributes;\n\n\tif (mode == Mode_Lock)\n\t\tXGetWindowAttributes(Dpy, Win, &attributes);\n\telse\n\t\tXGetWindowAttributes(Dpy, Root, &attributes);\n\n\tcolor.pixel = 0;\n\n\tif(!XParseColor(Dpy, attributes.colormap, colorname, &color))\n\t\tlogStream << APPNAME << \": can't parse color \" << colorname << endl;\n\telse if(!XAllocColor(Dpy, attributes.colormap, &color))\n\t\tlogStream << APPNAME << \": can't allocate color \" << colorname << endl;\n\n\treturn color.pixel;\n}\n\nvoid Panel::Cursor(int visible) {\n\tconst char* text = NULL;\n\tint xx = 0, yy = 0, y2 = 0, cheight = 0;\n\tconst char* txth = \"Wj\"; /* used to get cursor height */\n\n\tif (mode == Mode_Lock) {\n\t\t\ttext = HiddenPasswdBuffer.c_str();\n\t\t\txx = input_pass_x;\n\t\t\tyy = input_pass_y;\n\t} else {\n\t\tswitch(field) {\n\t\t\tcase Get_Passwd:\n\t\t\t\ttext = HiddenPasswdBuffer.c_str();\n\t\t\t\txx = input_pass_x;\n\t\t\t\tyy = input_pass_y;\n\t\t\t\tbreak;\n\n\t\t\tcase Get_Name:\n\t\t\t\ttext = NameBuffer.c_str();\n\t\t\t\txx = input_name_x;\n\t\t\t\tyy = input_name_y;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tXGlyphInfo extents;\n\tXftTextExtents8(Dpy, font, (XftChar8*)txth, strlen(txth), &extents);\n\tcheight = extents.height;\n\ty2 = yy - extents.y + extents.height;\n\tXftTextExtents8(Dpy, font, (XftChar8*)text, strlen(text), &extents);\n\txx += extents.width;\n\n\tif(visible == SHOW) {\n\t\tif (mode == Mode_Lock) {\n\t\t\txx += viewport.x;\n\t\t\tyy += viewport.y;\n\t\t\ty2 += viewport.y;\n\t\t}\n\t\tXSetForeground(Dpy, TextGC,\n\t\t\tGetColor(cfg->getOption(\"input_color\").c_str()));\n\n\t\tXDrawLine(Dpy, Win, TextGC,\n\t\t\t\t  xx+1, yy-cheight,\n\t\t\t\t  xx+1, y2);\n\t} else {\n\t\tif (mode == Mode_Lock)\n\t\t\tApplyBackground(Rectangle(xx+1, yy-cheight,\n\t\t\t\t1, y2-(yy-cheight)+1));\n\t\telse\n\t\t\tXClearArea(Dpy, Win, xx+1, yy-cheight,\n\t\t\t\t1, y2-(yy-cheight)+1, false);\n\t}\n}\n\nvoid Panel::EventHandler(const Panel::FieldType& curfield) {\n\tXEvent event;\n\tfield = curfield;\n\tbool loop = true;\n\n\tif (mode == Mode_DM)\n\t\tOnExpose();\n\n\tstruct pollfd x11_pfd = {0};\n\tx11_pfd.fd = ConnectionNumber(Dpy);\n\tx11_pfd.events = POLLIN;\n\n\twhile (loop) {\n\t\tif (XPending(Dpy) || poll(&x11_pfd, 1, -1) > 0) {\n\t\t\twhile(XPending(Dpy)) {\n\t\t\t\tXNextEvent(Dpy, &event);\n\t\t\t\tswitch(event.type) {\n\t\t\t\t\tcase Expose:\n\t\t\t\t\t\tOnExpose();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase KeyPress:\n\t\t\t\t\t\tloop=OnKeyPress(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn;\n}\n\nvoid Panel::OnExpose(void) {\n\tXftDraw *draw = XftDrawCreate(Dpy, Win,\n\t\tDefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));\n\n\tif (mode == Mode_Lock)\n\t\tApplyBackground();\n\telse\n\t\tXClearWindow(Dpy, Win);\n\n\tif (input_pass_x != input_name_x || input_pass_y != input_name_y){\n\t\tSlimDrawString8 (draw, &inputcolor, font, input_name_x, input_name_y,\n\t\t\t\t\t\t NameBuffer,\n\t\t\t\t\t\t &inputshadowcolor,\n\t\t\t\t\t\t inputShadowXOffset, inputShadowYOffset);\n\t\tSlimDrawString8 (draw, &inputcolor, font, input_pass_x, input_pass_y,\n\t\t\t\t\t\t HiddenPasswdBuffer,\n\t\t\t\t\t\t &inputshadowcolor,\n\t\t\t\t\t\t inputShadowXOffset, inputShadowYOffset);\n\t} else { /*single input mode */\n\t\tswitch(field) {\n\t\t\tcase Get_Passwd:\n\t\t\t\tSlimDrawString8 (draw, &inputcolor, font,\n\t\t\t\t\t\t\t\t input_pass_x, input_pass_y,\n\t\t\t\t\t\t\t\t HiddenPasswdBuffer,\n\t\t\t\t\t\t\t\t &inputshadowcolor,\n\t\t\t\t\t\t\t\t inputShadowXOffset, inputShadowYOffset);\n\t\t\t\tbreak;\n\t\t\tcase Get_Name:\n\t\t\t\tSlimDrawString8 (draw, &inputcolor, font,\n\t\t\t\t\t\t\t\t input_name_x, input_name_y,\n\t\t\t\t\t\t\t\t NameBuffer,\n\t\t\t\t\t\t\t\t &inputshadowcolor,\n\t\t\t\t\t\t\t\t inputShadowXOffset, inputShadowYOffset);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tXftDrawDestroy (draw);\n\tCursor(SHOW);\n\tShowText();\n}\n\nvoid Panel::EraseLastChar(string &formerString) {\n\tswitch(field) {\n\tcase GET_NAME:\n\t\tif (! NameBuffer.empty()) {\n\t\t\tformerString=NameBuffer;\n\t\t\tNameBuffer.erase(--NameBuffer.end());\n\t\t}\n\t\tbreak;\n\n\tcase GET_PASSWD:\n\t\tif (!PasswdBuffer.empty()) {\n\t\t\tformerString=HiddenPasswdBuffer;\n\t\t\tPasswdBuffer.erase(--PasswdBuffer.end());\n\t\t\tHiddenPasswdBuffer.erase(--HiddenPasswdBuffer.end());\n\t\t}\n\t\tbreak;\n\t}\n}\n\nbool Panel::OnKeyPress(XEvent& event) {\n\tchar ascii;\n\tKeySym keysym;\n\tXComposeStatus compstatus;\n\tint xx = 0;\n\tint yy = 0;\n\tstring text;\n\tstring formerString = \"\";\n\n\tXLookupString(&event.xkey, &ascii, 1, &keysym, &compstatus);\n\tswitch(keysym){\n\t\tcase XK_F1:\n\t\t\tSwitchSession();\n\t\t\treturn true;\n\n\t\tcase XK_F11:\n\t\t\t/* Take a screenshot */\n\t\t\tsystem(cfg->getOption(\"screenshot_cmd\").c_str());\n\t\t\treturn true;\n\n\t\tcase XK_Return:\n\t\tcase XK_KP_Enter:\n\t\t\tif (field==Get_Name){\n\t\t\t\t/* Don't allow an empty username */\n\t\t\t\tif (NameBuffer.empty()) return true;\n\n\t\t\t\tif (NameBuffer==CONSOLE_STR){\n\t\t\t\t\taction = Console;\n\t\t\t\t} else if (NameBuffer==HALT_STR){\n\t\t\t\t\taction = Halt;\n\t\t\t\t} else if (NameBuffer==REBOOT_STR){\n\t\t\t\t\taction = Reboot;\n\t\t\t\t} else if (NameBuffer==SUSPEND_STR){\n\t\t\t\t\taction = Suspend;\n\t\t\t\t} else if (NameBuffer==EXIT_STR){\n\t\t\t\t\taction = Exit;\n\t\t\t\t} else{\n\t\t\t\t\tif (mode == Mode_DM)\n\t\t\t\t\t\taction = Login;\n\t\t\t\t\telse\n\t\t\t\t\t\taction = Lock;\n\t\t\t\t}\n\t\t\t};\n\t\t\treturn false;\n\t\tdefault:\n\t\t\tbreak;\n\t};\n\n\tCursor(HIDE);\n\tswitch(keysym){\n\t\tcase XK_Delete:\n\t\tcase XK_BackSpace:\n\t\t\tEraseLastChar(formerString);\n\t\t\tbreak;\n\n\t\tcase XK_w:\n\t\tcase XK_u:\n\t\t\tif (reinterpret_cast<XKeyEvent&>(event).state & ControlMask) {\n\t\t\t\tswitch(field) {\n\t\t\t\t\tcase Get_Passwd:\n\t\t\t\t\t\tformerString = HiddenPasswdBuffer;\n\t\t\t\t\t\tHiddenPasswdBuffer.clear();\n\t\t\t\t\t\tPasswdBuffer.clear();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Get_Name:\n\t\t\t\t\t\tformerString = NameBuffer;\n\t\t\t\t\t\tNameBuffer.clear();\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase XK_h:\n\t\t\tif (reinterpret_cast<XKeyEvent&>(event).state & ControlMask) {\n\t\t\t\tEraseLastChar(formerString);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t/* Deliberate fall-through */\n\n\t\tdefault:\n\t\t\tif (isprint(ascii) && (keysym < XK_Shift_L || keysym > XK_Hyper_R)){\n\t\t\t\tswitch(field) {\n\t\t\t\t\tcase GET_NAME:\n\t\t\t\t\t\tformerString=NameBuffer;\n\t\t\t\t\t\tif (NameBuffer.length() < INPUT_MAXLENGTH_NAME-1){\n\t\t\t\t\t\t\tNameBuffer.append(&ascii,1);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase GET_PASSWD:\n\t\t\t\t\t\tformerString=HiddenPasswdBuffer;\n\t\t\t\t\t\tif (PasswdBuffer.length() < INPUT_MAXLENGTH_PASSWD-1){\n\t\t\t\t\t\t\tPasswdBuffer.append(&ascii,1);\n\t\t\t\t\t\t\tHiddenPasswdBuffer.append(\"*\");\n\t\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\t\t\t\t};\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn true; //nodraw if notchange\n\t\t\t};\n\t\t\tbreak;\n\t};\n\n\tXGlyphInfo extents;\n\tXftDraw *draw = XftDrawCreate(Dpy, Win,\n\t\t\t  DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));\n\n\tswitch(field) {\n\t\tcase Get_Name:\n\t\t\ttext = NameBuffer;\n\t\t\txx = input_name_x;\n\t\t\tyy = input_name_y;\n\t\t\tbreak;\n\n\t\tcase Get_Passwd:\n\t\t\ttext = HiddenPasswdBuffer;\n\t\t\txx = input_pass_x;\n\t\t\tyy = input_pass_y;\n\t\t\tbreak;\n\t}\n\n\tif (!formerString.empty()){\n\t\tconst char* txth = \"Wj\"; /* get proper maximum height ? */\n\t\tXftTextExtents8(Dpy, font,\n\t\t\t\treinterpret_cast<const XftChar8*>(txth), strlen(txth), &extents);\n\t\tint maxHeight = extents.height;\n\n\t\tXftTextExtents8(Dpy, font,\n\t\t\t\treinterpret_cast<const XftChar8*>(formerString.c_str()),\n\t\t\t\t\t\tformerString.length(), &extents);\n\t\tint maxLength = extents.width;\n\n\t\tif (mode == Mode_Lock)\n\t\t\tApplyBackground(Rectangle(input_pass_x - 3,\n\t\t\t\tinput_pass_y - maxHeight - 3,\n\t\t\t\tmaxLength + 6, maxHeight + 6));\n\t\telse\n\t\t\tXClearArea(Dpy, Win, xx - 3, yy-maxHeight - 3,\n\t\t\t\tmaxLength + 6, maxHeight + 6, false);\n\t}\n\n\tif (!text.empty()) {\n\t\tSlimDrawString8 (draw, &inputcolor, font, xx, yy,\n\t\t\t\t text,\n\t\t\t\t &inputshadowcolor,\n\t\t\t\t inputShadowXOffset, inputShadowYOffset);\n\t}\n\n\tXftDrawDestroy (draw);\n\tCursor(SHOW);\n\treturn true;\n}\n\n/* Draw welcome and \"enter username\" message */\nvoid Panel::ShowText(){\n\tstring cfgX, cfgY;\n\tXGlyphInfo extents;\n\n\tbool singleInputMode =\n\tinput_name_x == input_pass_x &&\n\tinput_name_y == input_pass_y;\n\n\tXftDraw *draw = XftDrawCreate(Dpy, Win,\n\t\t  DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));\n\t/* welcome message */\n\tXftTextExtents8(Dpy, welcomefont, (XftChar8*)welcome_message.c_str(),\n\t\t\t\t\tstrlen(welcome_message.c_str()), &extents);\n\tcfgX = cfg->getOption(\"welcome_x\");\n\tcfgY = cfg->getOption(\"welcome_y\");\n\tint shadowXOffset = cfg->getIntOption(\"welcome_shadow_xoffset\");\n\tint shadowYOffset = cfg->getIntOption(\"welcome_shadow_yoffset\");\n\n\twelcome_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);\n\twelcome_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);\n\tif (welcome_x >= 0 && welcome_y >= 0) {\n\t\tSlimDrawString8 (draw, &welcomecolor, welcomefont,\n\t\t\t\t\t\t welcome_x, welcome_y,\n\t\t\t\t\t\t welcome_message,\n\t\t\t\t\t\t &welcomeshadowcolor, shadowXOffset, shadowYOffset);\n\t}\n\n\t/* Enter username-password message */\n\tstring msg;\n\tif ((!singleInputMode|| field == Get_Passwd) && mode == Mode_DM) {\n\t\tmsg = cfg->getOption(\"password_msg\");\n\t\tXftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(),\n\t\t\t\t\t\tstrlen(msg.c_str()), &extents);\n\t\tcfgX = cfg->getOption(\"password_x\");\n\t\tcfgY = cfg->getOption(\"password_y\");\n\t\tint shadowXOffset = cfg->getIntOption(\"username_shadow_xoffset\");\n\t\tint shadowYOffset = cfg->getIntOption(\"username_shadow_yoffset\");\n\t\tpassword_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);\n\t\tpassword_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);\n\t\tif (password_x >= 0 && password_y >= 0){\n\t\t\tSlimDrawString8 (draw, &entercolor, enterfont, password_x, password_y,\n\t\t\t\t\t\t\t msg, &entershadowcolor, shadowXOffset, shadowYOffset);\n\t\t}\n\t}\n\n\tif (!singleInputMode|| field == Get_Name) {\n\t\tmsg = cfg->getOption(\"username_msg\");\n\t\tXftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(),\n\t\t\t\t\t\tstrlen(msg.c_str()), &extents);\n\t\tcfgX = cfg->getOption(\"username_x\");\n\t\tcfgY = cfg->getOption(\"username_y\");\n\t\tint shadowXOffset = cfg->getIntOption(\"username_shadow_xoffset\");\n\t\tint shadowYOffset = cfg->getIntOption(\"username_shadow_yoffset\");\n\t\tusername_x = Cfg::absolutepos(cfgX, image->Width(), extents.width);\n\t\tusername_y = Cfg::absolutepos(cfgY, image->Height(), extents.height);\n\t\tif (username_x >= 0 && username_y >= 0){\n\t\t\tSlimDrawString8 (draw, &entercolor, enterfont, username_x, username_y,\n\t\t\t\t\t\t\t msg, &entershadowcolor, shadowXOffset, shadowYOffset);\n\t\t}\n\t}\n\tXftDrawDestroy(draw);\n\n\tif (mode == Mode_Lock) {\n\t\t// If only the password box is visible, draw the user name somewhere too\n\t\tstring user_msg = \"User: \" + GetName();\n\t\tint show_username = cfg->getIntOption(\"show_username\");\n\t\tif (singleInputMode && show_username) {\n\t\t\tMessage(user_msg);\n\t\t}\n\t}\n}\n\nstring Panel::getSession() {\n\treturn session_exec;\n}\n\n/* choose next available session type */\nvoid Panel::SwitchSession() {\n        pair<string,string> ses = cfg->nextSession();\n        session_name = ses.first;\n        session_exec = ses.second;\n        if (session_name.size() > 0) {\n                ShowSession();\n        }\n }\n\n/* Display session type on the screen */\nvoid Panel::ShowSession() {\n\tstring msg_x, msg_y;\n\tXClearWindow(Dpy, Root);\n\tstring currsession = cfg->getOption(\"session_msg\") + \" \" + session_name;\n\tXGlyphInfo extents;\n\n\tsessionfont = XftFontOpenName(Dpy, Scr, cfg->getOption(\"session_font\").c_str());\n\n\tXftDraw *draw = XftDrawCreate(Dpy, Root,\n\t\t\t\t\t\t\t\t  DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr));\n\tXftTextExtents8(Dpy, sessionfont, reinterpret_cast<const XftChar8*>(currsession.c_str()),\n\t\t\t\t\tcurrsession.length(), &extents);\n\tmsg_x = cfg->getOption(\"session_x\");\n\tmsg_y = cfg->getOption(\"session_y\");\n\tint x = Cfg::absolutepos(msg_x, XWidthOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.width);\n\tint y = Cfg::absolutepos(msg_y, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height);\n\tint shadowXOffset = cfg->getIntOption(\"session_shadow_xoffset\");\n\tint shadowYOffset = cfg->getIntOption(\"session_shadow_yoffset\");\n\n\tSlimDrawString8(draw, &sessioncolor, sessionfont, x, y,\n\t\t\t\t\tcurrsession,\n\t\t\t\t\t&sessionshadowcolor,\n\t\t\t\t\tshadowXOffset, shadowYOffset);\n\tXFlush(Dpy);\n\tXftDrawDestroy(draw);\n}\n\n\nvoid Panel::SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font,\n\t\t\t\t\t\t\tint x, int y, const string& str,\n\t\t\t\t\t\t\tXftColor* shadowColor,\n\t\t\t\t\t\t\tint xOffset, int yOffset)\n{\n\tint calc_x = 0;\n\tint calc_y = 0;\n\tif (mode == Mode_Lock) {\n\t\tcalc_x = viewport.x;\n\t\tcalc_y = viewport.y;\n\t}\n\n\tif (xOffset && yOffset) {\n\t\tXftDrawStringUtf8(d, shadowColor, font,\n\t\t\tx + xOffset + calc_x,\n\t\t\ty + yOffset + calc_y,\n\t\t\treinterpret_cast<const FcChar8*>(str.c_str()),\n\t\t\tstr.length());\n\t}\n\n\tXftDrawStringUtf8(d, color, font,\n\t\tx + calc_x,\n\t\ty + calc_y,\n\t\treinterpret_cast<const FcChar8*>(str.c_str()),\n\t\tstr.length());\n}\n\nPanel::ActionType Panel::getAction(void) const{\n\treturn action;\n}\n\nvoid Panel::Reset(void){\n\tResetName();\n\tResetPasswd();\n}\n\nvoid Panel::ResetName(void){\n\tNameBuffer.clear();\n}\n\nvoid Panel::ResetPasswd(void){\n\tPasswdBuffer.clear();\n\tHiddenPasswdBuffer.clear();\n}\n\nvoid Panel::SetName(const string& name){\n\tNameBuffer=name;\n\tif (mode == Mode_DM)\n\t\taction = Login;\n\telse\n\t\taction = Lock;\n}\n\nconst string& Panel::GetName(void) const{\n\treturn NameBuffer;\n}\n\nconst string& Panel::GetPasswd(void) const{\n\treturn PasswdBuffer;\n}\n\nRectangle Panel::GetPrimaryViewport() {\n\tRectangle fallback;\n\tRectangle result;\n\n\tRROutput primary;\n\tXRROutputInfo *primary_info;\n\tXRRScreenResources *resources;\n\tXRRCrtcInfo *crtc_info;\n\n    int crtc;\n\n\tfallback.x = 0;\n\tfallback.y = 0;\n\tfallback.width = DisplayWidth(Dpy, Scr);\n\tfallback.height = DisplayHeight(Dpy, Scr);\n\n\tprimary = XRRGetOutputPrimary(Dpy, Win);\n\tif (!primary) {\n\t    return fallback;\n\t}\n\tresources = XRRGetScreenResources(Dpy, Win);\n\tif (!resources)\n\t    return fallback;\n\n\tprimary_info = XRRGetOutputInfo(Dpy, resources, primary);\n\tif (!primary_info) {\n\t    XRRFreeScreenResources(resources);\n\t    return fallback;\n\t}\n\n    // Fixes bug with multiple monitors.  Just pick first monitor if \n    // XRRGetOutputInfo gives returns bad into for crtc.\n    if (primary_info->crtc < 1) {\n        if (primary_info->ncrtc > 0) {\n           crtc = primary_info->crtcs[0];\n        } else {\n            cerr << \"Cannot get crtc from xrandr.\\n\";\n            exit(EXIT_FAILURE);\n        }\n    } else {\n        crtc = primary_info->crtc;\n    }\n\n\tcrtc_info = XRRGetCrtcInfo(Dpy, resources, crtc);\n\n\tif (!crtc_info) {\n\t    XRRFreeOutputInfo(primary_info);\n\t    XRRFreeScreenResources(resources);\n\t    return fallback;\n\t}\n\n\tresult.x = crtc_info->x;\n\tresult.y = crtc_info->y;\n\tresult.width = crtc_info->width;\n\tresult.height = crtc_info->height;\n\n\tXRRFreeCrtcInfo(crtc_info);\n\tXRRFreeOutputInfo(primary_info);\n\tXRRFreeScreenResources(resources);\n\n\treturn result;\n}\n\nvoid Panel::ApplyBackground(Rectangle rect) {\n\tint ret = 0;\n\n\tif (rect.is_empty()) {\n\t    rect.x = 0;\n\t    rect.y = 0;\n\t    rect.width = viewport.width;\n\t    rect.height = viewport.height;\n\t}\n\n\tret = XCopyArea(Dpy, PanelPixmap, Win, WinGC,\n\t\trect.x, rect.y, rect.width, rect.height,\n\t\tviewport.x + rect.x, viewport.y + rect.y);\n\n\tif (!ret)\n\t    cerr << APPNAME << \": failed to put pixmap on the screen\\n.\";\n}\n"
  },
  {
    "path": "panel.h",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 1997, 1998 Per Liden\n   Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n   Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n   Copyright (C) 2013 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n*/\n\n#ifndef _PANEL_H_\n#define _PANEL_H_\n\n#include <X11/Xlib.h>\n#include <X11/keysym.h>\n#include <X11/Xft/Xft.h>\n#include <X11/cursorfont.h>\n#include <X11/Xmu/WinUtil.h>\n#include <sys/wait.h>\n#include <stdlib.h>\n#include <signal.h>\n#include <iostream>\n#include <string>\n\n#ifdef NEEDS_BASENAME\n#include <libgen.h>\n#endif\n\n#include \"switchuser.h\"\n#include \"log.h\"\n#include \"image.h\"\n\nstruct Rectangle {\n\tint x;\n\tint y;\n\tunsigned int width;\n\tunsigned int height;\n\n\tRectangle() : x(0), y(0), width(0), height(0) {};\n\tRectangle(int x, int y, unsigned int width,\n\t\t\t\t\tunsigned int height) :\n\t\tx(x), y(y), width(width), height(height) {};\n\tbool is_empty() const {\n\t\treturn width == 0 || height == 0;\n\t}\n};\n\nclass Panel {\npublic:\n\tenum ActionType {\n\t\tLogin,\n\t\tLock,\n\t\tConsole,\n\t\tReboot,\n\t\tHalt,\n\t\tExit,\n\t\tSuspend\n\t};\n\n\tenum FieldType {\n\t\tGet_Name,\n\t\tGet_Passwd\n\t};\n\n\tenum PanelType {\n\t\tMode_DM,\n\t\tMode_Lock\n\t};\n\n\tPanel(Display *dpy, int scr, Window root, Cfg *config,\n\t\t  const std::string& themed, PanelType panel_mode);\n\t~Panel();\n\tvoid OpenPanel();\n\tvoid ClosePanel();\n\tvoid ClearPanel();\n\tvoid WrongPassword(int timeout);\n\tvoid Message(const std::string &text);\n\tvoid Error(const std::string &text);\n\tvoid EventHandler(const FieldType &curfield);\n\tstd::string getSession();\n\tActionType getAction(void) const;\n\n\tvoid Reset(void);\n\tvoid ResetName(void);\n\tvoid ResetPasswd(void);\n\tvoid SetName(const std::string &name);\n\tconst std::string& GetName(void) const;\n\tconst std::string& GetPasswd(void) const;\n\tvoid SwitchSession();\nprivate:\n\tPanel();\n\tvoid Cursor(int visible);\n\tunsigned long GetColor(const char *colorname);\n\tvoid OnExpose(void);\n\tvoid EraseLastChar(string &formerString);\n\tbool OnKeyPress(XEvent& event);\n\tvoid ShowText();\n\tvoid ShowSession();\n\n\tvoid SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font,\n\t\t\t\t\t\t\tint x, int y, const std::string &str,\n\t\t\t\t\t\t\tXftColor *shadowColor,\n\t\t\t\t\t\t\tint xOffset, int yOffset);\n\n\tRectangle GetPrimaryViewport();\n\tvoid ApplyBackground(Rectangle = Rectangle());\n\n\t/* Private data */\n\tPanelType mode; /* work mode */\n\tCfg *cfg;\n\tWindow Win;\n\tWindow Root;\n\tDisplay *Dpy;\n\tint Scr;\n\tint X, Y;\n\tGC TextGC;\n\tGC WinGC;\n\tXftFont *font;\n\tXftColor inputshadowcolor;\n\tXftColor inputcolor;\n\tXftColor msgcolor;\n\tXftColor msgshadowcolor;\n\tXftFont *msgfont;\n\tXftColor introcolor;\n\tXftFont *introfont;\n\tXftFont *welcomefont;\n\tXftColor welcomecolor;\n\tXftFont *sessionfont;\n\tXftColor sessioncolor;\n\tXftColor sessionshadowcolor;\n\tXftColor welcomeshadowcolor;\n\tXftFont *enterfont;\n\tXftColor entercolor;\n\tXftColor entershadowcolor;\n\tActionType action;\n\tFieldType field;\n\t//Pixmap   background;\n\t\n\t/* Username/Password */\n\tstd::string NameBuffer;\n\tstd::string PasswdBuffer;\n\tstd::string HiddenPasswdBuffer;\n\n\t/* screen stuff */\n\tRectangle viewport;\n\n\t/* Configuration */\n\tint input_name_x;\n\tint input_name_y;\n\tint input_pass_x;\n\tint input_pass_y;\n\tint inputShadowXOffset;\n\tint inputShadowYOffset;\n\tint input_cursor_height;\n\tint welcome_x;\n\tint welcome_y;\n\tint welcome_shadow_xoffset;\n\tint welcome_shadow_yoffset;\n\tint session_shadow_xoffset;\n\tint session_shadow_yoffset;\n\tint intro_x;\n\tint intro_y;\n\tint username_x;\n\tint username_y;\n\tint username_shadow_xoffset;\n\tint username_shadow_yoffset;\n\tint password_x;\n\tint password_y;\n\tstd::string welcome_message;\n\tstd::string intro_message;\n\n\t/* Pixmap data */\n\tPixmap PanelPixmap;\n\n\tImage *image;\n\n\t/* For thesting themes */\n\tbool testing;\n\tstd::string themedir;\n\n\t/* Session handling */\n\tstd::string session_name;\n    std::string session_exec;\n};\n\n#endif /* _PANEL_H_ */\n"
  },
  {
    "path": "png.c",
    "content": "/****************************************************************************\n\tpng.c - read and write png images using libpng routines.\n\tDistributed with Xplanet.\n\tCopyright (C) 2002 Hari Nair <hari@alumni.caltech.edu>\n\n\tThis program is free software; you can redistribute it and/or modify\n\tit under the terms of the GNU General Public License as published by\n\tthe Free Software Foundation; either version 2 of the License, or\n\t(at your option) any later version.\n\n\tThis program is distributed in the hope that it will be useful,\n\tbut WITHOUT ANY WARRANTY; without even the implied warranty of\n\tMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\tGNU General Public License for more details.\n\n\tYou should have received a copy of the GNU General Public License\n\talong with this program; if not, write to the Free Software\n\tFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n****************************************************************************/\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <string.h>\n#include <unistd.h>\n#include <sys/socket.h>\n#include <png.h>\n#include \"const.h\"\n\nint\nread_png(const char *filename, int *width, int *height, unsigned char **rgb,\n\t unsigned char **alpha)\n{\n\tint ret = 0;\n\n\tpng_structp png_ptr;\n\tpng_infop info_ptr;\n\tpng_bytepp row_pointers;\n\n\tunsigned char *ptr = NULL;\n\tpng_uint_32 w, h;\n\tint bit_depth, color_type, interlace_type;\n\tint i;\n\n\tFILE *infile = fopen(filename, \"rb\");\n\tif (infile == NULL) {\n\t\tfprintf(stderr, \"Can not fopen file: %s\\n\", filename);\n\t\treturn ret;\n\t}\n\n\tpng_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,\n\t\t\t\t\t\t(png_voidp)NULL,\n\t\t\t\t\t\t(png_error_ptr)NULL,\n\t\t\t\t\t\t(png_error_ptr)NULL);\n\tif (!png_ptr)\n\t\tgoto file_close;\n\n\tinfo_ptr = png_create_info_struct(png_ptr);\n\tif (!info_ptr) {\n\t\tpng_destroy_read_struct(&png_ptr,\n\t\t\t\t\t\t(png_infopp)NULL,\n\t\t\t\t\t\t(png_infopp)NULL);\n\t}\n\n#if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 4\n\tif (setjmp(png_jmpbuf((png_ptr))))\n#else\n\tif (setjmp(png_ptr->jmpbuf))\n#endif\n\t\tgoto png_destroy;\n\n\tpng_init_io(png_ptr, infile);\n\tpng_read_info(png_ptr, info_ptr);\n\n\tpng_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type,\n\t\t\t\t &interlace_type, (int *) NULL, (int *) NULL);\n\n\t/* Prevent against integer overflow */\n\tif (w >= MAX_DIMENSION || h >= MAX_DIMENSION) {\n\t\tfprintf(stderr,\n\t\t\t\"Unreasonable dimension found in file: %s\\n\", filename);\n\t\tgoto png_destroy;\n\t}\n\n\t*width = (int) w;\n\t*height = (int) h;\n\n\tif (color_type == PNG_COLOR_TYPE_RGB_ALPHA\n\t\t|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {\n\t\talpha[0] = malloc(*width * *height);\n\t\tif (alpha[0] == NULL) {\n\t\t\tfprintf(stderr,\n\t\t\t\t\"Can't allocate memory for alpha channel in PNG file.\\n\");\n\t\t\tgoto png_destroy;\n\t\t}\n\t}\n\n\t/* Change a paletted/grayscale image to RGB */\n\tif (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)\n\t\tpng_set_expand(png_ptr);\n\n\t/* Change a grayscale image to RGB */\n\tif (color_type == PNG_COLOR_TYPE_GRAY ||\n\t\tcolor_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n\t\tpng_set_gray_to_rgb(png_ptr);\n\n\t/* If the PNG file has 16 bits per channel, strip them down to 8 */\n\tif (bit_depth == 16)\n\t\tpng_set_strip_16(png_ptr);\n\n\t/* use 1 byte per pixel */\n\tpng_set_packing(png_ptr);\n\n\trow_pointers = malloc(*height * sizeof(png_bytep));\n\tif (row_pointers == NULL) {\n\t\tfprintf(stderr, \"Can't allocate memory for PNG file.\\n\");\n\t\tgoto png_destroy;\n\t}\n\n\tfor (i = 0; i < *height; i++) {\n\t\trow_pointers[i] = malloc(4 * *width);\n\t\tif (row_pointers == NULL) {\n\t\t\tfprintf(stderr,\n\t\t\t\t\"Can't allocate memory for PNG line.\\n\");\n\t\t\tgoto rows_free;\n\t\t}\n\t}\n\n\tpng_read_image(png_ptr, row_pointers);\n\n\trgb[0] = malloc(3 * *width * *height);\n\tif (rgb[0] == NULL) {\n\t\tfprintf(stderr, \"Can't allocate memory for PNG file.\\n\");\n\t\tgoto rows_free;\n\t}\n\n\tif (alpha[0] == NULL) {\n\t\tptr = rgb[0];\n\t\tfor (i = 0; i < *height; i++) {\n\t\t\tmemcpy(ptr, row_pointers[i], 3 * *width);\n\t\t\tptr += 3 * *width;\n\t\t}\n\t} else {\n\t\tint j;\n\t\tptr = rgb[0];\n\t\tfor (i = 0; i < *height; i++) {\n\t\t\tint ipos = 0;\n\t\t\tfor (j = 0; j < *width; j++) {\n\t\t\t\t*ptr++ = row_pointers[i][ipos++];\n\t\t\t\t*ptr++ = row_pointers[i][ipos++];\n\t\t\t\t*ptr++ = row_pointers[i][ipos++];\n\t\t\t\talpha[0][i * *width + j]\n\t\t\t\t\t= row_pointers[i][ipos++];\n\t\t\t}\n\t\t}\n\t}\n\n\tret = 1; /* data reading is OK */\n\nrows_free:\n\tfor (i = 0; i < *height; i++) {\n\t\tif (row_pointers[i] != NULL)\n\t\t\tfree(row_pointers[i]);\n\t}\n\n\tfree(row_pointers);\n\npng_destroy:\n\tpng_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);\n\nfile_close:\n\tfclose(infile);\n\treturn ret;\n}\n"
  },
  {
    "path": "slim.1",
    "content": "\" Text automatically generated by txt2man-1.4.7\n.TH slim 1 \"October 03, 2013\" \"\" \"\"\n.SH NAME\n\\fBslim \\fP- Simple LogIn Manager\n\\fB\n.SH SYNOPSIS\n.nf\n.fam C\n\\fBslim\\fP [\\fIoptions\\fP] [<arguments>]\n.fam T\n.fi\n.SH DESCRIPTION\nSLiM is a lightweight login manager for X11, allowing the initialization\nof a graphical session by entring username and password in a login screen.\n.SH OPTIONS\n.TP\n.B\n\\fB-d\\fP\nrun as a daemon\n.TP\n.B\n\\fB-p\\fP /path/to/theme\ndisplay a preview of the theme. An already running X11 session\nis required for theme preview.\n.TP\n.B\n\\fB-h\\fP\ndisplay a brief help message\n.TP\n.B\n\\fB-v\\fP\ndisplay version information\n.SH EXAMPLES\n.TP\n.B\n\\fBslim\\fP \\fB-d\\fP\nrun \\fBslim\\fP in daemon mode\n.TP\n.B\n\\fBslim\\fP \\fB-p\\fP /usr/share/\\fBslim\\fP/themes/default\npreview of the default theme\n.SH STARTING SLIM AT BOOT\nPlease refer to documentation of your Operating System to make \\fBslim\\fP\nautomatically startup after the system boots.\n.SH CONFIGURATION\nGlobal configuration is stored in the /etc/slim.conf file. See the comments\ninside the file for a detailed explanation of the \\fIoptions\\fP.\n.SH USAGE AND SPECIAL USERNAMES\nWhen started, \\fBslim\\fP will show a login panel; enter the username and\npassword of the user you want to login as.\n.PP\nSpecial usernames:\n.TP\n.B\nconsole\nopen a xterm console\n.TP\n.B\nexit\nquit \\fBslim\\fP\n.TP\n.B\nhalt\nshutdown the machine\n.TP\n.B\nreboot\nreboot the machine\n.TP\n.B\nsuspend\npower-suspend the machine\n.PP\nSee the configuration file for customizing the above commands.\nThe 'halt' and 'reboot' commands need the root password, this may\nchange in future releases.\n.PP\nShortcuts:\n.TP\n.B\nF11\nexecutes a custom command (by default takes a screenshot)  \n.TP\n.B\nF1\nchoose session type from session list.\n.SH AUTHORS \nNobuhiro Iwamatsu <iwamatsu@nigauri.org>\n.SH SEE ALSO\nSee the online documentation at the SLiM web site for further information\non themes, FAQs, etc.\n"
  },
  {
    "path": "slim.conf",
    "content": "# Path, X server and arguments (if needed)\n# Note: -xauth $authfile is automatically appended\ndefault_path        /bin:/usr/bin:/usr/local/bin\ndefault_xserver     /usr/bin/X\n#xserver_arguments   -dpi 75\n\n# Commands for halt, login, etc.\nhalt_cmd            /sbin/shutdown -h now\nreboot_cmd          /sbin/shutdown -r now\nconsole_cmd         /usr/bin/xterm -C -fg white -bg black +sb -T \"Console login\" -e /bin/sh -c \"/bin/cat /etc/issue; exec /bin/login\"\n#suspend_cmd        /usr/sbin/suspend\n\n# Full path to the xauth binary\nxauth_path         /usr/bin/xauth \n\n# Xauth file for server\nauthfile           /var/run/slim.auth\n\n\n# Activate numlock when slim starts. Valid values: on|off\n# numlock             on\n\n# Hide the mouse cursor (note: does not work with some WMs).\n# Valid values: true|false\n# hidecursor          false\n\n# This command is executed after a succesful login.\n# you can place the %session and %theme variables\n# to handle launching of specific commands in .xinitrc\n# depending of chosen session and slim theme\n#\n# NOTE: if your system does not have bash you need\n# to adjust the command according to your preferred shell,\n# i.e. for freebsd use:\n# login_cmd           exec /bin/sh - ~/.xinitrc %session\nlogin_cmd           exec /bin/bash -login ~/.xinitrc %session\n\n# Commands executed when starting and exiting a session.\n# They can be used for registering a X11 session with\n# sessreg. You can use the %user variable\n#\n# sessionstart_cmd\tsome command\n# sessionstop_cmd\tsome command\n\n# Start in daemon mode. Valid values: yes | no\n# Note that this can be overriden by the command line\n# options \"-d\" and \"-nodaemon\"\n# daemon\tyes\n\n# Set directory that contains the xsessions.\n# slim reads xsesion from this directory, and be able to select.\nsessiondir            /usr/share/xsessions/\n\n# Executed when pressing F11 (requires imagemagick)\nscreenshot_cmd      import -window root /slim.png\n\n# welcome message. Available variables: %host, %domain\nwelcome_msg         Welcome to %host\n\n# Session message. Prepended to the session name when pressing F1\n# session_msg         Session: \n\n# shutdown / reboot messages\nshutdown_msg       The system is halting...\nreboot_msg         The system is rebooting...\n\n# default user, leave blank or remove this line\n# for avoid pre-loading the username.\n#default_user        simone\n\n# Focus the password field on start when default_user is set\n# Set to \"yes\" to enable this feature\n#focus_password      no\n\n# Automatically login the default user (without entering\n# the password. Set to \"yes\" to enable this feature\n#auto_login          no\n\n\n# current theme, use comma separated list to specify a set to \n# randomly choose from\ncurrent_theme       default\n\n# Lock file\nlockfile            /var/run/slim.lock\n\n# Log file\nlogfile             /var/log/slim.log\n\n"
  },
  {
    "path": "slim.service",
    "content": "[Unit]\nDescription=SLiM Simple Login Manager\nAfter=systemd-user-sessions.service\n\n[Service]\nExecStart=/usr/bin/slim -nodaemon\n\n[Install]\nAlias=display-manager.service\n"
  },
  {
    "path": "slimlock.1",
    "content": ".TH slimlock 1 \"June 10, 2011\" \"version 0.8\"\n.SH NAME\n\\fBslimlock\\fP - Unholy Screen Locker\n\\fB\n.SH SYNOPSIS\n.nf\n.fam C\n\\fBslimlock\\fP [-v]\n.fam T\n.fi\n.SH DESCRIPTION\nThe Frankenstein's monster of screen lockers. Grafting SLiM and slock together\nleads to blood, tears, and locked screens.\n.SH OPTIONS\n.TP\n.B\n\\fB-v\\fP\ndisplay version information\n.SH CONFIGURATION\nSlimlock reads the same configuration files you use for SLiM. It looks in \\fICFGDIR/slim.conf\\fP and \\fICFGDIR/slimlock.conf\\fP, where \\fICFGDIR\\fP is defined in the makefile. The options that are read from slim.conf are hidecursor, current_theme, background_color, and background_style, screenshot_cmd, and welcome_msg. See the SLiM docs for more information.\n\nslimlock.conf contains the following settings:\n\n.TP\n.B dpms_standby_timeout\nnumber of seconds of inactivity before the screen blanks.\n.BI \"Default: \" 60\n.TP \n.B dpms_off_timeout\nnumber of seconds of inactivity before the screen is turned off.\n.BI \"Default: \" 600\n.TP\n.B wrong_passwd_timeout\ndelay in seconds after an incorrect password is entered.\n.BI \"Default: \" 2\n.TP\n.B passwd_feedback_msg\nmessage to display after a failed authentication attempt.\n.BI \"Default: \" \"Authentication failed\"\n.TP\n.B passwd_feedback_capslock\nmessage to display after a failed authentication attempt if the CapsLock is on.\n.BI \"Default: \" \"Authentication failed (CapsLock is on)\"\n.TP\n.B show_username\n1 to show username on themes with single input field; 0 to disable.\n.BI \"Default: \" 1\n.TP\n.B show_welcome_msg\n1 to show SLiM's welcome message; 0 to disable.\n.BI \"Default: \" 0\n.TP\n.B tty_lock\n1 to disallow virtual terminals switching; 0 to allow.\n.BI \"Default: \" 1\n.TP\n.B bell\n1 to enable the bell on authentication failure; 0 to disable.\n.BI \"Default: \" 1\n.SH \"SEE ALSO\"\n.BR slim (1)\n"
  },
  {
    "path": "slimlock.conf",
    "content": "dpms_standby_timeout            60\ndpms_off_timeout                600\n\nwrong_passwd_timeout            2\npasswd_feedback_x               50%\npasswd_feedback_y               10%\npasswd_feedback_msg             Authentication failed\npasswd_feedback_capslock        Authentication failed (CapsLock is on)\nshow_username                   1\nshow_welcome_msg                0\ntty_lock                        0\n"
  },
  {
    "path": "slimlock.cpp",
    "content": "/* slimlock\n * Copyright (c) 2010-2012 Joel Burget <joelburget@gmail.com>\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n */\n\n#include <cstdio>\n#include <cstring>\n#include <algorithm>\n#include <sys/types.h>\n#include <sys/ioctl.h>\n#include <linux/vt.h>\n#include <X11/keysym.h>\n#include <X11/Xlib.h>\n#include <X11/Xutil.h>\n#include <X11/extensions/dpms.h>\n#include <security/pam_appl.h>\n#include <pthread.h>\n#include <err.h>\n#include <signal.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/file.h>\n#include <errno.h>\n#include <sys/file.h>\n#include <fcntl.h>\n\n#include \"cfg.h\"\n#include \"util.h\"\n#include \"panel.h\"\n\n#undef APPNAME\n#define APPNAME \"slimlock\"\n#define SLIMLOCKCFG SYSCONFDIR\"/slimlock.conf\"\n\nusing namespace std;\n\nvoid setBackground(const string& themedir);\nvoid HideCursor();\nbool AuthenticateUser();\nstatic int ConvCallback(int num_msgs, const struct pam_message **msg,\n\t\t\t\t\t\tstruct pam_response **resp, void *appdata_ptr);\nstring findValidRandomTheme(const string& set);\nvoid HandleSignal(int sig);\nvoid *RaiseWindow(void *data);\n\n// I really didn't wanna put these globals here, but it's the only way...\nDisplay* dpy;\nint scr;\nWindow win;\nCfg* cfg;\nPanel* loginPanel;\nstring themeName = \"\";\n\npam_handle_t *pam_handle;\nstruct pam_conv conv = {ConvCallback, NULL};\n\nCARD16 dpms_standby, dpms_suspend, dpms_off, dpms_level;\nBOOL dpms_state, using_dpms;\nint term;\n\nstatic void\ndie(const char *errstr, ...) {\n\tva_list ap;\n\n\tva_start(ap, errstr);\n\tvfprintf(stderr, errstr, ap);\n\tva_end(ap);\n\texit(EXIT_FAILURE);\n}\n\nint main(int argc, char **argv) {\n\tif((argc == 2) && !strcmp(\"-v\", argv[1]))\n\t\tdie(APPNAME\"-\"VERSION\", © 2010-2012 Joel Burget\\n\");\n\telse if(argc != 1)\n\t\tdie(\"usage: \"APPNAME\" [-v]\\n\");\n\n\tvoid (*prev_fn)(int);\n\n\t// restore DPMS settings should slimlock be killed in the line of duty\n\tprev_fn = signal(SIGTERM, HandleSignal);\n\tif (prev_fn == SIG_IGN) signal(SIGTERM, SIG_IGN);\n\n\t// create a lock file to solve mutliple instances problem\n\t// /var/lock used to be the place to put this, now it's /run/lock\n\t// ...i think\n\tstruct stat statbuf;\n\tint lock_file;\n\n\t// try /run/lock first, since i believe it's preferred\n\tif (!stat(\"/run/lock\", &statbuf))\n\t\tlock_file = open(\"/run/lock/\"APPNAME\".lock\", O_CREAT | O_RDWR, 0666);\n\telse\n\t\tlock_file = open(\"/var/lock/\"APPNAME\".lock\", O_CREAT | O_RDWR, 0666);\n\n\tint rc = flock(lock_file, LOCK_EX | LOCK_NB);\n\n\tif(rc) {\n\t\tif(EWOULDBLOCK == errno)\n\t\t\tdie(APPNAME\" already running\\n\");\n\t}\n\n\tunsigned int cfg_passwd_timeout;\n\t// Read user's current theme\n\tcfg = new Cfg;\n\tcfg->readConf(CFGFILE);\n\tcfg->readConf(SLIMLOCKCFG);\n\tstring themebase = \"\";\n\tstring themefile = \"\";\n\tstring themedir = \"\";\n\tthemeName = \"\";\n\tthemebase = string(THEMESDIR) + \"/\";\n\tthemeName = cfg->getOption(\"current_theme\");\n\tstring::size_type pos;\n\tif ((pos = themeName.find(\",\")) != string::npos) {\n\t\tthemeName = findValidRandomTheme(themeName);\n\t}\n\n\tbool loaded = false;\n\twhile (!loaded) {\n\t\tthemedir =  themebase + themeName;\n\t\tthemefile = themedir + THEMESFILE;\n\t\tif (!cfg->readConf(themefile)) {\n\t\t\tif (themeName == \"default\") {\n\t\t\t\tcerr << APPNAME << \": Failed to open default theme file \"\n\t\t\t\t\t << themefile << endl;\n\t\t\t\texit(ERR_EXIT);\n\t\t\t} else {\n\t\t\t\tcerr << APPNAME << \": Invalid theme in config: \"\n\t\t\t\t\t << themeName << endl;\n\t\t\t\tthemeName = \"default\";\n\t\t\t}\n\t\t} else {\n\t\t\tloaded = true;\n\t\t}\n\t}\n\n\tconst char *display = getenv(\"DISPLAY\");\n\tif (!display)\n\t\tdisplay = DISPLAY;\n\n\tif(!(dpy = XOpenDisplay(display)))\n\t\tdie(APPNAME\": cannot open display\\n\");\n\tscr = DefaultScreen(dpy);\n\n\tXSetWindowAttributes wa;\n\twa.override_redirect = 1;\n\twa.background_pixel = BlackPixel(dpy, scr);\n\n\t// Create a full screen window\n\tWindow root = RootWindow(dpy, scr);\n\twin = XCreateWindow(dpy,\n\t  root,\n\t  0,\n\t  0,\n\t  DisplayWidth(dpy, scr),\n\t  DisplayHeight(dpy, scr),\n\t  0,\n\t  DefaultDepth(dpy, scr),\n\t  CopyFromParent,\n\t  DefaultVisual(dpy, scr),\n\t  CWOverrideRedirect | CWBackPixel,\n\t  &wa);\n\tXMapWindow(dpy, win);\n\n\tXFlush(dpy);\n\tfor (int len = 1000; len; len--) {\n\t\tif(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)\n\t\t\t== GrabSuccess)\n\t\t\tbreak;\n\t\tusleep(1000);\n\t}\n\tXSelectInput(dpy, win, ExposureMask | KeyPressMask);\n\n\t// This hides the cursor if the user has that option enabled in their\n\t// configuration\n\tHideCursor();\n\n\tloginPanel = new Panel(dpy, scr, win, cfg, themedir, Panel::Mode_Lock);\n\n\tint ret = pam_start(APPNAME, loginPanel->GetName().c_str(), &conv, &pam_handle);\n\t// If we can't start PAM, just exit because slimlock won't work right\n\tif (ret != PAM_SUCCESS)\n\t\tdie(\"PAM: %s\\n\", pam_strerror(pam_handle, ret));\n\n\t// disable tty switching\n\tif(cfg->getOption(\"tty_lock\") == \"1\") {\n\t\tif ((term = open(\"/dev/console\", O_RDWR)) == -1)\n\t\t\tperror(\"error opening console\");\n\n\t\tif ((ioctl(term, VT_LOCKSWITCH)) == -1)\n\t\t\tperror(\"error locking console\");\n\t}\n\n\t// Set up DPMS\n\tunsigned int cfg_dpms_standby, cfg_dpms_off;\n\tcfg_dpms_standby = Cfg::string2int(cfg->getOption(\"dpms_standby_timeout\").c_str());\n\tcfg_dpms_off = Cfg::string2int(cfg->getOption(\"dpms_off_timeout\").c_str());\n\tusing_dpms = DPMSCapable(dpy) && (cfg_dpms_standby > 0);\n\tif (using_dpms) {\n\t\tDPMSGetTimeouts(dpy, &dpms_standby, &dpms_suspend, &dpms_off);\n\n\t\tDPMSSetTimeouts(dpy, cfg_dpms_standby,\n\t\t\t\t\t\tcfg_dpms_standby, cfg_dpms_off);\n\n\t\tDPMSInfo(dpy, &dpms_level, &dpms_state);\n\t\tif (!dpms_state)\n\t\t\tDPMSEnable(dpy);\n\t}\n\n\t// Get password timeout\n\tcfg_passwd_timeout = Cfg::string2int(cfg->getOption(\"wrong_passwd_timeout\").c_str());\n\t// Let's just make sure it has a sane value\n\tcfg_passwd_timeout = cfg_passwd_timeout > 60 ? 60 : cfg_passwd_timeout;\n\n\tpthread_t raise_thread;\n\tpthread_create(&raise_thread, NULL, RaiseWindow, NULL);\n\n\t// Main loop\n\twhile (true)\n\t{\n\t\tloginPanel->ResetPasswd();\n\n\t\t// AuthenticateUser returns true if authenticated\n\t\tif (AuthenticateUser())\n\t\t\tbreak;\n\n\t\tloginPanel->WrongPassword(cfg_passwd_timeout);\n\t}\n\n\t// kill thread before destroying the window that it's supposed to be raising\n\tpthread_cancel(raise_thread);\n\n\tloginPanel->ClosePanel();\n\tdelete loginPanel;\n\n\t// Get DPMS stuff back to normal\n\tif (using_dpms) {\n\t\tDPMSSetTimeouts(dpy, dpms_standby, dpms_suspend, dpms_off);\n\t\t// turn off DPMS if it was off when we entered\n\t\tif (!dpms_state)\n\t\t\tDPMSDisable(dpy);\n\t}\n\n\tXCloseDisplay(dpy);\n\n\tclose(lock_file);\n\n\tif(cfg->getOption(\"tty_lock\") == \"1\") {\n\t\tif ((ioctl(term, VT_UNLOCKSWITCH)) == -1) {\n\t\t\tperror(\"error unlocking console\");\n\t\t}\n\t}\n\tclose(term);\n\n\treturn 0;\n}\n\nvoid HideCursor()\n{\n\tif (cfg->getOption(\"hidecursor\") == \"true\") {\n\t\tXColor black;\n\t\tchar cursordata[1];\n\t\tPixmap cursorpixmap;\n\t\tCursor cursor;\n\t\tcursordata[0] = 0;\n\t\tcursorpixmap = XCreateBitmapFromData(dpy, win, cursordata, 1, 1);\n\t\tblack.red = 0;\n\t\tblack.green = 0;\n\t\tblack.blue = 0;\n\t\tcursor = XCreatePixmapCursor(dpy, cursorpixmap, cursorpixmap,\n\t\t\t\t\t\t\t\t\t &black, &black, 0, 0);\n\t\tXFreePixmap(dpy, cursorpixmap);\n\t\tXDefineCursor(dpy, win, cursor);\n\t}\n}\n\nstatic int ConvCallback(int num_msgs, const struct pam_message **msg,\n\t\t\t\t\t\tstruct pam_response **resp, void *appdata_ptr)\n{\n\tloginPanel->EventHandler(Panel::Get_Passwd);\n\n\t// PAM expects an array of responses, one for each message\n\tif (num_msgs == 0 ||\n\t\t(*resp = (pam_response*) calloc(num_msgs, sizeof(struct pam_message))) == NULL)\n\t\treturn PAM_BUF_ERR;\n\n\tfor (int i = 0; i < num_msgs; i++) {\n\t\tif (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF &&\n\t\t\tmsg[i]->msg_style != PAM_PROMPT_ECHO_ON)\n\t\t\tcontinue;\n\n\t\t// return code is currently not used but should be set to zero\n\t\tresp[i]->resp_retcode = 0;\n\t\tif ((resp[i]->resp = strdup(loginPanel->GetPasswd().c_str())) == NULL) {\n\t\t\tfree(*resp);\n\t\t\treturn PAM_BUF_ERR;\n\t\t}\n\t}\n\n\treturn PAM_SUCCESS;\n}\n\nbool AuthenticateUser()\n{\n\treturn(pam_authenticate(pam_handle, 0) == PAM_SUCCESS);\n}\n\nstring findValidRandomTheme(const string& set)\n{\n\t// extract random theme from theme set; return empty string on error\n\tstring name = set;\n\tstruct stat buf;\n\n\tif (name[name.length() - 1] == ',') {\n\t\tname.erase(name.length() - 1);\n\t}\n\n\tUtil::srandom(Util::makeseed());\n\n\tvector<string> themes;\n\tstring themefile;\n\tCfg::split(themes, name, ',');\n\tdo {\n\t\tint sel = Util::random() % themes.size();\n\n\t\tname = Cfg::Trim(themes[sel]);\n\t\tthemefile = string(THEMESDIR) +\"/\" + name + THEMESFILE;\n\t\tif (stat(themefile.c_str(), &buf) != 0) {\n\t\t\tthemes.erase(find(themes.begin(), themes.end(), name));\n\t\t\tcerr << APPNAME << \": Invalid theme in config: \"\n\t\t\t\t << name << endl;\n\t\t\tname = \"\";\n\t\t}\n\t} while (name == \"\" && themes.size());\n\treturn name;\n}\n\nvoid HandleSignal(int sig)\n{\n\t// Get DPMS stuff back to normal\n\tif (using_dpms) {\n\t\tDPMSSetTimeouts(dpy, dpms_standby, dpms_suspend, dpms_off);\n\t\t// turn off DPMS if it was off when we entered\n\t\tif (!dpms_state)\n\t\t\tDPMSDisable(dpy);\n\t}\n\n\tif ((ioctl(term, VT_UNLOCKSWITCH)) == -1) {\n\t\tperror(\"error unlocking console\");\n\t}\n\tclose(term);\n\n\tloginPanel->ClosePanel();\n\tdelete loginPanel;\n\n\tdie(APPNAME\": Caught signal; dying\\n\");\n}\n\nvoid* RaiseWindow(void *data) {\n\twhile(1) {\n\t\tXRaiseWindow(dpy, win);\n\t\tsleep(1);\n\t}\n\n\treturn (void *)0;\n}\n"
  },
  {
    "path": "slimlock.pam",
    "content": "#%PAM-1.0\nauth\trequired pam_unix.so nodelay nullok\n"
  },
  {
    "path": "switchuser.cpp",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 1997, 1998 Per Liden\n   Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n   Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n*/\n\n#include <cstdio>\n#include \"switchuser.h\"\n#include \"util.h\"\n\nusing namespace std;\n\nSwitchUser::SwitchUser(struct passwd *pw, Cfg *c, const string& display,\n\t\t\t\t\t   char** _env)\n\t: cfg(c),\n\t  Pw(pw),\n\t  displayName(display),\n\t  env(_env)\n{\n}\n\nSwitchUser::~SwitchUser() {\n\t/* Never called */\n}\n\nvoid SwitchUser::Login(const char* cmd, const char* mcookie) {\n\tSetUserId();\n\tSetClientAuth(mcookie);\n\tExecute(cmd);\n}\n\nvoid SwitchUser::SetUserId() {\n\tif( (Pw == 0) ||\n\t\t\t(initgroups(Pw->pw_name, Pw->pw_gid) != 0) ||\n\t\t\t(setgid(Pw->pw_gid) != 0) ||\n\t\t\t(setuid(Pw->pw_uid) != 0) ) {\n\t\tlogStream << APPNAME << \": could not switch user id\" << endl;\n\t\texit(ERR_EXIT);\n\t}\n}\n\nvoid SwitchUser::Execute(const char* cmd) {\n\tchdir(Pw->pw_dir);\n\texecle(Pw->pw_shell, Pw->pw_shell, \"-c\", cmd, NULL, env);\n\tlogStream << APPNAME << \": could not execute login command\" << endl;\n}\n\nvoid SwitchUser::SetClientAuth(const char* mcookie) {\n\tstring home = string(Pw->pw_dir);\n\tstring authfile = home + \"/.Xauthority\";\n\tremove(authfile.c_str());\n\tUtil::add_mcookie(mcookie, \":0\", cfg->getOption(\"xauth_path\"),\n\t  authfile);\n}\n"
  },
  {
    "path": "switchuser.h",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 1997, 1998 Per Liden\n   Copyright (C) 2004-06 Simone Rota <sip@varlock.com>\n   Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n*/\n\t\n#ifndef _SWITCHUSER_H_\n#define _SWITCHUSER_H_\n\n#include <stdlib.h>\n#include <unistd.h>\n#include <string.h>\n#include <pwd.h>\n#include <grp.h>\n#include <paths.h>\n#include <cstdio>\n#include <iostream>\n#include \"log.h\"\n#include \"cfg.h\"\n\n\nclass SwitchUser {\npublic:\n\tSwitchUser(struct passwd *pw, Cfg *c, const std::string& display,\n\t\t\t   char** _env);\n\t~SwitchUser();\n\tvoid Login(const char* cmd, const char* mcookie);\n\nprivate:\n\tSwitchUser();\n\tvoid SetEnvironment();\n\tvoid SetUserId();\n\tvoid Execute(const char* cmd);\n\tvoid SetClientAuth(const char* mcookie);\n\tCfg* cfg;\n\tstruct passwd *Pw;\n\n\tstd::string displayName;\n\tchar** env;\n};\n\n#endif /* _SWITCHUSER_H_ */\n"
  },
  {
    "path": "themes/CMakeLists.txt",
    "content": "subdirs (default)\n"
  },
  {
    "path": "themes/default/CMakeLists.txt",
    "content": "set (THEMES \"themes/default\")\n\ninstall(FILES slim.theme DESTINATION ${PKGDATADIR}/${THEMES})\ninstall(FILES panel.png DESTINATION ${PKGDATADIR}/${THEMES})\ninstall(FILES background.jpg DESTINATION ${PKGDATADIR}/${THEMES})\n"
  },
  {
    "path": "themes/default/COPYRIGHT.background",
    "content": "Text. 04 is copyright (c) 2005 by rafael nascimento\nhttp://darkevil.deviantart.com\n"
  },
  {
    "path": "themes/default/COPYRIGHT.panel",
    "content": "    Lila SVG Icon and Theme Artwork\n    Copyright (C) 2004 Lila Community\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program; if not, write to the Free Software\n    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"
  },
  {
    "path": "themes/default/LICENSE.panel",
    "content": "\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Library General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\f\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\f\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\f\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\f\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n\t    How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program; if not, write to the Free Software\n    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year  name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General\nPublic License instead of this License.\n"
  },
  {
    "path": "themes/default/slim.theme",
    "content": "# text04 theme for SLiM\n# by Johannes Winkelmann\n\n# Messages (ie: shutdown)\nmsg_color               #FFFFFF\nmsg_font                Verdana:size=18:bold:dpi=75\nmsg_x                   50%\nmsg_y                   40%\nmsg_shadow_color #702342\nmsg_shadow_xoffset 1\nmsg_shadow_yoffset 1\n\n# valid values: stretch, tile\nbackground_style        stretch\nbackground_color        #eedddd\n\n# Input controls\ninput_panel_x           25%\ninput_panel_y           65%\ninput_name_x            394\ninput_name_y            181\ninput_font          \tVerdana:size=12:dpi=75\ninput_color             #000000\n\n# Username / password request\nusername_font          \tVerdana:size=14:bold:dpi=75\nusername_color        \t#f9f9f9\nusername_x              280\nusername_y              183\npassword_x              50%\npassword_y              183\nusername_shadow_color   #702342\nusername_shadow_xoffset 1\nusername_shadow_yoffset 1\n\nusername_msg            Username:\npassword_msg            Password:\n"
  },
  {
    "path": "util.cpp",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 2009 Eygene Ryabinkin <rea@codelabs.ru>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n*/\n\n#include <sys/types.h>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <time.h>\n#include <unistd.h>\n\n#include \"util.h\"\n\n/*\n * Adds the given cookie to the specified Xauthority file.\n * Returns true on success, false on fault.\n */\nbool Util::add_mcookie(const std::string &mcookie, const char *display,\n\tconst std::string &xauth_cmd, const std::string &authfile)\n{\n\tFILE *fp;\n\tstd::string cmd = xauth_cmd + \" -f \" + authfile + \" -q\";\n\n\tfp = popen(cmd.c_str(), \"w\");\n\tif (!fp)\n\t\treturn false;\n\tfprintf(fp, \"remove %s\\n\", display);\n\tfprintf(fp, \"add %s %s %s\\n\", display, \".\", mcookie.c_str());\n\tfprintf(fp, \"exit\\n\");\n\n\tpclose(fp);\n\treturn true;\n}\n\n/*\n * Interface for random number generator.  Just now it uses ordinary\n * random/srandom routines and serves as a wrapper for them.\n */\nvoid Util::srandom(unsigned long seed)\n{\n\t::srandom(seed);\n}\n\nlong Util::random(void)\n{\n\treturn ::random();\n}\n\n/*\n * Makes seed for the srandom() using \"random\" values obtained from\n * getpid(), time(NULL) and others.\n */\nlong Util::makeseed(void)\n{\n\tstruct timespec ts;\n\tlong pid = getpid();\n\tlong tm = time(NULL);\n\n\tif (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {\n\t\tts.tv_sec = ts.tv_nsec = 0;\n\t}\n\n\treturn pid + tm + (ts.tv_sec ^ ts.tv_nsec);\n}\n"
  },
  {
    "path": "util.h",
    "content": "/* SLiM - Simple Login Manager\n   Copyright (C) 2009 Eygene Ryabinkin <rea@codelabs.ru>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n*/\n#ifndef _UTIL_H__\n#define _UTIL_H__\n\n#include <string>\n\nnamespace Util {\n\tbool add_mcookie(const std::string &mcookie, const char *display,\n\t\tconst std::string &xauth_cmd, const std::string &authfile);\n\n\tvoid srandom(unsigned long seed);\n\tlong random(void);\n\n\tlong makeseed(void);\n}\n\n#endif /* _UTIL_H__ */\n"
  },
  {
    "path": "xinitrc.sample",
    "content": "# the following variable defines the session which is started if the user\n# doesn't explicitely select a session\nDEFAULT_SESSION=twm\n\ncase $1 in\nxfce4)\n\texec startxfce4\n\t;;\nicewm)\n\ticewmbg &\n\ticewmtray &\n\texec icewm\n\t;;\nwmaker)\n\texec wmaker\n\t;;\nblackbox)\n\texec blackbox\n\t;;\n*)\n\texec $DEFAULT_SESSION\n\t;;\nesac\n"
  }
]